Realizing, Mapping, and Showing
GLib的一些规范

GTK系统添加建立一种新的“类型”的过程

simplyzhao posted @ 2009年6月07日 04:01 in Gtk+ with tags gtk+ GObject , 2306 阅读

来源:

blog.csai.cn/user1/265/archives/2005/786.html

 

GTK对象系统运行时,为支持对象的动态创建和销毁,系统中必定会拥有所有对象“类型”之间的 关联表,也即所有_GtkTypeNode实体组织而成的“类继承树”,每个_GtkTypeNode代表一种“类型”,它包含了指向 _GtkTypeInfo,以及从_GtkObjectClass派生出的结构的数据信息,所以,我们可以轻松通过GtkType来遍历系统中所有的类 型。

为系统添加建立一种新的“类型”的过程很简单,它一般由gtk_xxx_get_type()触发,例如 gtk_window_get_type()函数。注意,一种新“类型”被加入时,它会创建一个_GtkTypeNode的数据结构,并添入到系统的“类 继承树”中,具体的过程参阅下面的源代码:

 

typedef struct _GtkTypeInfo GtkTypeInfo;

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;
}

 

Enjoy Linux, Fighting.

登录 *


loading captcha image...
(输入验证码)
or Ctrl+Enter