您的位置:首页 > 移动开发 > Objective-C

看看GtkWindow如何被生出来的(gtk_window_new()的内部机制).

2009-06-05 17:42 309 查看
看看GtkWindow如何被生出来的.
用Glib/GObject/Gtk也有很长时间了,没有时间往下刨根,现在刨一刨。

1 定义GtkWindow.. 2
2 展开它:... 2
在gtype.h中定义如下宏:... 2
把定义的宏展开:... 3
再把GtkBin的定义展开:... 4
再展开GtkContainer的定义://不用展开,直接定义的... 5
GtkWidget的get_type()也是直接定义的... 6
GtkObject的get_type()也是直接定义的:... 7
看看GObject的定义:gtk_init()后,这个对象是已经建立了... 8
3 在用的时候,是直接调用一个宏:... 8
下面我们来跟着一下其流程:(步步跟踪其父类,如果父类还没有创建,则先创建父类) 8
Step 1: 程序会调用这个接口:... 8
Step 2: 接着会调用 (层层上访) 9
Step 3:所要先看GtkObject的创立过程:... 9
GtkObject对象存在了,那就看它的子类吧:GtkWidget 10
接着往下搞:GtkWidget对象也有了,在往下看子类:GtkContainer 11
Go on: GtkBin. 12
GtkBin创建后,GtkWindow对象也就创建了;... 13
这样一系列的对象存在如下:... 13
上面仅仅是一些对象,那这些对象携带的回调函数都是从哪里调用的呢?... 14
关键之处是g_object_new()里面调用的函数... 14
重点看看g_object_newv:... 14
g_type_class_ref这个就是核心:递归调用... 17
上面的递归调用会调用函数type_class_init_Wm()完成对某个类的初始化,即,分配内存同时调用class_init() 19
Base_class_init()调用的顺序:... 23
1. g_object_base_class_init 23
2 gtk_object_base_class_init 23
3 gtk_widget_base_class_init 是NULL所以不调用... 23
4 gtk_container_base_class_init 24
5 gtk_bin, gtk_windonw的base_class_init()都是NULL. 24
下面开始class_init: 24
class_init() 之前有个递归过程(图示)... 24
下面用运行代码来检查实际的过程:... 25
条件:... 25
结果:... 25

1 定义GtkWindow

G_DEFINE_TYPE_WITH_CODE (GtkWindow, gtk_window, GTK_TYPE_BIN,

G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
gtk_window_buildable_interface_init))

2 展开它:

在gtype.h中定义如下宏:

#define G_DEFINE_TYPE_WITH_CODE(TN, t_n, T_P, _C_) _G_DEFINE_TYPE_EXTENDED_BEGIN (TN, t_n, T_P, 0) {_C_;} _G_DEFINE_TYPE_EXTENDED_END()

#define _G_DEFINE_TYPE_EXTENDED_BEGIN(TypeName, type_name, TYPE_PARENT, flags) /
/
static void type_name##_init (TypeName *self); /
static void type_name##_class_init (TypeName##Class *klass); /
static gpointer type_name##_parent_class = NULL; /
static void type_name##_class_intern_init (gpointer klass) /
{ /
type_name##_parent_class = g_type_class_peek_parent (klass); /
type_name##_class_init ((TypeName##Class*) klass); /
} /
/
GType /
type_name##_get_type (void) /
{ /
static volatile gsize g_define_type_id__volatile = 0; /
if (g_once_init_enter (&g_define_type_id__volatile)) /
{ /
GType g_define_type_id = /
g_type_register_static_simple (TYPE_PARENT, /
g_intern_static_string (#TypeName), /
sizeof (TypeName##Class), /
(GClassInitFunc) type_name##_class_intern_init, /
sizeof (TypeName), /
(GInstanceInitFunc) type_name##_init, /
(GTypeFlags) flags); /
{ /* custom code follows */
#define _G_DEFINE_TYPE_EXTENDED_END() /
/* following custom code */ /
} /
g_once_init_leave (&g_define_type_id__volatile, g_define_type_id); /
} /
return g_define_type_id__volatile; /
} /* closes type_name##_get_type() */

把定义的宏展开:

static void gtk_window_init (GtkWindow *self);

static void gtk_window_class_init (GtkWindowClass * klass);
static void gtk_window_parent_class = NULL;
static void gtk_window_class_intern_init (gpointer klass)
{
gtk_window_parent_class = g_type_class_peek_parent (klass);
gtk_window_class_init ((GtkWindowClass*) klass);
}

GType
gtk_window_get_type (void)
{
static volatile gsize g_define_type_id__volatile = 0;
if (g_once_init_enter (&g_define_type_id__volatile))
{
GType g_define_type_id =
g_type_register_static_simple (GTK_TYPE_BIN, //父亲
g_intern_static_string ("GtkWindow"),
sizeof (GtkWindowClass),
(GClassInitFunc) gtk_window_class_intern_init,
sizeof (GtkWindow),
(GInstanceInitFunc) gtk_window_init,
0);
{
const GInterfaceInfo g_implement_interface = {
(GInterfaceInitFunc) gtk_window_buildable_interface_init, NULL, NULL };

g_type_add_interface_static (g_define_type_id, GTK_TYPE_BUILDABLE, &g_implement_interface);
}
g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
}
return g_define_type_id__volatile;
}

再把GtkBin的定义展开:

G_DEFINE_ABSTRACT_TYPE (GtkBin, gtk_bin, GTK_TYPE_CONTAINER)

static void gtk_bin_init (GtkBin *self);

static void gtk_bin_class_init (GtkBinClass * klass);
static void gtk_bin_parent_class = NULL;
static void gtk_bin_class_intern_init (gpointer klass)
{
gtk_bin_parent_class = g_type_class_peek_parent (klass);
gtk_bin_class_init ((GtkBinClass*) klass);
}

GType
gtk_bin_get_type(void)
{
static volatile gsize g_define_type_id__volatile = 0;
if (g_once_init_enter (&g_define_type_id__volatile))
{
GType g_define_type_id =
g_type_register_static_simple (GTK_TYPE_CONTAINER, //GtkBin的父亲
g_intern_static_string ("GtkBin"),
sizeof (GtkBinClass),
(GClassInitFunc) gtk_bin_class_intern_init,
sizeof (GtkBin),
(GInstanceInitFunc) gtk_bin_init,
G_TYPE_FLAG_ABSTRACT);
{
}
g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
}
return g_define_type_id__volatile;
}

再展开GtkContainer的定义://不用展开,直接定义的

#define GTK_TYPE_CONTAINER (gtk_container_get_type ())

/* --- functions --- */

GType
gtk_container_get_type (void)
{
static GType container_type = 0;

if (!container_type)
{
const GTypeInfo container_info =
{
sizeof (GtkContainerClass),
(GBaseInitFunc) gtk_container_base_class_init,
(GBaseFinalizeFunc) gtk_container_base_class_finalize,
(GClassInitFunc) gtk_container_class_init,
NULL /* class_finalize */,
NULL /* class_data */,
sizeof (GtkContainer),
0 /* n_preallocs */,
(GInstanceInitFunc) gtk_container_init,
NULL, /* value_table */
};

static const GInterfaceInfo buildable_info =
{
(GInterfaceInitFunc) gtk_container_buildable_init,
NULL,
NULL
};

container_type =
g_type_register_static (GTK_TYPE_WIDGET, //GtkContainer的父亲
I_("GtkContainer"),
&container_info, G_TYPE_FLAG_ABSTRACT);

g_type_add_interface_static (container_type,
GTK_TYPE_BUILDABLE,
&buildable_info);

}

return container_type;
}

GtkWidget的get_type()也是直接定义的

/* --- functions --- */

GType
gtk_widget_get_type (void)
{
static GType widget_type = 0;

if (G_UNLIKELY (widget_type == 0))
{
const GTypeInfo widget_info =
{
sizeof (GtkWidgetClass),
NULL, /* base_init */
(GBaseFinalizeFunc) gtk_widget_base_class_finalize,
(GClassInitFunc) gtk_widget_class_init,
NULL, /* class_finalize */
NULL, /* class_init */
sizeof (GtkWidget),
0, /* n_preallocs */
(GInstanceInitFunc) gtk_widget_init,
NULL, /* value_table */
};

const GInterfaceInfo accessibility_info =
{
(GInterfaceInitFunc) gtk_widget_accessible_interface_init,
(GInterfaceFinalizeFunc) NULL,
NULL /* interface data */
};

const GInterfaceInfo buildable_info =
{
(GInterfaceInitFunc) gtk_widget_buildable_interface_init,
(GInterfaceFinalizeFunc) NULL,
NULL /* interface data */
};

widget_type = g_type_register_static (GTK_TYPE_OBJECT, //GtkWidget的父亲
"GtkWidget",
&widget_info, G_TYPE_FLAG_ABSTRACT);

g_type_add_interface_static (widget_type, ATK_TYPE_IMPLEMENTOR,
&accessibility_info) ;
g_type_add_interface_static (widget_type, GTK_TYPE_BUILDABLE,
&buildable_info) ;

}

return widget_type;
}

GtkObject的get_type()也是直接定义的:

#define GTK_TYPE_OBJECT (gtk_object_get_type ())

GType
gtk_object_get_type (void)
{
static GType object_type = 0;

if (!object_type)
{
const GTypeInfo object_info =
{
sizeof (GtkObjectClass),
(GBaseInitFunc) gtk_object_base_class_init,
(GBaseFinalizeFunc) gtk_object_base_class_finalize,
(GClassInitFunc) gtk_object_class_init,
NULL, /* class_finalize */
NULL, /* class_data */
sizeof (GtkObject),
16, /* n_preallocs */
(GInstanceInitFunc) gtk_object_init,
NULL, /* value_table */
};

object_type = g_type_register_static
(G_TYPE_INITIALLY_UNOWNED, //GtkObject的父亲,就是GObject
I_("GtkObject"),
&object_info, G_TYPE_FLAG_ABSTRACT);
}

return object_type;
}

看看GObject的定义:gtk_init()后,这个对象是已经建立了

GType

g_object_get_type (void)
{
return G_TYPE_OBJECT;
}

//GObject的回调函数什么时候被调用的?

3 在用的时候,是直接调用一个宏:

#define GTK_TYPE_WINDOW (gtk_window_get_type ())

下面我们来跟着一下其流程:(步步跟踪其父类,如果父类还没有创建,则先创建父类)

Step 1: 程序会调用这个接口:

GtkWidget* gtk_window_new (GtkWindowType type);

这个函数内部会调用
window = g_object_new (GTK_TYPE_WINDOW, NULL);

Step 2: 接着会调用 (层层上访)

GType

gtk_window_get_type (void)

//这个函数内部又会找GtkWindows的父类:GtkBin
GtkBin又找其父类GtkContainer,
GtkContainer又找其父类GtkWidget
GtkWidget又找其父类GtkObject
GtkObject又找其父类Gobject, 这个类在gtk_init()后,就已经存在了;
所以在反过来进行

Step 3:所要先看GtkObject的创立过程:

GType

gtk_object_get_type (void)
{
static GType object_type = 0;

if (!object_type)
{
const GTypeInfo object_info =
{
sizeof (GtkObjectClass),
(GBaseInitFunc) gtk_object_base_class_init,
(GBaseFinalizeFunc) gtk_object_base_class_finalize,
(GClassInitFunc) gtk_object_class_init,
NULL, /* class_finalize */
NULL, /* class_data */
sizeof (GtkObject),
16, /* n_preallocs */
(GInstanceInitFunc) gtk_object_init,
NULL, /* value_table */
};

//g_type_register_static就从GObject派生出来一个类GtkObject,并填充好以后,放到全局的数组中,以及Hash Table中,具体如下:
//这个函数首先干的事情:检查名字是否合法以及在当前的Hash Table中是不是已经有了?然后再检查和指定的父类之间是否真的具有继承关系
//如果可以注册,
//如果父类不存在,直接放到全局数组中,则先在static_fundamental_type_nodes[]数组中找个位置,来存放这个类型节点指针
//如果父类存在,则从父类拷贝一份内存出来,作为子类, 主要在type_node_any_new_W()中完成,并且把这个新的子类放到父类的一个子类数组中
// 然后把新类放到Hash Table中,这样方便查询
// 然后给类型数据填充一些字段,主要是注册一些回调函数,由type_data_make_W()来完成
//同时把ref_count置为1,表明这个对象活了!
object_type = g_type_register_static (G_TYPE_INITIALLY_UNOWNED, I_("GtkObject"),
&object_info, G_TYPE_FLAG_ABSTRACT);
}

return object_type;
}

//还有问题没有搞明白,注册的系列回调,何时调用的?

GtkObject对象存在了,那就看它的子类吧:GtkWidget

/* --- functions --- */

GType
gtk_widget_get_type (void)
{
static GType widget_type = 0;

if (G_UNLIKELY (widget_type == 0))
{
const GTypeInfo widget_info =
{
sizeof (GtkWidgetClass),
NULL, /* base_init */
(GBaseFinalizeFunc) gtk_widget_base_class_finalize,
(GClassInitFunc) gtk_widget_class_init,
NULL, /* class_finalize */
NULL, /* class_init */
sizeof (GtkWidget),
0, /* n_preallocs */
(GInstanceInitFunc) gtk_widget_init,
NULL, /* value_table */
};

const GInterfaceInfo accessibility_info =
{
(GInterfaceInitFunc) gtk_widget_accessible_interface_init,
(GInterfaceFinalizeFunc) NULL,
NULL /* interface data */
};

const GInterfaceInfo buildable_info =
{
(GInterfaceInitFunc) gtk_widget_buildable_interface_init,
(GInterfaceFinalizeFunc) NULL,
NULL /* interface data */
};

//也是从GtkObject对象做一个内存拷贝,然后填充数据(注册回调),新创建的对象GtkWidget地址存放于GtkObject维护的一个子类列表里面;当然了,在Hash Table里面也是有的;
widget_type = g_type_register_static (GTK_TYPE_OBJECT, "GtkWidget",
&widget_info, G_TYPE_FLAG_ABSTRACT);

g_type_add_interface_static (widget_type, ATK_TYPE_IMPLEMENTOR,
&accessibility_info) ;
g_type_add_interface_static (widget_type, GTK_TYPE_BUILDABLE,
&buildable_info) ;

}

return widget_type;
}

接着往下搞:GtkWidget对象也有了,在往下看子类:GtkContainer

/* --- functions --- */

GType
gtk_container_get_type (void)
{
static GType container_type = 0;

if (!container_type)
{
const GTypeInfo container_info =
{
sizeof (GtkContainerClass),
(GBaseInitFunc) gtk_container_base_class_init,
(GBaseFinalizeFunc) gtk_container_base_class_finalize,
(GClassInitFunc) gtk_container_class_init,
NULL /* class_finalize */,
NULL /* class_data */,
sizeof (GtkContainer),
0 /* n_preallocs */,
(GInstanceInitFunc) gtk_container_init,
NULL, /* value_table */
};

static const GInterfaceInfo buildable_info =
{
(GInterfaceInitFunc) gtk_container_buildable_init,
NULL,
NULL
};

//也是从GtkWidget对象做一个内存拷贝,然后填充数据(注册回调),新创建的对象GtkContainer地址存放于GtkWidget维护的一个子类列表里面;当然了,在Hash Table里面也是有的;
container_type =
g_type_register_static (GTK_TYPE_WIDGET, I_("GtkContainer"),
&container_info, G_TYPE_FLAG_ABSTRACT);

g_type_add_interface_static (container_type,
GTK_TYPE_BUILDABLE,
&buildable_info);

}

return container_type;
}

Go on: GtkBin

static void gtk_bin_init (GtkBin *self);

static void gtk_bin_class_init (GtkBinClass * klass);
static void gtk_bin_parent_class = NULL;
static void gtk_bin_class_intern_init (gpointer klass)
{
gtk_bin_parent_class = g_type_class_peek_parent (klass);
gtk_bin_class_init ((GtkBinClass*) klass);
}

GType
gtk_bin_get_type(void)
{
static volatile gsize g_define_type_id__volatile = 0;
if (g_once_init_enter (&g_define_type_id__volatile))
{
GType g_define_type_id =
g_type_register_static_simple (GTK_TYPE_CONTAINER,
g_intern_static_string ("GtkBin"),
sizeof (GtkBinClass),
(GClassInitFunc) gtk_bin_class_intern_init,
sizeof (GtkBin),
(GInstanceInitFunc) gtk_bin_init,
G_TYPE_FLAG_ABSTRACT);
{
}
g_once_init_leave (&g_define_type_id__volatile, g_define_type_id);
}
return g_define_type_id__volatile;
}

GtkBin创建后,GtkWindow对象也就创建了;

这样一系列的对象存在如下:

| `GtkObject

| |
| `GtkWidget
| |
| `GtkContainer
| |
| +GtkBin
| | |
| | +GtkWindow
对象的出生过程:老子先出生,然后是儿子,然后是孙子…; 自然界的规律
不过这里是先提出要孙子,谁提呢?如来佛吧!
然后如来就查查这个人的父亲是谁?已经出生了吗?没有再往上找;…
这些对象都有些本领(回调函数),一般情况下,也是先把老子的钱榨干,然后用儿子的,然后用…

上面仅仅是一些对象,那这些对象携带的回调函数都是从哪里调用的呢?

关键之处是g_object_new()里面调用的函数

要仔细的分析!

window = g_object_new (GTK_TYPE_WINDOW, NULL);

重点看看g_object_newv:

gpointer

g_object_newv (GType object_type,
guint n_parameters,
GParameter *parameters)
{
GObjectConstructParam *cparams, *oparams;
GObjectNotifyQueue *nqueue = NULL; /* shouldn't be initialized, just to silence compiler */
GObject *object;
GObjectClass *class, *unref_class = NULL;
GSList *slist;
guint n_total_cparams = 0, n_cparams = 0, n_oparams = 0, n_cvalues;
GValue *cvalues;
GList *clist = NULL;
gboolean newly_constructed;
guint i;

g_return_val_if_fail (G_TYPE_IS_OBJECT (object_type), NULL);

class = g_type_class_peek_static (object_type);
if (!class)
class = unref_class = g_type_class_ref (object_type);
for (slist = class->construct_properties; slist; slist = slist->next)
{
clist = g_list_prepend (clist, slist->data);
n_total_cparams += 1;
}

/* collect parameters, sort into construction and normal ones */
oparams = g_new (GObjectConstructParam, n_parameters);
cparams = g_new (GObjectConstructParam, n_total_cparams);
for (i = 0; i < n_parameters; i++)
{
GValue *value = ¶meters[i].value;
GParamSpec *pspec = g_param_spec_pool_lookup (pspec_pool,
parameters[i].name,
object_type,
TRUE);
if (!pspec)
{
g_warning ("%s: object class `%s' has no property named `%s'",
G_STRFUNC,
g_type_name (object_type),
parameters[i].name);
continue;
}
if (!(pspec->flags & G_PARAM_WRITABLE))
{
g_warning ("%s: property `%s' of object class `%s' is not writable",
G_STRFUNC,
pspec->name,
g_type_name (object_type));
continue;
}
if (pspec->flags & (G_PARAM_CONSTRUCT | G_PARAM_CONSTRUCT_ONLY))
{
GList *list = g_list_find (clist, pspec);

if (!list)
{
g_warning ("%s: construct property /"%s/" for object `%s' can't be set twice",
G_STRFUNC, pspec->name, g_type_name (object_type));
continue;
}
cparams[n_cparams].pspec = pspec;
cparams[n_cparams].value = value;
n_cparams++;
if (!list->prev)
clist = list->next;
else
list->prev->next = list->next;
if (list->next)
list->next->prev = list->prev;
g_list_free_1 (list);
}
else
{
oparams[n_oparams].pspec = pspec;
oparams[n_oparams].value = value;
n_oparams++;
}
}

/* set remaining construction properties to default values */
n_cvalues = n_total_cparams - n_cparams;
cvalues = g_new (GValue, n_cvalues);
while (clist)
{
GList *tmp = clist->next;
GParamSpec *pspec = clist->data;
GValue *value = cvalues + n_total_cparams - n_cparams - 1;

value->g_type = 0;
g_value_init (value, G_PARAM_SPEC_VALUE_TYPE (pspec));
g_param_value_set_default (pspec, value);

cparams[n_cparams].pspec = pspec;
cparams[n_cparams].value = value;
n_cparams++;

g_list_free_1 (clist);
clist = tmp;
}

/* construct object from construction parameters */
object = class->constructor (object_type, n_total_cparams, cparams);
/* free construction values */
g_free (cparams);
while (n_cvalues--)
g_value_unset (cvalues + n_cvalues);
g_free (cvalues);

/* adjust freeze_count according to g_object_init() and remaining properties */
G_LOCK (construction_mutex);
newly_constructed = slist_maybe_remove (&construction_objects, object);
G_UNLOCK (construction_mutex);
if (newly_constructed || n_oparams)
nqueue = g_object_notify_queue_freeze (object, &property_notify_context);
if (newly_constructed)
g_object_notify_queue_thaw (object, nqueue);

/* run 'constructed' handler if there is one */
if (newly_constructed && class->constructed)
class->constructed (object);

/* set remaining properties */
for (i = 0; i < n_oparams; i++)
object_set_property (object, oparams[i].pspec, oparams[i].value, nqueue);
g_free (oparams);

/* release our own freeze count and handle notifications */
if (newly_constructed || n_oparams)
g_object_notify_queue_thaw (object, nqueue);

if (unref_class)
g_type_class_unref (unref_class);

return object;
}

g_type_class_ref这个就是核心:递归调用

gpointer

g_type_class_ref (GType type)
{
TypeNode *node;
GType ptype;

/* optimize for common code path */
G_WRITE_LOCK (&type_rw_lock);
//如果当前类型对应的节点数据已经存在了,并且也别初始化过,则紧紧增加一个ref_count,然后返回。
node = lookup_type_node_I (type);
if (node && node->is_classed && node->data &&
node->data->class.class &&
node->data->class.init_state == INITIALIZED)
{
type_data_ref_Wm (node);
G_WRITE_UNLOCK (&type_rw_lock);
return node->data->class.class;
}
if (!node || !node->is_classed ||
(node->data && node->data->common.ref_count < 1))
{
G_WRITE_UNLOCK (&type_rw_lock);
g_warning ("cannot retrieve class for invalid (unclassed) type `%s'",
type_descriptive_name_I (type));
return NULL;
}

//给当前节点分配内存等
type_data_ref_Wm (node);

//找到其父节点
ptype = NODE_PARENT_TYPE (node);
G_WRITE_UNLOCK (&type_rw_lock);

g_static_rec_mutex_lock (&class_init_rec_mutex); /* required locking order: 1) class_init_rec_mutex, 2) type_rw_lock */
/* here, we either have node->data->class.class == NULL, or a recursive
* call to g_type_class_ref() with a partly initialized class, or
* node->data->class.init_state == INITIALIZED, because any
* concurrently running initialization was guarded by class_init_rec_mutex.
*/
if (!node->data->class.class) /* class uninitialized */
{
/* acquire reference on parent class */
//这个地方是最重要的,会一直找到最上面的基类
GtkWindow-> GtkBin -> GtkContainer ->GtkWidget->GtkObject
GTypeClass *pclass = ptype ? g_type_class_ref (ptype) : NULL;
G_WRITE_LOCK (&type_rw_lock);
if (node->data->class.class) /* class was initialized during parent class initialization? */
INVALID_RECURSION ("g_type_plugin_*", node->plugin, NODE_NAME (node));
//当上面的递归调用入口的边界条件(ptype == NULL, 即发现GObject没有父类后,就会,就不会再次调用g_type_class_ref了,这时候函数调用堆栈就会返回就从最后一个g_type_class_ref开始往下执行了,此时是GObject, 所以会从类的顶层开始调用其Class_init(); 这样就实现了从父类,到子类,再到孙子类的class_init()的过程。比较巧妙。
type_class_init_Wm (node, pclass);
G_WRITE_UNLOCK (&type_rw_lock);
}
g_static_rec_mutex_unlock (&class_init_rec_mutex);

return node->data->class.class;
}

上面的递归调用会调用函数type_class_init_Wm()完成对某个类的初始化,即,分配内存同时调用class_init()

static void
type_class_init_Wm (TypeNode *node,
GTypeClass *pclass)
{
GSList *slist, *init_slist = NULL;
GTypeClass *class;
IFaceEntry *entry;
TypeNode *bnode, *pnode;
guint i;

g_assert (node->is_classed && node->data &&
node->data->class.class_size &&
!node->data->class.class &&
node->data->class.init_state == UNINITIALIZED);

class = g_malloc0 (node->data->class.class_size);
node->data->class.class = class;
node->data->class.init_state = BASE_CLASS_INIT;

if (pclass)
{
//找到GObjectClass对应的节点
TypeNode *pnode = lookup_type_node_I (pclass->g_type);

//拷贝给子类GtkWidgetClass, 这就是继承?
memcpy (class, pclass, pnode->data->class.class_size);

if (node->is_instantiatable)
{
/* We need to initialize the private_size here rather than in
* type_data_make_W() since the class init for the parent
* class may have changed pnode->data->instance.private_size.
*/
node->data->instance.private_size = pnode->data->instance.private_size;
}
}
class->g_type = NODE_TYPE (node);

G_WRITE_UNLOCK (&type_rw_lock);

/* stack all base class initialization functions, so we
* call them in ascending order.
*/

//这个遍历是从GtkWindow-> GtkBin -> GtkContainer ->GtkWidget->GtkObject->GObject ,即从子到父亲的顺序;
//而列举出的base_class_init()函数的列表正好是反的:
GObject::class_init_base() à GtkObject::class_init_base()à GtkWidget::class_init_base()à GtkContainer::class_init_base()à GtkBin::class_init_base()à GtkWidow::class_init_base()
//所以首先会调用基类的base_class_init()函数,然后依次进行下去
for (bnode = node; bnode; bnode = lookup_type_node_I (NODE_PARENT_TYPE (bnode)))
if (bnode->data->class.class_init_base)
init_slist = g_slist_prepend (init_slist, (gpointer) bnode->data->class.class_init_base);

for (slist = init_slist; slist; slist = slist->next)
{
GBaseInitFunc class_init_base = (GBaseInitFunc) slist->data;

class_init_base (class);
}
g_slist_free (init_slist);

G_WRITE_LOCK (&type_rw_lock);

node->data->class.init_state = BASE_IFACE_INIT;

/* Before we initialize the class, base initialize all interfaces, either
* from parent, or through our holder info
*/
pnode = lookup_type_node_I (NODE_PARENT_TYPE (node));

i = 0;
while (i < CLASSED_NODE_N_IFACES (node))
{
entry = &CLASSED_NODE_IFACES_ENTRIES (node)[i];
while (i < CLASSED_NODE_N_IFACES (node) &&
entry->init_state == IFACE_INIT)
{
entry++;
i++;
}

if (i == CLASSED_NODE_N_IFACES (node))
break;

if (!type_iface_vtable_base_init_Wm (lookup_type_node_I (entry->iface_type), node))
{
guint j;

/* need to get this interface from parent, type_iface_vtable_base_init_Wm()
* doesn't modify write lock upon FALSE, so entry is still valid;
*/
g_assert (pnode != NULL);

for (j = 0; j < CLASSED_NODE_N_IFACES (pnode); j++)
{
IFaceEntry *pentry = CLASSED_NODE_IFACES_ENTRIES (pnode) + j;

if (pentry->iface_type == entry->iface_type)
{
entry->vtable = pentry->vtable;
entry->init_state = INITIALIZED;
break;
}
}
g_assert (entry->vtable != NULL);
}

/* If the write lock was released, additional interface entries might
* have been inserted into CLASSED_NODE_IFACES_ENTRIES (node); they'll
* be base-initialized when inserted, so we don't have to worry that
* we might miss them. Uninitialized entries can only be moved higher
* when new ones are inserted.
*/
i++;
}

node->data->class.init_state = CLASS_INIT;

G_WRITE_UNLOCK (&type_rw_lock);

//这句话非常重要,开始class_init的过程了!!!
//从gtk_window_class_init()开始?
if (node->data->class.class_init)
node->data->class.class_init (class, (gpointer) node->data->class.class_data);

G_WRITE_LOCK (&type_rw_lock);

node->data->class.init_state = IFACE_INIT;

/* finish initializing the interfaces through our holder info.
* inherited interfaces are already init_state == INITIALIZED, because
* they either got setup in the above base_init loop, or during
* class_init from within type_add_interface_Wm() for this or
* an anchestor type.
*/
i = 0;
while (TRUE)
{
entry = &CLASSED_NODE_IFACES_ENTRIES (node)[i];
while (i < CLASSED_NODE_N_IFACES (node) &&
entry->init_state == INITIALIZED)
{
entry++;
i++;
}

if (i == CLASSED_NODE_N_IFACES (node))
break;

type_iface_vtable_iface_init_Wm (lookup_type_node_I (entry->iface_type), node);

/* As in the loop above, additional initialized entries might be inserted
* if the write lock is released, but that's harmless because the entries
* we need to initialize only move higher in the list.
*/
i++;
}

node->data->class.init_state = INITIALIZED;
}

Base_class_init()调用的顺序:

1. g_object_base_class_init

static void

g_object_base_class_init (GObjectClass *class)
{
GObjectClass *pclass = g_type_class_peek_parent (class);

/* reset instance specific fields and methods that don't get inherited */
class->construct_properties = pclass ? g_slist_copy (pclass->construct_properties) : NULL;
class->get_property = NULL;
class->set_property = NULL;
}

2 gtk_object_base_class_init

static void

gtk_object_base_class_init (GtkObjectClass *class)
{
/* reset instance specifc methods that don't get inherited */
class->get_arg = NULL;
class->set_arg = NULL;
}

3 gtk_widget_base_class_init 是NULL所以不调用

4 gtk_container_base_class_init

static void

gtk_container_base_class_init (GtkContainerClass *class)
{
/* reset instance specifc class fields that don't get inherited */
class->set_child_property = NULL;
class->get_child_property = NULL;
}

5 gtk_bin, gtk_windonw的base_class_init()都是NULL

下面开始class_init:

class_init() 之前有个递归过程(图示)

GtkWindow
g_type_class_ref

GtkBin
g_type_class_ref

GtkContainer
g_type_class_ref

GtkWidget
g_type_class_ref

GtkObject
g_type_class_ref

GObject
g_type_class_ref

class_init

class_init

class_init

class_init

class_init

class_init

注意:如果某个类在递归过程中检查是已经被初始化过的类,则跳过其class_init()函数。

下面用运行代码来检查实际的过程:

条件:

g_type_init();

GtkWidget *window =gtk_window_new(GTK_WINDOW_TOPLEVEL);

结果:

GObject: g_type_name (object_type) : GtkWindow

GObject: class == NULL.
GType: enter g_type_class_ref() times = 1.
GType: current type: GtkWindow
GType: type_data_ref_Wm(GtkWindow).
GType: find current type's GtkWindow parent: GtkBin.
GType: enter g_type_class_ref() times = 2.
GType: current type: GtkBin
GType: type_data_ref_Wm(GtkBin).
GType: find current type's GtkBin parent: GtkContainer.
GType: enter g_type_class_ref() times = 3.
GType: current type: GtkContainer
GType: type_data_ref_Wm(GtkContainer).
GType: find current type's GtkContainer parent: GtkWidget.
GType: enter g_type_class_ref() times = 4.
GType: current type: GtkWidget
GType: type_data_ref_Wm(GtkWidget).
GType: find current type's GtkWidget parent: GtkObject.
GType: enter g_type_class_ref() times = 5.
GType: current type: GtkObject
GType: type_data_ref_Wm(GtkObject).
GType: find current type's GtkObject parent: GInitiallyUnowned.
GType: enter g_type_class_ref() times = 6.
GType: current type: GInitiallyUnowned
GType: type_data_ref_Wm(GInitiallyUnowned).
GType: find current type's GInitiallyUnowned parent: GObject.
GType: enter g_type_class_ref() times = 7.
GType: current type: GObject
GType: type_data_ref_Wm(GObject).
GType: find current type's GObject parent: (null).
GType: Node name: GObject.
GType: Node name: GInitiallyUnowned.
GType: Node name: GtkObject.
GType: enter g_type_class_ref() times = 8.
GType: current type: GObject
GType: current type already exist. return.

GType: enter g_type_class_ref() times = 9.
GType: current type: GParamPointer
GType: type_data_ref_Wm(GParamPointer).
GType: find current type's GParamPointer parent: GParam.
GType: enter g_type_class_ref() times = 10.
GType: current type: GParam
GType: type_data_ref_Wm(GParam).
GType: find current type's GParam parent: (null).
GType: Node name: GParam.
GType: Node name: GParamPointer.
GType: Node name: GtkWidget.
GType: enter g_type_class_ref() times = 11.
GType: current type: GParamString
GType: type_data_ref_Wm(GParamString).
GType: find current type's GParamString parent: GParam.
GType: enter g_type_class_ref() times = 12.
GType: current type: GParam
GType: current type already exist. return.

GType: Node name: GParamString.
GType: enter g_type_class_ref() times = 13.
GType: current type: GParamObject
GType: type_data_ref_Wm(GParamObject).
GType: find current type's GParamObject parent: GParam.
GType: enter g_type_class_ref() times = 14.
GType: current type: GParam
GType: current type already exist. return.

GType: Node name: GParamObject.
GType: enter g_type_class_ref() times = 15.
GType: current type: GParamInt
GType: type_data_ref_Wm(GParamInt).
GType: find current type's GParamInt parent: GParam.
GType: enter g_type_class_ref() times = 16.
GType: current type: GParam
GType: current type already exist. return.

GType: Node name: GParamInt.
GType: enter g_type_class_ref() times = 17.
GType: current type: GParamInt
GType: current type already exist. return.

GType: enter g_type_class_ref() times = 18.
GType: current type: GParamBoolean
GType: type_data_ref_Wm(GParamBoolean).
GType: find current type's GParamBoolean parent: GParam.
GType: enter g_type_class_ref() times = 19.
GType: current type: GParam
GType: current type already exist. return.

GType: Node name: GParamBoolean.
GType: enter g_type_class_ref() times = 20.
GType: current type: GParamBoolean
GType: current type already exist. return.

GType: enter g_type_class_ref() times = 21.
GType: current type: GParamBoolean
GType: current type already exist. return.

GType: enter g_type_class_ref() times = 22.
GType: current type: GParamBoolean
GType: current type already exist. return.

GType: enter g_type_class_ref() times = 23.
GType: current type: GParamBoolean
GType: current type already exist. return.

GType: enter g_type_class_ref() times = 24.
GType: current type: GParamBoolean
GType: current type already exist. return.

GType: enter g_type_class_ref() times = 25.
GType: current type: GParamBoolean
GType: current type already exist. return.

GType: enter g_type_class_ref() times = 26.
GType: current type: GParamBoolean
GType: current type already exist. return.

GType: enter g_type_class_ref() times = 27.
GType: current type: GParamBoolean
GType: current type already exist. return.

GType: enter g_type_class_ref() times = 28.
GType: current type: GParamBoolean
GType: current type already exist. return.

GType: enter g_type_class_ref() times = 29.
GType: current type: GParamObject
GType: current type already exist. return.

GType: enter g_type_class_ref() times = 30.
GType: current type: GdkEventMask
GType: type_data_ref_Wm(GdkEventMask).
GType: find current type's GdkEventMask parent: GFlags.
GType: enter g_type_class_ref() times = 31.
GType: current type: GFlags
GType: type_data_ref_Wm(GFlags).
GType: find current type's GFlags parent: (null).
GType: Node name: GFlags.
GType: Node name: GdkEventMask.
GType: enter g_type_class_ref() times = 32.
GType: current type: GParamFlags
GType: type_data_ref_Wm(GParamFlags).
GType: find current type's GParamFlags parent: GParam.
GType: enter g_type_class_ref() times = 33.
GType: current type: GParam
GType: current type already exist. return.

GType: Node name: GParamFlags.
GType: enter g_type_class_ref() times = 34.
GType: current type: GdkExtensionMode
GType: type_data_ref_Wm(GdkExtensionMode).
GType: find current type's GdkExtensionMode parent: GEnum.
GType: enter g_type_class_ref() times = 35.
GType: current type: GEnum
GType: type_data_ref_Wm(GEnum).
GType: find current type's GEnum parent: (null).
GType: Node name: GEnum.
GType: Node name: GdkExtensionMode.
GType: enter g_type_class_ref() times = 36.
GType: current type: GParamEnum
GType: type_data_ref_Wm(GParamEnum).
GType: find current type's GParamEnum parent: GParam.
GType: enter g_type_class_ref() times = 37.
GType: current type: GParam
GType: current type already exist. return.

GType: Node name: GParamEnum.
GType: enter g_type_class_ref() times = 38.
GType: current type: GParamBoolean
GType: current type already exist. return.

GType: enter g_type_class_ref() times = 39.
GType: current type: GParamBoolean
GType: current type already exist. return.

GType: enter g_type_class_ref() times = 40.
GType: current type: GParamString
GType: current type already exist. return.

GType: enter g_type_class_ref() times = 41.
GType: current type: GParamString
GType: current type already exist. return.

GType: enter g_type_class_ref() times = 42.
GType: current type: GParamObject
GType: current type already exist. return.

GType: enter g_type_class_ref() times = 43.
GType: current type: GtkTouchSoundType
GType: type_data_ref_Wm(GtkTouchSoundType).
GType: find current type's GtkTouchSoundType parent: GEnum.
GType: enter g_type_class_ref() times = 44.
GType: current type: GEnum
GType: current type already exist. return.

GType: Node name: GtkTouchSoundType.
GType: enter g_type_class_ref() times = 45.
GType: current type: GParamEnum
GType: current type already exist. return.

GType: enter g_type_class_ref() times = 46.
GType: current type: GtkSvibeEffectType
GType: type_data_ref_Wm(GtkSvibeEffectType).
GType: find current type's GtkSvibeEffectType parent: GEnum.
GType: enter g_type_class_ref() times = 47.
GType: current type: GEnum
GType: current type already exist. return.

GType: Node name: GtkSvibeEffectType.
GType: enter g_type_class_ref() times = 48.
GType: current type: GParamEnum
GType: current type already exist. return.

GType: enter g_type_class_ref() times = 49.
GType: current type: GParamBoolean
GType: current type already exist. return.

GType: enter g_type_class_ref() times = 50.
GType: current type: GParamInt
GType: current type already exist. return.

GType: enter g_type_class_ref() times = 51.
GType: current type: GParamString
GType: current type already exist. return.

GType: enter g_type_class_ref() times = 52.
GType: current type: GParamInt
GType: current type already exist. return.

GType: enter g_type_class_ref() times = 53.
GType: current type: GParamBoxed
GType: type_data_ref_Wm(GParamBoxed).
GType: find current type's GParamBoxed parent: GParam.
GType: enter g_type_class_ref() times = 54.
GType: current type: GParam
GType: current type already exist. return.

GType: Node name: GParamBoxed.
GType: enter g_type_class_ref() times = 55.
GType: current type: GParamBoxed
GType: current type already exist. return.

GType: enter g_type_class_ref() times = 56.
GType: current type: GParamFloat
GType: type_data_ref_Wm(GParamFloat).
GType: find current type's GParamFloat parent: GParam.
GType: enter g_type_class_ref() times = 57.
GType: current type: GParam
GType: current type already exist. return.

GType: Node name: GParamFloat.
GType: enter g_type_class_ref() times = 58.
GType: current type: GParamBoxed
GType: current type already exist. return.

GType: enter g_type_class_ref() times = 59.
GType: current type: GParamBoxed
GType: current type already exist. return.

GType: enter g_type_class_ref() times = 60.
GType: current type: GParamBoxed
GType: current type already exist. return.

GType: enter g_type_class_ref() times = 61.
GType: current type: GParamBoolean
GType: current type already exist. return.

GType: enter g_type_class_ref() times = 62.
GType: current type: GParamInt
GType: current type already exist. return.

GType: enter g_type_class_ref() times = 63.
GType: current type: GParamInt
GType: current type already exist. return.

GType: enter g_type_class_ref() times = 64.
GType: current type: GParamInt
GType: current type already exist. return.

GType: enter g_type_class_ref() times = 65.
GType: current type: GParamInt
GType: current type already exist. return.

GType: enter g_type_class_ref() times = 66.
GType: current type: GParamString
GType: current type already exist. return.

GType: Node name: GtkContainer.
GType: enter g_type_class_ref() times = 67.
GType: current type: GtkResizeMode
GType: type_data_ref_Wm(GtkResizeMode).
GType: find current type's GtkResizeMode parent: GEnum.
GType: enter g_type_class_ref() times = 68.
GType: current type: GEnum
GType: current type already exist. return.

GType: Node name: GtkResizeMode.
GType: enter g_type_class_ref() times = 69.
GType: current type: GParamEnum
GType: current type already exist. return.

GType: enter g_type_class_ref() times = 70.
GType: current type: GParamUInt
GType: type_data_ref_Wm(GParamUInt).
GType: find current type's GParamUInt parent: GParam.
GType: enter g_type_class_ref() times = 71.
GType: current type: GParam
GType: current type already exist. return.

GType: Node name: GParamUInt.
GType: enter g_type_class_ref() times = 72.
GType: current type: GParamObject
GType: current type already exist. return.

GType: Node name: GtkBin.
GType: Node name: GtkWindow.
GType: enter g_type_class_ref() times = 73.
GType: current type: GtkWindowType
GType: type_data_ref_Wm(GtkWindowType).
GType: find current type's GtkWindowType parent: GEnum.
GType: enter g_type_class_ref() times = 74.
GType: current type: GEnum
GType: current type already exist. return.

GType: Node name: GtkWindowType.
GType: enter g_type_class_ref() times = 75.
GType: current type: GParamEnum
GType: current type already exist. return.

GType: enter g_type_class_ref() times = 76.
GType: current type: GParamString
GType: current type already exist. return.

GType: enter g_type_class_ref() times = 77.
GType: current type: GParamString
GType: current type already exist. return.

GType: enter g_type_class_ref() times = 78.
GType: current type: GParamString
GType: current type already exist. return.

GType: enter g_type_class_ref() times = 79.
GType: current type: GParamBoolean
GType: current type already exist. return.

GType: enter g_type_class_ref() times = 80.
GType: current type: GParamBoolean
GType: current type already exist. return.

GType: enter g_type_class_ref() times = 81.
GType: current type: GParamBoolean
GType: current type already exist. return.

GType: enter g_type_class_ref() times = 82.
GType: current type: GParamBoolean
GType: current type already exist. return.

GType: enter g_type_class_ref() times = 83.
GType: current type: GtkWindowPosition
GType: type_data_ref_Wm(GtkWindowPosition).
GType: find current type's GtkWindowPosition parent: GEnum.
GType: enter g_type_class_ref() times = 84.
GType: current type: GEnum
GType: current type already exist. return.

GType: Node name: GtkWindowPosition.
GType: enter g_type_class_ref() times = 85.
GType: current type: GParamEnum
GType: current type already exist. return.

GType: enter g_type_class_ref() times = 86.
GType: current type: GParamInt
GType: current type already exist. return.

GType: enter g_type_class_ref() times = 87.
GType: current type: GParamInt
GType: current type already exist. return.

GType: enter g_type_class_ref() times = 88.
GType: current type: GParamBoolean
GType: current type already exist. return.

GType: enter g_type_class_ref() times = 89.
GType: current type: GParamObject
GType: current type already exist. return.

GType: enter g_type_class_ref() times = 90.
GType: current type: GParamString
GType: current type already exist. return.

GType: enter g_type_class_ref() times = 91.
GType: current type: GParamObject
GType: current type already exist. return.

GType: enter g_type_class_ref() times = 92.
GType: current type: GParamBoolean
GType: current type already exist. return.

GType: enter g_type_class_ref() times = 93.
GType: current type: GParamBoolean
GType: current type already exist. return.

GType: enter g_type_class_ref() times = 94.
GType: current type: GdkWindowTypeHint
GType: type_data_ref_Wm(GdkWindowTypeHint).
GType: find current type's GdkWindowTypeHint parent: GEnum.
GType: enter g_type_class_ref() times = 95.
GType: current type: GEnum
GType: current type already exist. return.

GType: Node name: GdkWindowTypeHint.
GType: enter g_type_class_ref() times = 96.
GType: current type: GParamEnum
GType: current type already exist. return.

GType: enter g_type_class_ref() times = 97.
GType: current type: GParamBoolean
GType: current type already exist. return.

GType: enter g_type_class_ref() times = 98.
GType: current type: GParamBoolean
GType: current type already exist. return.

GType: enter g_type_class_ref() times = 99.
GType: current type: GParamBoolean
GType: current type already exist. return.

GType: enter g_type_class_ref() times = 100.
GType: current type: GParamBoolean
GType: current type already exist. return.

GType: enter g_type_class_ref() times = 101.
GType: current type: GParamBoolean
GType: current type already exist. return.

GType: enter g_type_class_ref() times = 102.
GType: current type: GParamBoolean
GType: current type already exist. return.

GType: enter g_type_class_ref() times = 103.
GType: current type: GParamBoolean
GType: current type already exist. return.

GType: enter g_type_class_ref() times = 104.
GType: current type: GdkGravity
GType: type_data_ref_Wm(GdkGravity).
GType: find current type's GdkGravity parent: GEnum.
GType: enter g_type_class_ref() times = 105.
GType: current type: GEnum
GType: current type already exist. return.

GType: Node name: GdkGravity.
GType: enter g_type_class_ref() times = 106.
GType: current type: GParamEnum
GType: current type already exist. return.

GType: enter g_type_class_ref() times = 107.
GType: current type: GParamObject
GType: current type already exist. return.

GType: enter g_type_class_ref() times = 108.
GType: current type: GParamDouble
GType: type_data_ref_Wm(GParamDouble).
GType: find current type's GParamDouble parent: GParam.
GType: enter g_type_class_ref() times = 109.
GType: current type: GParam
GType: current type already exist. return.

GType: Node name: GParamDouble.
GType: enter g_type_class_ref() times = 110.
GType: current type: GtkWindow
GType: current type already exist. return.

GObject: g_type_name (object_type) : GtkStyle
GObject: class == NULL.
GType: enter g_type_class_ref() times = 111.
GType: current type: GtkStyle
GType: type_data_ref_Wm(GtkStyle).
GType: find current type's GtkStyle parent: GObject.
GType: enter g_type_class_ref() times = 112.
GType: current type: GObject
GType: current type already exist. return.

GType: Node name: GtkStyle.
GType: enter g_type_class_ref() times = 113.
GType: current type: GtkStyle
GType: current type already exist. return.

(process:802): GLib-GObject-WARNING **: invalid (NULL) pointer instance

(process:802): GLib-GObject-CRITICAL **: g_signal_connect_data: assertion `G_TYPE_CHECK_INSTANCE (instance)' failed
|
`void
|
`GInterface
|
+GTypePlugin
|
+AtkImplementorIface
|
`GtkBuildable
|
`gchar
|
`guchar
|
`gboolean
|
`gint
|
`guint
|
`glong
|
`gulong
|
`gint64
|
`guint64
|
`GEnum
|
+GdkExtensionMode
|
+GtkTouchSoundType
|
+GtkSvibeEffectType
|
+GtkStateType
|
+GtkTextDirection
|
+GtkDirectionType
|
+GtkDragResult
|
+GtkWidgetHelpType
|
+GtkResizeMode
|
+GtkWindowType
|
+GtkWindowPosition
|
+GdkWindowTypeHint
|
`GdkGravity
|
`GFlags
|
`GdkEventMask
|
`gfloat
|
`gdouble
|
`gchararray
|
`gpointer
|
`GType
|
`GBoxed
|
+GValueArray
|
+GtkRequisition
|
+GdkRectangle
|
+GdkEvent
|
+GtkSelectionData
|
+GdkColor
|
`GtkBorder
|
`GParam
|
+GParamChar
|
+GParamUChar
|
+GParamBoolean
|
+GParamInt
|
+GParamUInt
|
+GParamLong
|
+GParamULong
|
+GParamInt64
|
+GParamUInt64
|
+GParamUnichar
|
+GParamEnum
|
+GParamFlags
|
+GParamFloat
|
+GParamDouble
|
+GParamString
|
+GParamParam
|
+GParamBoxed
|
+GParamPointer
|
+GParamValueArray
|
+GParamObject
|
+GParamOverride
|
`GParamGType
|
`GObject
|
+GInitiallyUnowned
| |
| `GtkObject
| |
| `GtkWidget
| |
| `GtkContainer
| |
| `GtkBin
| |
| `GtkWindow
|
+GtkStyle
|
+GdkDrawable
| |
| `GdkWindow
|
+GdkDragContext
|
+GtkTooltip
|
+GdkScreen
|
+GtkDeviceGroup
|
`GdkPixbuf
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息