GTK系统添加建立一种新的“类型”的过程
来源:
blog.csai.cn/user1/265/archives/2005/786.html
GTK对象系统运行时,为支持对象的动态创建和销毁,系统中必定会拥有所有对象“类型”之间的 关联表,也即所有_GtkTypeNode实体组织而成的“类继承树”,每个_GtkTypeNode代表一种“类型”,它包含了指向 _GtkTypeInfo,以及从_GtkObjectClass派生出的结构的数据信息,所以,我们可以轻松通过GtkType来遍历系统中所有的类 型。 为系统添加建立一种新的“类型”的过程很简单,它一般由gtk_xxx_get_type()触发,例如 gtk_window_get_type()函数。注意,一种新“类型”被加入时,它会创建一个_GtkTypeNode的数据结构,并添入到系统的“类 继承树”中,具体的过程参阅下面的源代码:
struct _GtkTypeInfo
{
gchar *type_name;
guint object_size;
guint class_size;
GtkClassInitFunc class_init_func;
GtkObjectInitFunc object_init_func;
gpointer reserved_1;
gpointer reserved_2;
GtkClassInitFunc base_class_init_func;
};
GtkType
gtk_window_get_type (void)
{
// 每种“类型”只会被创建一次,因此这里定义static形式的变量
static GtkType window_type = 0;
if (!window_type)
{
// 如果该“类型”仍没有被创建,那么这里创建
// 注意:GtkTypeInfo变量定义也是static的,因为每种“类型”只会对应一份GtkTypeInfo
static const GtkTypeInfo window_info =
{
"GtkWindow",
sizeof (GtkWindow),
sizeof (GtkWindowClass),
(GtkClassInitFunc) gtk_window_class_init,
(GtkObjectInitFunc) gtk_window_init,
/* reserved_1 */ NULL,
/* reserved_2 */ NULL,
(GtkClassInitFunc) NULL,
};
// 创建并返回“类”ID(GtkType值)
// 注意,它的参数有2个:第1个为父类ID;第2个为GtkTypeInfo
// 所以这里很巧妙,它利用了一种递归的方法来保证:子类型的所有父类型都依次会被创建加载
window_type = gtk_type_unique (gtk_bin_get_type (), &window_info);
}
return window_type;
}
/* GtkWindow的父类对象GtkBin,流程与其它一样 */
GtkType
gtk_bin_get_type (void)
{
static guint bin_type = 0;
if (!bin_type)
{
static const GtkTypeInfo bin_info =
{
"GtkBin",
sizeof (GtkBin),
sizeof (GtkBinClass),
(GtkClassInitFunc) gtk_bin_class_init,
(GtkObjectInitFunc) gtk_bin_init,
/* reserved_1 */ NULL,
/* reserved_2 */ NULL,
(GtkClassInitFunc) NULL,
};
bin_type = gtk_type_unique (GTK_TYPE_CONTAINER, &bin_info);
}
return bin_type;
}
/* GtkBin的父类对象GtkContainer,流程与其它一样 */
GtkType
gtk_container_get_type (void)
{
static GtkType container_type = 0;
if (!container_type)
{
static const GtkTypeInfo container_info =
{
"GtkContainer",
sizeof (GtkContainer),
sizeof (GtkContainerClass),
(GtkClassInitFunc) gtk_container_class_init,
(GtkObjectInitFunc) gtk_container_init,
/* reserved_1 */ NULL,
/* reserved_2 */ NULL,
(GtkClassInitFunc) gtk_container_base_class_init,
};
container_type = gtk_type_unique (gtk_widget_get_type (), &container_info);
}
return container_type;
}
/* GtkContainer的父类对象GtkWidget,流程与其它一样 */
GtkType
gtk_widget_get_type (void)
{
static GtkType widget_type = 0;
if (!widget_type)
{
static const GtkTypeInfo widget_info =
{
"GtkWidget",
sizeof (GtkWidget),
sizeof (GtkWidgetClass),
(GtkClassInitFunc) gtk_widget_class_init,
(GtkObjectInitFunc) gtk_widget_init,
/* reserved_1 */ NULL,
/* reserved_2 */ NULL,
(GtkClassInitFunc) NULL,
};
widget_type = gtk_type_unique (gtk_object_get_type (), &widget_info);
}
return widget_type;
}
/* GtkWidget的父类对象GtkObject,根“类型”,没有动态生成一份_GtkTypeNode数据,而是静态定义的 */
GtkType
gtk_object_get_type (void)
{
return GTK_TYPE_OBJECT;
}
/* 创建并返回“类”ID(GtkType值)
* 注意,它的参数有2个:第1个为父类ID;第2个为GtkTypeInfo
*/
GtkType
gtk_type_unique (GtkType parent_type,
const GtkTypeInfo *type_info)
{
GtkType new_type;
gchar *type_name;
g_return_val_if_fail (type_info != NULL, 0);
g_return_val_if_fail (type_info->type_name != NULL, 0);
/* 如果父类ID有问题,返回 */
if (!parent_type && n_ftype_nodes >= GTK_TYPE_FUNDAMENTAL_MAX)
{
g_warning ("gtk_type_unique(): maximum amount of fundamental types reached, "
"try increasing GTK_TYPE_FUNDAMENTAL_MAX");
return 0;
}
type_name = g_strdup (type_info->type_name);
/* relookup pointers afterwards.
*/
// 动态生成一份_GtkTypeNode数据,并计算“类ID”,也即GtkType
new_type = gtk_type_create (parent_type, type_name, type_info);
if (!new_type)
g_free (type_name);
return new_type;
}
/* 动态生成一份_GtkTypeNode数据,加入到系统的“类继承树”中,并计算“类ID”返回(也即GtkType) */
static GtkType
gtk_type_create (GtkType parent_type,
gchar *type_name,
const GtkTypeInfo *type_info)
{
GtkTypeNode *new_node;
GtkTypeNode *parent;
guint i;
if (g_hash_table_lookup (type_name_2_type_ht, type_name))
{
g_warning ("gtk_type_create(): type `%s' already exists.", type_name);
return 0;
}
if (parent_type)
{
GtkTypeNode *tmp_node;
LOOKUP_TYPE_NODE (tmp_node, parent_type);
if (!tmp_node)
{
g_warning ("gtk_type_create(): unknown parent type `%u'.", parent_type);
return 0;
}
}
/* relookup pointers afterwards.
*/
new_node = gtk_type_node_next_and_invalidate (parent_type);
if (parent_type)
{
g_assert (GTK_TYPE_SEQNO (new_node->type) > GTK_TYPE_FUNDAMENTAL_MAX);
LOOKUP_TYPE_NODE (parent, parent_type);
}
else
{
g_assert (new_node->type <= GTK_TYPE_FUNDAMENTAL_MAX);
parent = NULL;
}
/* 这里对新“类型”的结点(GtkTypeNode)进行赋值,重点注意几个字段 */
// _GtkTypeInfo数据
new_node->type_info = *type_info;
new_node->type_info.type_name = type_name;
/* new_node->type_info.reserved_1 = NULL; */
new_node->type_info.reserved_2 = NULL;
// 全部父类的数量
new_node->n_supers = parent ? parent->n_supers + 1 : 0;
new_node->chunk_alloc_locked = FALSE;
// 全部父“类”的ID,一个GtkType[]数组
new_node->supers = g_new0 (GtkType, new_node->n_supers + 1);
// 直系的父“类”的ID,通过它,所有的“类”串联起来形成一个链表
new_node->parent_type = parent_type;
// 这里指向从_GtkObjectClass派生出的“类”结构的klass字段暂时置为NULL
new_node->klass = NULL;
new_node->children_types = NULL;
new_node->mem_chunk = NULL;
if (parent)
parent->children_types = g_list_append (parent->children_types, GUINT_TO_POINTER (new_node->type));
parent = new_node;
for (i = 0; i < new_node->n_supers + 1; i++)
{
new_node->supers[i] = parent->type;
LOOKUP_TYPE_NODE (parent, parent->parent_type);
}
g_hash_table_insert (type_name_2_type_ht, new_node->type_info.type_name, GUINT_TO_POINTER (new_node->type));
return new_node->type;
}