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

来源:互联网 发布:大数据服务器搭建 编辑:程序博客网 时间:2024/04/29 18:36

http://blog.csdn.net/cuijpus/article/details/4245828


 

看看GtkWindow如何被生出来的.

用Glib/GObject/Gtk也有很长时间了,没有时间往下刨根,现在刨一刨。

 

1 定义GtkWindow

2 展开它:

在gtype.h中定义如下宏:

把定义的宏展开:

再把GtkBin的定义展开:

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

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

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

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

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

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

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

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

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

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

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

Go on: GtkBin

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

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

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

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

重点看看g_object_newv:

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

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

Base_class_init()调用的顺序:

1. g_object_base_class_init

2 gtk_object_base_class_init

3 gtk_widget_base_class_init 是NULL所以不调用

4 gtk_container_base_class_init

5 gtk_bin, gtk_windonw的base_class_init()都是NULL

下面开始class_init:

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

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

条件:

结果:

 

 

 

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 = &parameters[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


原创粉丝点击