gobject运行时重要的数据结构。

 

 数据定义

 说明

gtype

static TypeNode                               *static_fundamental_type_nodes[256]

一个全局指针数组, 用来保存基本类型;

通过基本类型顺藤摸瓜,可以找到其子类型

static GHashTable       *static_type_nodes_ht = NULL;

一个全局的Hash Table

这个Hash Table一般是通过“名字”来查询TypeNode时使用

 

 

 

Signal

static SignalNode   **g_signal_nodes = NULL;

双指针 == 指针数组?

  static GBSearchArray *g_signal_key_bsa = NULL;  方便根据signal name/type来查询signal_id

 

static GHashTable    *g_handler_list_bsa_ht = NULL;

信号处理函数用hash table

 

static Emission      *g_recursive_emissions = NULL;

 

 

static Emission      *g_restart_emissions = NULL;

 

 

object

static GQuark                 quark_closure_array = 0;

 这个和CArray关系紧密;是Object的回调函数数组的标志。

 

static GQuark                 quark_weak_refs = 0;

 

 

static GQuark                 quark_toggle_refs = 0;

 

 

static GObjectNotifyContext property_notify_context = { 0, };

 

 

static gulong                   gobject_signals[LAST_SIGNAL] = { 0, };

全局数组

 

param_spec

static GParamSpecPool *pspec_pool = NULL;

 用Hash Table来保存Object的ParamSpec

 

/* --- type initialization --- */

GType *g_param_spec_types = NULL;

一个全局数组

Gtype.c中

1. 定义:

//这个用处比较少,只是用“名字”来查询时用
static GHashTable       *static_type_nodes_ht = NULL;

//这个用的比较多,访问数组查询效率高
static TypeNode		*static_fundamental_type_nodes[(G_TYPE_FUNDAMENTAL_MAX >> G_TYPE_FUNDAMENTAL_SHIFT) + 1] = { NULL, };

2. 初始化

void
g_type_init_with_debug_flags (GTypeDebugFlags debug_flags)
{
  G_LOCK_DEFINE_STATIC (type_init_lock);
  const gchar *env_string;
  GTypeInfo info;
  TypeNode *node;
  volatile GType votype;

  
   
  /* type qname hash table */
  static_type_nodes_ht = g_hash_table_new (g_direct_hash, g_direct_equal);
  
  /* invalid type G_TYPE_INVALID (0)
   */
  static_fundamental_type_nodes[0] = NULL;

3. New 一个Type:

type_node_any_new_W()

如果是基本类型的,直接放入数组中:static_fundamental_type_nodes;

如果有父类,则查到父类,然后放入父类的子类数组pnode->children[i]中;

同时把新建的Type, 放入Hash Table:static_type_nodes_ht中。

static TypeNode*
type_node_any_new_W (TypeNode             *pnode,
		     GType                 ftype,
		     const gchar          *name,
		     GTypePlugin          *plugin,
		     GTypeFundamentalFlags type_flags)
{
  guint n_supers;
  GType type;
  TypeNode *node;
  guint i, node_size = 0;

  n_supers = pnode ? pnode->n_supers + 1 : 0;
  
  if (!pnode)
    node_size += SIZEOF_FUNDAMENTAL_INFO;	      /* fundamental type info */
  node_size += SIZEOF_BASE_TYPE_NODE ();	      /* TypeNode structure */
  node_size += (sizeof (GType) * (1 + n_supers + 1)); /* self + ancestors + (0) for ->supers[] */
  node = g_malloc0 (node_size);
  if (!pnode)					      /* offset fundamental types */
    {
      node = G_STRUCT_MEMBER_P (node, SIZEOF_FUNDAMENTAL_INFO);
      static_fundamental_type_nodes[ftype >> G_TYPE_FUNDAMENTAL_SHIFT] = node;
      type = ftype;
    }
  else
    type = (GType) node;
  
  g_assert ((type & TYPE_ID_MASK) == 0);
  
  node->n_supers = n_supers;
  if (!pnode)
    {
      node->supers[0] = type;
      node->supers[1] = 0;
      
      node->is_classed = (type_flags & G_TYPE_FLAG_CLASSED) != 0;
      node->is_instantiatable = (type_flags & G_TYPE_FLAG_INSTANTIATABLE) != 0;
      
      if (NODE_IS_IFACE (node))
	{
          IFACE_NODE_N_PREREQUISITES (node) = 0;
	  IFACE_NODE_PREREQUISITES (node) = NULL;
	}
      else
	_g_atomic_array_init (CLASSED_NODE_IFACES_ENTRIES (node));
    }
  else
    {
      node->supers[0] = type;
      memcpy (node->supers + 1, pnode->supers, sizeof (GType) * (1 + pnode->n_supers + 1));
      
      node->is_classed = pnode->is_classed;
      node->is_instantiatable = pnode->is_instantiatable;
      
      if (NODE_IS_IFACE (node))
	{
	  IFACE_NODE_N_PREREQUISITES (node) = 0;
	  IFACE_NODE_PREREQUISITES (node) = NULL;
	}
      else
	{
	  guint j;
	  IFaceEntries *entries;

	  entries = _g_atomic_array_copy (CLASSED_NODE_IFACES_ENTRIES (pnode),
					  IFACE_ENTRIES_HEADER_SIZE,
					  0);
	  if (entries)
	    {
	      for (j = 0; j < IFACE_ENTRIES_N_ENTRIES (entries); j++)
		{
		  entries->entry[j].vtable = NULL;
		  entries->entry[j].init_state = UNINITIALIZED;
		}
	      _g_atomic_array_update (CLASSED_NODE_IFACES_ENTRIES (node),
				      entries);
	    }
	}

      i = pnode->n_children++;
      pnode->children = g_renew (GType, pnode->children, pnode->n_children);
      pnode->children[i] = type;
    }

  TRACE(GOBJECT_TYPE_NEW(name, node->supers[1], type));

  
  g_hash_table_insert (static_type_nodes_ht,
		       GUINT_TO_POINTER (node->qname),
		       (gpointer) type);
  return node;
}

4. 查询TypeNode,

用的比较多的是lookup_type_node_I,直接访问数组

static inline TypeNode*
lookup_type_node_I (register GType utype)
{
  if (utype > G_TYPE_FUNDAMENTAL_MAX)
    return (TypeNode*) (utype & ~TYPE_ID_MASK);
  else
    return static_fundamental_type_nodes[utype >> G_TYPE_FUNDAMENTAL_SHIFT];
}

 

当使用Type Name来查询时,访问Hash Table比较快:

这个函数目前看,使用还不是很多。

GType
g_type_from_name (const gchar *name)
{
  GType type = 0;
  GQuark quark;
  
  g_return_val_if_fail (name != NULL, 0);
  
  quark = g_quark_try_string (name);
  if (quark)
    {
      G_READ_LOCK (&type_rw_lock);
      type = (GType) g_hash_table_lookup (static_type_nodes_ht, GUINT_TO_POINTER (quark));
      G_READ_UNLOCK (&type_rw_lock);
    }
  
  return type;
}

 

GParamSpec.c:

1. 定义一个全局指针g_param_spec_types,引用时也可以用数组的方式进行:

/* --- type initialization --- */
GType *g_param_spec_types = NULL;

 

2. 初始化

 首先分配一块内存给g_param_spec_types:

然后注册23个基本的参数类型,同时对每种参数类型,都提供相应的处理函数:

void
g_param_spec_types_init (void)	
{
  const guint n_types = 23;
  GType type, *spec_types, *spec_types_bound;

  g_param_spec_types = g_new0 (GType, n_types);
  spec_types = g_param_spec_types;
  spec_types_bound = g_param_spec_types + n_types;
  
  /* G_TYPE_PARAM_CHAR
   */
  {
    static const GParamSpecTypeInfo pspec_info = {
      sizeof (GParamSpecChar),	/* instance_size */
      16,			/* n_preallocs */
      param_char_init,		/* instance_init */
      G_TYPE_CHAR,		/* value_type */
      NULL,			/* finalize */
      param_char_set_default,	/* value_set_default */
      param_char_validate,	/* value_validate */
      param_int_values_cmp,	/* values_cmp */
    };
    type = g_param_type_register_static (g_intern_static_string ("GParamChar"), &pspec_info);
    *spec_types++ = type;
    g_assert (type == G_TYPE_PARAM_CHAR);
  }
  

 基本23个参数类型:

  +GParamChar
  |
  +GParamUChar
  |
  +GParamBoolean
  |
  +GParamInt
  |
  +GParamUInt
  |
  +GParamLong
  |
  +GParamULong
  |
  +GParamInt64
  |
  +GParamUInt64
  |
  +GParamUnichar
  |
  +GParamEnum
  |
  +GParamFlags
  |
  +GParamFloat
  |
  +GParamDouble
  |
  +GParamString
  |
  +GParamParam
  |
  +GParamBoxed
  |
  +GParamPointer
  |
  +GParamValueArray
  |
  +GParamObject
  |
  +GParamOverride
  |
  +GParamGType
  |
  `GParamVariant

3. 引用这个数组:

初始化后,就可以直接使用这个数组了:

今后就用宏直接访问该参数类型,以及其关联的处理函数了。

#define	G_TYPE_PARAM_CHAR		   (g_param_spec_types[0])
#define	G_TYPE_PARAM_UCHAR		   (g_param_spec_types[1])
#define	G_TYPE_PARAM_BOOLEAN		   (g_param_spec_types[2])
#define	G_TYPE_PARAM_INT		   (g_param_spec_types[3])
#define	G_TYPE_PARAM_UINT		   (g_param_spec_types[4])
#define	G_TYPE_PARAM_LONG		   (g_param_spec_types[5])
#define	G_TYPE_PARAM_ULONG		   (g_param_spec_types[6])
#define	G_TYPE_PARAM_INT64		   (g_param_spec_types[7])
#define	G_TYPE_PARAM_UINT64		   (g_param_spec_types[8])
#define	G_TYPE_PARAM_UNICHAR		   (g_param_spec_types[9])
#define	G_TYPE_PARAM_ENUM		   (g_param_spec_types[10])
#define	G_TYPE_PARAM_FLAGS		   (g_param_spec_types[11])
#define	G_TYPE_PARAM_FLOAT		   (g_param_spec_types[12])
#define	G_TYPE_PARAM_DOUBLE		   (g_param_spec_types[13])
#define	G_TYPE_PARAM_STRING		   (g_param_spec_types[14])
#define	G_TYPE_PARAM_PARAM		   (g_param_spec_types[15])
#define	G_TYPE_PARAM_BOXED		   (g_param_spec_types[16])
#define	G_TYPE_PARAM_POINTER		   (g_param_spec_types[17])
#define	G_TYPE_PARAM_VALUE_ARRAY	   (g_param_spec_types[18])
#define	G_TYPE_PARAM_OBJECT		   (g_param_spec_types[19])
#define	G_TYPE_PARAM_OVERRIDE		   (g_param_spec_types[20])
#define	G_TYPE_PARAM_GTYPE		   (g_param_spec_types[21])
#define G_TYPE_PARAM_VARIANT                (g_param_spec_types[22])

例如,创建参数类型实例:

GParamSpec*
g_param_spec_char (const gchar *name,
		   const gchar *nick,
		   const gchar *blurb,
		   gint8	minimum,
		   gint8	maximum,
		   gint8	default_value,
		   GParamFlags	flags)
{
  GParamSpecChar *cspec;

  g_return_val_if_fail (default_value >= minimum && default_value <= maximum, NULL);

  cspec = g_param_spec_internal (G_TYPE_PARAM_CHAR,
				 name,
				 nick,
				 blurb,
				 flags);
  
  cspec->minimum = minimum;
  cspec->maximum = maximum;
  cspec->default_value = default_value;
  
  return G_PARAM_SPEC (cspec);
}

Gobject install property时,会大量使用上面这类函数:

static void
gst_play_base_bin_class_init (GstPlayBaseBinClass * klass)
{
  GObjectClass *gobject_klass;
  GstElementClass *gstelement_klass;
  GstBinClass *gstbin_klass;

  gobject_klass = (GObjectClass *) klass;
  gstelement_klass = (GstElementClass *) klass;
  gstbin_klass = (GstBinClass *) klass;

  parent_class = g_type_class_peek_parent (klass);

  gobject_klass->set_property = gst_play_base_bin_set_property;
  gobject_klass->get_property = gst_play_base_bin_get_property;

  g_object_class_install_property (gobject_klass, ARG_URI,
      g_param_spec_string ("uri", "URI", "URI of the media to play",
          NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
  g_object_class_install_property (gobject_klass, ARG_SUBURI,
      g_param_spec_string ("suburi", ".sub-URI", "Optional URI of a subtitle",
          NULL, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));

  g_object_class_install_property (gobject_klass, ARG_QUEUE_SIZE,
      g_param_spec_uint64 ("queue-size", "Queue size",
          "Size of internal queues in nanoseconds", 0, G_MAXINT64,
          DEFAULT_QUEUE_SIZE, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
  g_object_class_install_property (gobject_klass, ARG_QUEUE_THRESHOLD,
      g_param_spec_uint64 ("queue-threshold", "Queue threshold",
          "Buffering threshold of internal queues in nanoseconds", 0,
          G_MAXINT64, DEFAULT_QUEUE_THRESHOLD,
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
  g_object_class_install_property (gobject_klass, ARG_QUEUE_MIN_THRESHOLD,
      g_param_spec_uint64 ("queue-min-threshold", "Queue min threshold",
          "Buffering low threshold of internal queues in nanoseconds", 0,
          G_MAXINT64, DEFAULT_QUEUE_MIN_THRESHOLD,
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));

  g_object_class_install_property (gobject_klass, ARG_NSTREAMS,
      g_param_spec_int ("nstreams", "NStreams", "number of streams",
          0, G_MAXINT, 0, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
  g_object_class_install_property (gobject_klass, ARG_STREAMINFO,
      g_param_spec_pointer ("stream-info", "Stream info", "List of streaminfo",
          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
  g_object_class_install_property (gobject_klass, ARG_STREAMINFO_VALUES,
      g_param_spec_value_array ("stream-info-value-array",
          "StreamInfo GValueArray", "value array of streaminfo",
          g_param_spec_object ("streaminfo", "StreamInfo", "Streaminfo object",
              GST_TYPE_STREAM_INFO, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS),
          G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));
  g_object_class_install_property (gobject_klass, ARG_SOURCE,
      g_param_spec_object ("source", "Source", "Source element",
          GST_TYPE_ELEMENT, G_PARAM_READABLE | G_PARAM_STATIC_STRINGS));

  g_object_class_install_property (gobject_klass, ARG_VIDEO,
      g_param_spec_int ("current-video", "Current video",
          "Currently playing video stream (-1 = none)",
          -1, G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
  g_object_class_install_property (gobject_klass, ARG_AUDIO,
      g_param_spec_int ("current-audio", "Current audio",
          "Currently playing audio stream (-1 = none)",
          -1, G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
  g_object_class_install_property (gobject_klass, ARG_TEXT,
      g_param_spec_int ("current-text", "Current text",
          "Currently playing text stream (-1 = none)",
          -1, G_MAXINT, -1, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
  g_object_class_install_property (gobject_klass, ARG_SUBTITLE_ENCODING,
      g_param_spec_string ("subtitle-encoding", "subtitle encoding",
          "Encoding to assume if input subtitles are not in UTF-8 encoding. "
          "If not set, the GST_SUBTITLE_ENCODING environment variable will "
          "be checked for an encoding to use. If that is not set either, "
          "ISO-8859-15 will be assumed.", NULL,
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
  /**
   * GstPlayBaseBin:connection-speed
   *
   * Network connection speed in kbps (0 = unknown)
   * <note><simpara>
   * Since version 0.10.10 in #GstPlayBin, at 0.10.15 moved to #GstPlayBaseBin
   * </simpara></note>
   *
   * Since: 0.10.10
   */
  g_object_class_install_property (gobject_klass, ARG_CONNECTION_SPEED,
      g_param_spec_uint ("connection-speed", "Connection Speed",
          "Network connection speed in kbps (0 = unknown)",
          0, G_MAXUINT, DEFAULT_CONNECTION_SPEED,
          G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));

  GST_DEBUG_CATEGORY_INIT (gst_play_base_bin_debug, "playbasebin", 0,
      "playbasebin");

  gobject_klass->dispose = gst_play_base_bin_dispose;
  gobject_klass->finalize = gst_play_base_bin_finalize;

  gstbin_klass->handle_message =
      GST_DEBUG_FUNCPTR (gst_play_base_bin_handle_message_func);

  gstelement_klass->change_state =
      GST_DEBUG_FUNCPTR (gst_play_base_bin_change_state);
}

注意:g_param_spec_types数组仅仅保存上面预定义的23个基本类型的参数,以及其对应的处理函数。

通过g_param_spec_xxx() 实例化出来的参数实例,是保持在另外一个参数池GParamSpecPool中的。参加下面内容:

 

GObject的属性如何保持的?

在Gobject.c中,

1. 定义一个静态全局变量:

static GParamSpecPool      *pspec_pool = NULL;

属性池其实就是:互斥保护+散列表

2. 申请一块内存:

static void
g_object_do_class_init (GObjectClass *class)
{
  /* read the comment about typedef struct CArray; on why not to change this quark */
  quark_closure_array = g_quark_from_static_string ("GObject-closure-array");

  quark_weak_refs = g_quark_from_static_string ("GObject-weak-references");
  quark_toggle_refs = g_quark_from_static_string ("GObject-toggle-references");
  pspec_pool = g_param_spec_pool_new (TRUE);
  property_notify_context.quark_notify_queue = g_quark_from_static_string ("GObject-notify-queue");
  property_notify_context.dispatcher = g_object_notify_dispatcher;

3. 把参数属性,插入到属性池中,也就是放到Hash Table中:

static inline void
install_property_internal (GType       g_type,
			   guint       property_id,
			   GParamSpec *pspec)
{
  if (g_param_spec_pool_lookup (pspec_pool, pspec->name, g_type, FALSE))
    {
      g_warning ("When installing property: type `%s' already has a property named `%s'",
		 g_type_name (g_type),
		 pspec->name);
      return;
    }

  g_param_spec_ref (pspec);
  g_param_spec_sink (pspec);
  PARAM_SPEC_SET_PARAM_ID (pspec, property_id);
  g_param_spec_pool_insert (pspec_pool, pspec, g_type);
}
void
g_param_spec_pool_insert (GParamSpecPool *pool,
			  GParamSpec     *pspec,
			  GType           owner_type)
{
  gchar *p;
  
  if (pool && pspec && owner_type > 0 && pspec->owner_type == 0)
    {
      G_SLOCK (&pool->smutex);
      for (p = pspec->name; *p; p++)
	{
	  if (!strchr (G_CSET_A_2_Z G_CSET_a_2_z G_CSET_DIGITS "-_", *p))
	    {
	      g_warning (G_STRLOC ": pspec name \"%s\" contains invalid characters", pspec->name);
	      G_SUNLOCK (&pool->smutex);
	      return;
	    }
	}
      
      pspec->owner_type = owner_type;
      g_param_spec_ref (pspec);
      g_hash_table_insert (pool->hash_table, pspec, pspec);

4. 从属性池中查询属性:

static GParamSpecPool      *pspec_pool = NULL;
list = g_param_spec_pool_list_owned (pspec_pool, G_OBJECT_CLASS_TYPE (class));
g_param_spec_pool_remove (pspec_pool, pspec);
pspec_pool = g_param_spec_pool_new (TRUE);
if (g_param_spec_pool_lookup (pspec_pool, pspec->name, g_type, FALSE))
g_param_spec_pool_insert (pspec_pool, pspec, g_type);
pspec = g_param_spec_pool_lookup (pspec_pool, pspec->name, g_type_parent (G_OBJECT_CLASS_TYPE (class)), TRUE);
pspec = g_param_spec_pool_lookup (pspec_pool, pspec->name, parent_type, TRUE);
pspec = g_param_spec_pool_lookup (pspec_pool,
return g_param_spec_pool_lookup (pspec_pool,
overridden = g_param_spec_pool_lookup (pspec_pool,
overridden = g_param_spec_pool_lookup (pspec_pool,
pspecs = g_param_spec_pool_list (pspec_pool,
pspecs = g_param_spec_pool_list (pspec_pool,
pspec = g_param_spec_pool_lookup (pspec_pool,
pspecs = g_param_spec_pool_list (pspec_pool, iface_type, &n);
GParamSpec *class_pspec = g_param_spec_pool_lookup (pspec_pool,
GParamSpec *pspec = g_param_spec_pool_lookup (pspec_pool,
GParamSpec *pspec = g_param_spec_pool_lookup (pspec_pool,
pspec = g_param_spec_pool_lookup (pspec_pool,
pspec = g_param_spec_pool_lookup (pspec_pool,
pspec = g_param_spec_pool_lookup (pspec_pool,
pspec = g_param_spec_pool_lookup (pspec_pool,

 

5. 从Hash Table中提取所有的属性,到链表中,

用g_param_spec_pool_list

 

6. 从属性池中,根据属性名字,提取一个属性:

g_param_spec_pool_lookup

 

Gobject的属性如何install上去的:

安装属性,其实就是把属性放到hash table中:

void
g_object_class_install_property (GObjectClass *class,
				 guint	       property_id,
				 GParamSpec   *pspec)
void
g_object_class_install_properties (GObjectClass  *oclass,
                                   guint          n_pspecs,
                                   GParamSpec   **pspecs)
void
g_object_interface_install_property (gpointer      g_iface,
				     GParamSpec   *pspec)
{
  GTypeInterface *iface_class = g_iface;
	
  g_return_if_fail (G_TYPE_IS_INTERFACE (iface_class->g_type));
  g_return_if_fail (G_IS_PARAM_SPEC (pspec));
  g_return_if_fail (!G_IS_PARAM_SPEC_OVERRIDE (pspec)); /* paranoid */
  g_return_if_fail (PARAM_SPEC_PARAM_ID (pspec) == 0);	/* paranoid */
		    
  install_property_internal (iface_class->g_type, 0, pspec);
}

最后都是放到那个全局变量pspec_pool中:

static inline void
install_property_internal (GType       g_type,
			   guint       property_id,
			   GParamSpec *pspec)
{
  if (g_param_spec_pool_lookup (pspec_pool, pspec->name, g_type, FALSE))
    {
      g_warning ("When installing property: type `%s' already has a property named `%s'",
		 g_type_name (g_type),
		 pspec->name);
      return;
    }

  g_param_spec_ref (pspec);
  g_param_spec_sink (pspec);
  PARAM_SPEC_SET_PARAM_ID (pspec, property_id);
  g_param_spec_pool_insert (pspec_pool, pspec, g_type);
}

 

GObject的属性被被改变时,如何响应的:

 

 

GObject的回调数组

GObject的回调,实际上是为了处理用户定义的signal/callback.

1. 定义个数据结构:

typedef struct {
  GObject  *object;
  guint     n_closures;
  GClosure *closures[1]; /* flexible array */
} CArray;  //closure Array

同时定义一个标识:

static GQuark	            quark_closure_array = 0;
static void
g_object_do_class_init (GObjectClass *class)
{
  /* read the comment about typedef struct CArray; on why not to change this quark */
  quark_closure_array = g_quark_from_static_string ("GObject-closure-array");

2. 从object的回调数组 中拿掉一个回调:

static void
object_remove_closure (gpointer  data,
		       GClosure *closure)
{
  GObject *object = data;
  CArray *carray;
  guint i;
  
  G_LOCK (closure_array_mutex);
  carray = g_object_get_qdata (object, quark_closure_array);
  for (i = 0; i < carray->n_closures; i++)
    if (carray->closures[i] == closure)
      {
	carray->n_closures--;
	if (i < carray->n_closures)
	  carray->closures[i] = carray->closures[carray->n_closures];
	G_UNLOCK (closure_array_mutex);
	return;
      }
  G_UNLOCK (closure_array_mutex);
  g_assert_not_reached ();
}

3. 给Object增加一个需要监视的回调(GClosure), 放到回调数组中(Closure Array)

void
g_object_watch_closure (GObject  *object,
			GClosure *closure)
{
  CArray *carray;
  guint i;
  
  g_return_if_fail (G_IS_OBJECT (object));
  g_return_if_fail (closure != NULL);
  g_return_if_fail (closure->is_invalid == FALSE);
  g_return_if_fail (closure->in_marshal == FALSE);
  g_return_if_fail (object->ref_count > 0);	/* this doesn't work on finalizing objects */
  
  g_closure_add_invalidate_notifier (closure, object, object_remove_closure);
  g_closure_add_marshal_guards (closure,
				object, (GClosureNotify) g_object_ref,
				object, (GClosureNotify) g_object_unref);
  G_LOCK (closure_array_mutex);
  carray = g_datalist_id_remove_no_notify (&object->qdata, quark_closure_array);
  if (!carray)
    {
      carray = g_renew (CArray, NULL, 1);
      carray->object = object;
      carray->n_closures = 1;
      i = 0;
    }
  else
    {
      i = carray->n_closures++;
      carray = g_realloc (carray, sizeof (*carray) + sizeof (carray->closures[0]) * i);
    }
  carray->closures[i] = closure;
  g_datalist_id_set_data_full (&object->qdata, quark_closure_array, carray, destroy_closure_array);
  G_UNLOCK (closure_array_mutex);
}

4. 创建一个新的回调:注册user callback, 并且绑定Object, 同时加入Object的 Callback Array中:

GClosure*
g_cclosure_new_object (GCallback callback_func,
		       GObject  *object)
{
  GClosure *closure;

  g_return_val_if_fail (G_IS_OBJECT (object), NULL);
  g_return_val_if_fail (object->ref_count > 0, NULL);     /* this doesn't work on finalizing objects */
  g_return_val_if_fail (callback_func != NULL, NULL);

  closure = g_cclosure_new (callback_func, object, NULL);
  g_object_watch_closure (object, closure);

  return closure;
}

5. 把signal和信号回调联系在一起

这时候,把signal和object的callback array联系在一起了:

gulong
g_signal_connect_object (gpointer      instance,
			 const gchar  *detailed_signal,
			 GCallback     c_handler,
			 gpointer      gobject,
			 GConnectFlags connect_flags)
{
  g_return_val_if_fail (G_TYPE_CHECK_INSTANCE (instance), 0);
  g_return_val_if_fail (detailed_signal != NULL, 0);
  g_return_val_if_fail (c_handler != NULL, 0);

  if (gobject)
    {
      GClosure *closure;

      g_return_val_if_fail (G_IS_OBJECT (gobject), 0);

      closure = ((connect_flags & G_CONNECT_SWAPPED) ? g_cclosure_new_object_swap : g_cclosure_new_object) (c_handler, gobject);

      return g_signal_connect_closure (instance, detailed_signal, closure, connect_flags & G_CONNECT_AFTER);
    }
  else
    return g_signal_connect_data (instance, detailed_signal, c_handler, NULL, NULL, connect_flags);
}

 

6. 进一步的封装:可以链接一串信号

gpointer
g_object_connect (gpointer     _object,
		  const gchar *signal_spec,
		  ...)
{
  GObject *object = _object;
  va_list var_args;

  g_return_val_if_fail (G_IS_OBJECT (object), NULL);
  g_return_val_if_fail (object->ref_count > 0, object);

  va_start (var_args, signal_spec);
  while (signal_spec)
    {
      GCallback callback = va_arg (var_args, GCallback);
      gpointer data = va_arg (var_args, gpointer);
      gulong sid;

      if (strncmp (signal_spec, "signal::", 8) == 0)
	sid = g_signal_connect_data (object, signal_spec + 8,
				     callback, data, NULL,
				     0);
      else if (strncmp (signal_spec, "object_signal::", 15) == 0 ||
               strncmp (signal_spec, "object-signal::", 15) == 0)
	sid = g_signal_connect_object (object, signal_spec + 15,
				       callback, data,
				       0);
      else if (strncmp (signal_spec, "swapped_signal::", 16) == 0 ||
               strncmp (signal_spec, "swapped-signal::", 16) == 0)
	sid = g_signal_connect_data (object, signal_spec + 16,
				     callback, data, NULL,
				     G_CONNECT_SWAPPED);
      else if (strncmp (signal_spec, "swapped_object_signal::", 23) == 0 ||
               strncmp (signal_spec, "swapped-object-signal::", 23) == 0)
	sid = g_signal_connect_object (object, signal_spec + 23,
				       callback, data,
				       G_CONNECT_SWAPPED);
      else if (strncmp (signal_spec, "signal_after::", 14) == 0 ||
               strncmp (signal_spec, "signal-after::", 14) == 0)
	sid = g_signal_connect_data (object, signal_spec + 14,
				     callback, data, NULL,
				     G_CONNECT_AFTER);
      else if (strncmp (signal_spec, "object_signal_after::", 21) == 0 ||
               strncmp (signal_spec, "object-signal-after::", 21) == 0)
	sid = g_signal_connect_object (object, signal_spec + 21,
				       callback, data,
				       G_CONNECT_AFTER);
      else if (strncmp (signal_spec, "swapped_signal_after::", 22) == 0 ||
               strncmp (signal_spec, "swapped-signal-after::", 22) == 0)
	sid = g_signal_connect_data (object, signal_spec + 22,
				     callback, data, NULL,
				     G_CONNECT_SWAPPED | G_CONNECT_AFTER);
      else if (strncmp (signal_spec, "swapped_object_signal_after::", 29) == 0 ||
               strncmp (signal_spec, "swapped-object-signal-after::", 29) == 0)
	sid = g_signal_connect_object (object, signal_spec + 29,
				       callback, data,
				       G_CONNECT_SWAPPED | G_CONNECT_AFTER);
      else
	{
	  g_warning ("%s: invalid signal spec \"%s\"", G_STRFUNC, signal_spec);
	  break;
	}
      signal_spec = va_arg (var_args, gchar*);
    }
  va_end (var_args);

  return object;
}

 

7. 例子:比如gstbin:

  /* use the sync signal handler to link elements while the pipeline is still
   * doing the state change */
  gst_bus_set_sync_handler (bus, gst_bus_sync_signal_handler, pipeline);
  g_object_connect (bus, "signal::sync-message::state-changed",
      G_CALLBACK (test_link_structure_change_state_changed_sync_cb), pipeline,
      NULL);

 

8. 再如:gtk test中:

      button = g_object_new (gtk_button_get_type (),
			       "label", "push something",
			       "visible", TRUE,
			       "parent", box2,
			       NULL);
      g_object_connect (button,
			"signal::clicked", statusbar_push, statusbar,
			NULL);

      button = g_object_connect (g_object_new (gtk_button_get_type (),
						 "label", "pop",
						 "visible", TRUE,
						 "parent", box2,
						 NULL),
				 "signal_after::clicked", statusbar_pop, statusbar,
				 NULL);

      button = g_object_connect (g_object_new (gtk_button_get_type (),
						 "label", "steal #4",
						 "visible", TRUE,
						 "parent", box2,
						 NULL),
				 "signal_after::clicked", statusbar_steal, statusbar,
				 NULL);

      button = g_object_connect (g_object_new (gtk_button_get_type (),
						 "label", "test contexts",
						 "visible", TRUE,
						 "parent", box2,
						 NULL),
				 "swapped_signal_after::clicked", statusbar_contexts, statusbar,
				 NULL);

      button = g_object_connect (g_object_new (gtk_button_get_type (),
						 "label", "push something long",
						 "visible", TRUE,
						 "parent", box2,
						 NULL),
				 "signal_after::clicked", statusbar_push_long, statusbar,
				 NULL);

 

GSignal的SignalNode用指针数组保存:

1. 定义一个双指针

双指针,类似于指针数组;由于数组大小未知,定义为双指针。

/* --- signal nodes --- */
static guint          g_n_signal_nodes = 0;
static SignalNode   **g_signal_nodes = NULL;

如果知道了g_signal_nodes的大小,

可以像TypeNode那样定义:

static TypeNode		*static_fundamental_type_nodes[(G_TYPE_FUNDAMENTAL_MAX >> G_TYPE_FUNDAMENTAL_SHIFT) + 1] = { NULL, };

即:*static_fundamental_type_nodes[256]

 

假设信号最多有128个,我们可以这样定义:

static SignalNode   *g_signal_nodes[128 + 1] = { NULL, }

 

2. 初始化

void
g_signal_init (void)
{
  SIGNAL_LOCK ();
  if (!g_n_signal_nodes)
    {
      /* setup handler list binary searchable array hash table (in german, that'd be one word ;) */
      g_handler_list_bsa_ht = g_hash_table_new (g_direct_hash, NULL);
      g_signal_key_bsa = g_bsearch_array_create (&g_signal_key_bconfig);

      
      /* invalid (0) signal_id */
      g_n_signal_nodes = 1;
      g_signal_nodes = g_renew (SignalNode*, g_signal_nodes, g_n_signal_nodes);
      g_signal_nodes[0] = NULL;
    }
  SIGNAL_UNLOCK ();
}

3. 创建信号时:

吧新创建的SignalNode放入指针数组g_signal_nodes[signal_id]中:

guint
g_signal_newv (const gchar       *signal_name,
               GType              itype,
               GSignalFlags       signal_flags,
               GClosure          *class_closure,
               GSignalAccumulator accumulator,
	       gpointer		  accu_data,
               GSignalCMarshaller c_marshaller,
               GType		  return_type,
               guint              n_params,
               GType		 *param_types)
{
  gchar *name;
  guint signal_id, i;
  SignalNode *node;

  /* setup permanent portion of signal node */
  ////////////////////////////
  //....................
 
  ////////////////////////////

  if (!node)
    {
      SignalKey key;
      
      signal_id = g_n_signal_nodes++;
      node = g_new (SignalNode, 1);
      node->signal_id = signal_id;
      g_signal_nodes = g_renew (SignalNode*, g_signal_nodes, g_n_signal_nodes);
      g_signal_nodes[signal_id] = node;
      node->itype = itype;
      node->name = name;
      key.itype = itype;
      key.quark = g_quark_from_string (node->name);
      key.signal_id = signal_id;
      g_signal_key_bsa = g_bsearch_array_insert (g_signal_key_bsa, &g_signal_key_bconfig, &key);
      g_strdelimit (name, "_", '-');
      node->name = g_intern_string (name);
      key.quark = g_quark_from_string (name);
      g_signal_key_bsa = g_bsearch_array_insert (g_signal_key_bsa, &g_signal_key_bconfig, &key);

      TRACE(GOBJECT_SIGNAL_NEW(signal_id, name, itype));
    }
  node->destroyed = FALSE;
  node->test_class_offset = 0;

4. 查询SignalNode时,直接访问指针数组:

static inline SignalNode*
LOOKUP_SIGNAL_NODE (register guint signal_id)
{
  if (signal_id < g_n_signal_nodes)
    return g_signal_nodes[signal_id];
  else
    return NULL;
}

 

Signal的二分查找数组:

上面定义的数组g_signal_nodes[signal_id]; 在知道signal_id已知的情况下,可以直接访问数组,提取SignalNode*,

但是,很多情况下,我们不知道signal_id, 而知道signal_name.

如果通过signal_name如何查询与之对应的signal id等信息呢?

 

1 在前面New Signal时,我们就看到:为了方便查询,留了后手:

      key.itype = itype;
      key.quark = g_quark_from_string (node->name);
      key.signal_id = signal_id;
      g_signal_key_bsa = g_bsearch_array_insert (g_signal_key_bsa, &g_signal_key_bconfig, &key);

      g_strdelimit (name, "_", '-');
      node->name = g_intern_string (name);
      key.quark = g_quark_from_string (name);
      g_signal_key_bsa = g_bsearch_array_insert (g_signal_key_bsa, &g_signal_key_bconfig, &key);

把SignalNode的3个信息:

Node type, node name(-->quark), node signal id, 三位一体的几个简单信息,保存在SignalKey结构变量中,

然后放到一个数组中g_signal_key_bsa;

GBSearchArray是glib提供的一个二分查找数组,可以更快的使用“name"等查到与之对应的signal id.

 

常用的函数:

2 根据quark/type来查找:

/* --- functions --- */
static inline guint
signal_id_lookup (GQuark quark,
		  GType  itype)
{
  GType *ifaces, type = itype;
  SignalKey key;
  guint n_ifaces;

  key.quark = quark;

  /* try looking up signals for this type and its ancestors */
  do
    {
      SignalKey *signal_key;
      
      key.itype = type;
      signal_key = g_bsearch_array_lookup (g_signal_key_bsa, &g_signal_key_bconfig, &key);
      
      if (signal_key)
	return signal_key->signal_id;
      
      type = g_type_parent (type);
    }
  while (type);

  /* no luck, try interfaces it exports */
  ifaces = g_type_interfaces (itype, &n_ifaces);
  while (n_ifaces--)
    {
      SignalKey *signal_key;

      key.itype = ifaces[n_ifaces];
      signal_key = g_bsearch_array_lookup (g_signal_key_bsa, &g_signal_key_bconfig, &key);

      if (signal_key)
	{
	  g_free (ifaces);
	  return signal_key->signal_id;
	}
    }
  g_free (ifaces);
  
  return 0;
}

3 再封装一次,提供给外界使用:

guint
g_signal_lookup (const gchar *name,
                 GType        itype)
{
  guint signal_id;
  g_return_val_if_fail (name != NULL, 0);
  g_return_val_if_fail (G_TYPE_IS_INSTANTIATABLE (itype) || G_TYPE_IS_INTERFACE (itype), 0);
  
  SIGNAL_LOCK ();
  signal_id = signal_id_lookup (g_quark_try_string (name), itype);
  SIGNAL_UNLOCK ();
  if (!signal_id)
    {
      /* give elaborate warnings */
      if (!g_type_name (itype))
	g_warning (G_STRLOC ": unable to lookup signal \"%s\" for invalid type id `%"G_GSIZE_FORMAT"'",
		   name, itype);
      else if (!G_TYPE_IS_INSTANTIATABLE (itype))
	g_warning (G_STRLOC ": unable to lookup signal \"%s\" for non instantiatable type `%s'",
		   name, g_type_name (itype));
      else if (!g_type_class_peek (itype))
	g_warning (G_STRLOC ": unable to lookup signal \"%s\" of unloaded type `%s'",
		   name, g_type_name (itype));
    }
  
  return signal_id;
}

 

4 第三方库使用:

如gst-inspect:

static void
print_signal_info (GstElement * element)
{
  /* Signals/Actions Block */
  guint *signals;
  guint nsignals;
  gint i = 0, j, k;
  GSignalQuery *query = NULL;
  GType type;
  GSList *found_signals, *l;

  for (k = 0; k < 2; k++) {
    found_signals = NULL;

    /* For elements that have sometimes pads, also list a few useful GstElement
     * signals. Put these first, so element-specific ones come later. */
    if (k == 0 && has_sometimes_template (element)) {
      query = g_new0 (GSignalQuery, 1);
      g_signal_query (g_signal_lookup ("pad-added", GST_TYPE_ELEMENT), query);
      found_signals = g_slist_append (found_signals, query);
      query = g_new0 (GSignalQuery, 1);
      g_signal_query (g_signal_lookup ("pad-removed", GST_TYPE_ELEMENT), query);
      found_signals = g_slist_append (found_signals, query);
      query = g_new0 (GSignalQuery, 1);
      g_signal_query (g_signal_lookup ("no-more-pads", GST_TYPE_ELEMENT),
          query);
      found_signals = g_slist_append (found_signals, query);
    }

 

handler的处理:

这里的处理有点意思,也不知道到底是否高效:

1). handler -->放入handler list, 这没有问题

2). hander list作为key 放入handler_list_bsa (二分查找数组),可以很快查询?

3). handler_list_bsa 有装入了Hash Table中:handler_list_bsa_ht

 

1. 看看New hander_list_bsa_ht

在g_signal_init()时,先创建一个hash tabe:

void
g_signal_init (void)
{
  SIGNAL_LOCK ();
  if (!g_n_signal_nodes)
    {
      /* setup handler list binary searchable array hash table (in german, that'd be one word ;) */
      g_handler_list_bsa_ht = g_hash_table_new (g_direct_hash, NULL);

这个hash table何时用?如何用?

 

2. New 一个Handler

static inline Handler*
handler_new (gboolean after)
{
  Handler *handler = g_slice_new (Handler);
#ifndef G_DISABLE_CHECKS
  if (g_handler_sequential_number < 1)
    g_error (G_STRLOC ": handler id overflow, %s", REPORT_BUG);
#endif
  
  handler->sequential_number = g_handler_sequential_number++;
  handler->prev = NULL;
  handler->next = NULL;
  handler->detail = 0;
  handler->ref_count = 1;
  handler->block_count = 0;
  handler->after = after != FALSE;
  handler->closure = NULL;
  
  return handler;
}

 

3. New 的Handler一般会放到Handler list中 (各种插入)

static void
handler_insert (guint    signal_id,
		gpointer instance,
		Handler  *handler)
{
  HandlerList *hlist;
  
  g_assert (handler->prev == NULL && handler->next == NULL); /* paranoid */
  
  hlist = handler_list_ensure (signal_id, instance);
  if (!hlist->handlers)
    {
      hlist->handlers = handler;
      if (!handler->after)
        hlist->tail_before = handler;
    }
  else if (handler->after)
    {
      handler->prev = hlist->tail_after;
      hlist->tail_after->next = handler;
    }
  else
    {
      if (hlist->tail_before)
        {
          handler->next = hlist->tail_before->next;
          if (handler->next)
            handler->next->prev = handler;
          handler->prev = hlist->tail_before;
          hlist->tail_before->next = handler;
        }
      else /* insert !after handler into a list of only after handlers */
        {
          handler->next = hlist->handlers;
          if (handler->next)
            handler->next->prev = handler;
          hlist->handlers = handler;
        }
      hlist->tail_before = handler;
    }

  if (!handler->next)
    hlist->tail_after = handler;
}

这里就有一个重要的函数:handler_list_ensure

它做如下动作:

1)首先查询一下hash table: handler_list_bsa_ht, 里面有没有instance匹配的handler_list_bsa,

if 没有

    (1)则创建一个handler_list_bsa二分查找数组,并且把handler list的signal_id作为关键Key,

    (2) 把handler list放入到这个二分数组中;

     (3)然后把这个二分数组handler_list_bsa, 插入到hash table中,此时instance作为key

else 已经存在和instance对应的handler_list_bsa二分数组

      (1) 把handler list直接插入到二分数组中

     (2)二分数组,可能在插入到hash table中

具体参考代码:

static inline HandlerList*
handler_list_ensure (guint    signal_id,
		     gpointer instance)
{
  GBSearchArray *hlbsa = g_hash_table_lookup (g_handler_list_bsa_ht, instance);
  HandlerList key;
  
  key.signal_id = signal_id;
  key.handlers    = NULL;
  key.tail_before = NULL;
  key.tail_after  = NULL;
  if (!hlbsa)
    {
      hlbsa = g_bsearch_array_create (&g_signal_hlbsa_bconfig);
      hlbsa = g_bsearch_array_insert (hlbsa, &g_signal_hlbsa_bconfig, &key);
      g_hash_table_insert (g_handler_list_bsa_ht, instance, hlbsa);
    }
  else
    {
      GBSearchArray *o = hlbsa;

      hlbsa = g_bsearch_array_insert (o, &g_signal_hlbsa_bconfig, &key);
      if (hlbsa != o)
	g_hash_table_insert (g_handler_list_bsa_ht, instance, hlbsa);
    }
  return g_bsearch_array_lookup (hlbsa, &g_signal_hlbsa_bconfig, &key);
}

上面函数执行的是各种插入操作。

4 下面看看查询过程:

1)用instanc作为key, 在hash table中,找到handler_list_bsa数组

2)从binary searchable array中提取handler list

3) 遍历list, 找到与handler_id对应的handler

static inline HandlerList*
handler_list_lookup (guint    signal_id,
		     gpointer instance)
{
  GBSearchArray *hlbsa = g_hash_table_lookup (g_handler_list_bsa_ht, instance);
  HandlerList key;
  
  key.signal_id = signal_id;
  
  return hlbsa ? g_bsearch_array_lookup (hlbsa, &g_signal_hlbsa_bconfig, &key) : NULL;
}

static Handler*
handler_lookup (gpointer instance,
		gulong   handler_id,
		guint   *signal_id_p)
{
  GBSearchArray *hlbsa = g_hash_table_lookup (g_handler_list_bsa_ht, instance);
  
  if (hlbsa)
    {
      guint i;
      
      for (i = 0; i < hlbsa->n_nodes; i++)
        {
          HandlerList *hlist = g_bsearch_array_get_nth (hlbsa, &g_signal_hlbsa_bconfig, i);
          Handler *handler;
          
          for (handler = hlist->handlers; handler; handler = handler->next)
            if (handler->sequential_number == handler_id)
              {
                if (signal_id_p)
                  *signal_id_p = hlist->signal_id;
		
                return handler;
              }
        }
    }
  
  return NULL;
}

 

5 handler_new和外界的接口:

一般在外面调用g_signal_connect_xxx()是调用:

比如:

gulong
g_signal_connect_data (gpointer       instance,
		       const gchar   *detailed_signal,
		       GCallback      c_handler,
		       gpointer       data,
		       GClosureNotify destroy_data,
		       GConnectFlags  connect_flags)
gulong
g_signal_connect_closure (gpointer     instance,
			  const gchar *detailed_signal,
			  GClosure    *closure,
			  gboolean     after) 
gulong
g_signal_connect_closure_by_id (gpointer  instance,
				guint     signal_id,
				GQuark    detail,
				GClosure *closure,
				gboolean  after)

就是说,当Caller用上面3个函数时,就会给当前的instance/signal_id,

1. 注册好callback

2. 绑定closure

3. 生成handler (handler 绑定callback/closure)

4. 放入handler list

5. 放入handler list的二分查找array中

6. 插入到全局的hash table中。

 

之后的查询函数:

handler_lookup/handler_list_lookup/handlers_find, 从会根据instance/signal_id,来找到与之对应的handlers

 

信号的发射:

1. 先定义:这其实是个链表,为啥定义2个链表呢?

static Emission      *g_recursive_emissions = NULL;
static Emission      *g_restart_emissions = NULL;

2. 再定义3个内联函数:

把临时emission, 放入全局的list中:push

查找:find

弹出临时emission: pop

static inline void		emission_push		(Emission	**emission_list_p,
							 Emission	 *emission);
static inline void		emission_pop		(Emission	**emission_list_p,
							 Emission	 *emission);
static inline Emission*		emission_find		(Emission	 *emission_list,
							 guint		  signal_id,
							 GQuark		  detail,
							 gpointer	  instance);

 

gobjec相关学习文章的list.

 

 

 

 

 

 

 

 

 

 

 

 

 

 

GObject Reference Manual

gobjec相关学习文章的list.

 

Read the document and source code.

https://developer.gnome.org/gobject/unstable/

 

Introduction
I. Concepts
Background
Data types and programming
Exporting a C API
The GLib Dynamic Type System
Copy functions
Conventions
Non-instantiable non-classed fundamental types
Instantiable classed types: objects
Initialization and Destruction
Non-instantiable classed types: interfaces
Interface Initialization
Interface Destruction
The GObject base class
Object instantiation
Object memory management
Reference count
Weak References
Reference counts and cycles
Object properties
Accessing multiple properties at once
The GObject messaging system
Closures
C Closures
Non-C closures (for the fearless)
Signals
Signal registration
Signal connection
Signal emission
Thedetail argument
II. API Reference
Type Information — The GLib Runtime type identification and management system
GTypePlugin — An interface for dynamically loadable types
GTypeModule — Type loading modules
GObject — The base object type
Enumeration and Flag Types — Enumeration and flags types
Boxed Types — A mechanism to wrap opaque C structures registered by the type system
Generic values — A polymorphic type that can hold values of any other type
Parameters and Values — Standard Parameter and Value Types
GParamSpec — Metadata for parameter specifications
Varargs Value Collection — Converting varargs to generic values
Signals — A means for customization of object behaviour and a general purpose notification mechanism
Closures — Functions as first-class objects
Value arrays — A container structure to maintain an array of generic values
GBinding — Bind two object properties
III. Tools Reference
glib-mkenums — C language enum description generation utility
glib-genmarshal — C code marshaller generation utility for GLib closures
gobject-query — display a tree of types
IV. Tutorial
How to define and implement a new GObject
Boilerplate header code
Boilerplate code
Object Construction
Object Destruction
Object methods
Non-virtual public methods
Virtual public methods
Virtual private Methods
Chaining up
How to define and implement interfaces
Defining interfaces
Implementing interfaces
Interface definition prerequisites
Interface properties
Overriding interface methods
How to create and use signals
Simple use of signals
V. Related Tools
Vala
GObject builder
Graphical inspection of GObjects
Debugging reference count problems
Writing API docs
Index
Index of deprecated symbols
Index of new symbols in 2.2
Index of new symbols in 2.4
Index of new symbols in 2.6
Index of new symbols in 2.8
Index of new symbols in 2.10
Index of new symbols in 2.12
Index of new symbols in 2.14
Index of new symbols in 2.18
Index of new symbols in 2.22
Index of new symbols in 2.24
Index of new symbols in 2.26
Index of new symbols in 2.28
Index of new symbols in 2.30
Index of new symbols in 2.32
Index of new symbols in 2.34
Index of new symbols in 2.36
Annotation Glossary

gst init.

Gstreamer学习list.

 

gobject.c中:

static GType gst_signal_object_get_type (void);

其实还有一个宏:

G_DEFINE_ABSTRACT_TYPE (GstObject,gst_object, G_TYPE_OBJECT);

这个宏定义:gtype.h

#define G_DEFINE_ABSTRACT_TYPE(TN, t_n, T_P) G_DEFINE_TYPE_EXTENDED (TN, t_n, T_P, G_TYPE_FLAG_ABSTRACT, {})

#define G_DEFINE_TYPE_EXTENDED(TN, t_n, T_P, _f_, _C_) _G_DEFINE_TYPE_EXTENDED_BEGIN (TN, t_n, T_P, _f_) {_C_;} _G_DEFINE_TYPE_EXTENDED_END()

把宏展开:

#define _G_DEFINE_TYPE_EXTENDED_BEGIN(GstObject, gst_object, G_TYPE_OBJECT, flags) \

\

static void gst_object_init (GstObject *self); \

static void gst_object_class_init (GstObjectClass *klass); \

static gpointer gst_object _parent_class = NULL; \

static void gst_object_class_intern_init (gpointer klass) \

{ \

gst_object_parent_class = g_type_class_peek_parent (klass); \

gst_object_class_init ((GstObject Class*) klass); \

} \

\

GType \

gst_object_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 (G_TYPE_OBJECT, \

g_intern_static_string (“GstObject”), \

sizeof (GstObjectClass), \

(GClassInitFunc)gst_object_class_intern_init, \

sizeof (GstObject), \

(GInstanceInitFunc)gst_object_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 gst_object_get_type() */

Gst.c中:

static gboolean

init_post (GOptionContext * context, GOptionGroup * group, gpointer data,

GError ** error)

{

//….

g_type_class_ref (gst_object_get_type ()); //这个是非常重要的,里面执行和很多的东西

这个函数会调用前面定义的函数。

gst_object_get_type()会首先调用:

GType

g_type_register_static_simple (GType parent_type,

const gchar *type_name,

guint class_size,

GClassInitFunc class_init,

guint instance_size,

GInstanceInitFunc instance_init,

GTypeFlags flags)

{

GTypeInfo info;

 

/* Instances are not allowed to be larger than this. If you have a big

* fixed-length array or something, point to it instead.

*/

g_return_val_if_fail (class_size <= G_MAXUINT16, G_TYPE_INVALID);

g_return_val_if_fail (instance_size <= G_MAXUINT16, G_TYPE_INVALID);

 

info.class_size = class_size;

info.base_init = NULL;

info.base_finalize = NULL;

info.class_init = class_init;

info.class_finalize = NULL;

info.class_data = NULL;

info.instance_size = instance_size;

info.n_preallocs = 0;

info.instance_init = instance_init;

info.value_table = NULL;

 

return g_type_register_static (parent_type, type_name, &info, flags);

}

 

//给新类型,分配一块内存;

//和父亲建立联系;

//把定义的新类型的类函数/实例化函数,等都复制过去

GType

g_type_register_static (GType parent_type,

const gchar *type_name,

const GTypeInfo *info,

GTypeFlags flags)

{

TypeNode *pnode, *node;

GType type = 0;

 

g_return_val_if_type_system_uninitialized (0);

g_return_val_if_fail (parent_type > 0, 0);

g_return_val_if_fail (type_name != NULL, 0);

g_return_val_if_fail (info != NULL, 0);

 

if (!check_type_name_I (type_name) ||

!check_derivation_I (parent_type, type_name))

return 0;

if (info->class_finalize)

{

g_warning ("class finalizer specified for static type `%s'",

type_name);

return 0;

}

 

pnode = lookup_type_node_I (parent_type);

G_WRITE_LOCK (&type_rw_lock);

type_data_ref_Wm (pnode);

if (check_type_info_I (pnode, NODE_FUNDAMENTAL_TYPE (pnode), type_name, info))

{

node = type_node_new_W (pnode, type_name, NULL);

type_add_flags_W (node, flags);

type = NODE_TYPE (node);

type_data_make_W (node, info,

check_value_table_I (type_name, info->value_table) ? info->value_table : NULL);

}

G_WRITE_UNLOCK (&type_rw_lock);

 

return type;

}

所以gst_object_get_type(),就是获取一个新类型,并且把定义的一些函数指针赋值过去。

下面看另外一个重要的函数:

g_type_class_ref

gpointer

g_type_class_ref (GType type)

{

TypeNode *node;

GType ptype;

gboolean holds_ref;

GTypeClass *pclass;

 

/* optimize for common code path */

node = lookup_type_node_I (type);

if (!node || !node->is_classed)

{

g_warning ("cannot retrieve class for invalid (unclassed) type `%s'",

type_descriptive_name_I (type));

return NULL;

}

 

if (G_LIKELY (type_data_ref_U (node)))

{

if (G_LIKELY (g_atomic_int_get (&node->data->class.init_state) == INITIALIZED))

return node->data->class.class;

holds_ref = TRUE;

}

else

holds_ref = FALSE;

 

/* 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.

*/

g_rec_mutex_lock (&class_init_rec_mutex); /* required locking order: 1) class_init_rec_mutex, 2) type_rw_lock */

 

/* we need an initialized parent class for initializing derived classes */

ptype = NODE_PARENT_TYPE (node);

pclass = ptype ? g_type_class_ref (ptype) : NULL;//如果父亲的类没有初始化,先递归处理父亲,祖父等的事情

 

G_WRITE_LOCK (&type_rw_lock);

 

if (!holds_ref)

type_data_ref_Wm (node);

 

if (!node->data->class.class) /* class uninitialized */

type_class_init_Wm (node, pclass);//这个地方会调用gst_object_class_init,包括可能递归调用父类的类初始化函数

 

G_WRITE_UNLOCK (&type_rw_lock);

 

if (pclass)

g_type_class_unref (pclass);

 

g_rec_mutex_unlock (&class_init_rec_mutex);

 

return node->data->class.class;

}

 

gstreamer的参考资料。

Gstreamer学习list.

 

Documentation

General

 

document HEAD
Application Development Manual (Read this first) HTML PostScript PDF
Frequently Asked Questions HTML PostScript PDF
Plugin Writer's Guide HTML PostScript PDF
Core Reference HTML
Core Libraries Reference HTML
Core Design Documentation HTML
GStreamer 0.10 to 1.0 porting guide HTML
GStreamer Wiki (see esp. ReleasePlanning and SubmittingPatches) HTML

GStreamer Plugins-Base Module Libraries Reference

 

document HEAD
GStreamer Base Plugins Libraries Reference HTML

Plugin Modules

 

document HEAD
Overview of all Plug-ins HTML
GStreamer Core Plugins Reference HTML
GStreamer Base Plugins Reference HTML
GStreamer Good Plugins Reference HTML
GStreamer Ugly Plugins Reference HTML
GStreamer Bad Plugins Reference HTML
GStreamer OpenGL Plugins Reference HTML
GStreamer Non-Linear Multimedia Editing Plugins Reference HTML

Other modules

 

document HEAD
GStreamer Editing Services Reference HTML
GStreamer RTSP Server Reference HTML
QtGStreamer Reference HTML

 

 

 

1. Gstreamer的中文开发手册

http://wenku.baidu.com/view/41194b35eefdc8d376ee3239.html

 

2. Gstreamer的插件开发手册

http://wenku.baidu.com/view/ffbcc6116c175f0e7cd13734.html

 

3. Gstreamer 编译、安装、测试

http://www.360doc.com/content/12/0416/13/474846_204097848.shtml

http://www.360doc.com/content/12/0416/13/474846_204096042.shtml

http://www.360doc.com/content/12/0416/13/474846_204099329.shtml

http://www.360doc.com/content/12/0428/16/474846_207310882.shtml

 

4. Gstreamer工作原理分析

http://wenku.baidu.com/view/e8565d76a417866fb84a8e7b.html

 

5. Gstreamer Core的理解

http://wenku.baidu.com/view/464fc6728e9951e79b892745.html

 

6. Gstreamer plugin 分析

http://blog.csdn.net/acs713/article/details/7708503

 

7. Gstreamer的一个练习

http://wiki.oz9aec.net/index.php/Gstreamer_cheat_sheet#Video_Wall:_Live_from_Pluto

 

 

图文详解YUV422格式

http://zhongcong386.blog.163.com/blog/static/1347278042013526104349588/?latestBlog

glib data structure.

 

1. Glib Array (可变长的数组)

可以存放任意类型的元素,并且大小随着元素的增加可以自动增长。

glib库数组GArray介绍

glib库中的数组GArray类型很像C++标准容器库中的vector容器。要使用glib库中的数组中需要声明一个指向GArray类型的指针。  

struct _GArray
{
  gchar *data;
  guint len;
};

struct _GByteArray
{
  guint8 *data;
  guint	  len;
};

struct _GPtrArray
{
  gpointer *pdata;
  guint	    len;
};

2. Glib SList/SList (单项列表/双向列表)

glib库单向链表GSList介绍

typedef struct _GSList GSList;

struct _GSList
{
  gpointer data;
  GSList *next;
};

 

 

glib库双向链表GList介绍

双向链表与单向链表的区别是,从一个节点,不仅能访问到它的下一个节点,还能访问到它的上一个节点,其定义如下:

typedef struct _GList GList;

struct _GList
{
  gpointer data;
  GList *next;
  GList *prev;
};

 

 

继续阅读

Glib参考资料。

1. GLib Reference Manual

http://developer.gimp.org/api/2.0/glib/index.html (完整的)

https://developer.gnome.org/glib/stable/

 

2. glib

http://wenku.baidu.com/view/c72d83222f60ddccda38a07b.html

 

3. 使GlibC (使用数据结构)

http://wenku.baidu.com/view/29d6911ffc4ffe473368abb8.html

 

4. Glib

http://wenku.baidu.com/view/28dd2e0590c69ec3d5bb7564.html?pn=51

 

glib/gobject的一个网友的:

http://socol.iteye.com/category/86299

 

glib中用的非常多的:

指针,指针数组,数组指针,函数指针,指针函数:

http://see.xidian.edu.cn/cpp/u/cjinjie4/

type.h

gobjec相关学习文章的list.

Read the source code!

看再多的文档,最后都要回归到code上面来。

Gtype.h:

/* Basic Type Macros

 */

#define G_TYPE_FUNDAMENTAL(type)                (g_type_fundamental (type))

#define                G_TYPE_FUNDAMENTAL_MAX                 (255 << G_TYPE_FUNDAMENTAL_SHIFT) //1020

#define G_TYPE_INVALID                                            G_TYPE_MAKE_FUNDAMENTAL (0) //0

#define G_TYPE_NONE                                                G_TYPE_MAKE_FUNDAMENTAL (1)   //4

#define G_TYPE_INTERFACE                      G_TYPE_MAKE_FUNDAMENTAL (2)   //8

#define G_TYPE_CHAR                                 G_TYPE_MAKE_FUNDAMENTAL (3)   //12

#define G_TYPE_UCHAR                                              G_TYPE_MAKE_FUNDAMENTAL (4) //16

#define G_TYPE_BOOLEAN                                         G_TYPE_MAKE_FUNDAMENTAL (5) //20

#define G_TYPE_INT                                      G_TYPE_MAKE_FUNDAMENTAL (6)  //24

#define G_TYPE_UINT                                  G_TYPE_MAKE_FUNDAMENTAL (7)

#define G_TYPE_LONG                                 G_TYPE_MAKE_FUNDAMENTAL (8)

#define G_TYPE_ULONG                                             G_TYPE_MAKE_FUNDAMENTAL (9)

#define G_TYPE_INT64                                 G_TYPE_MAKE_FUNDAMENTAL (10)

#define G_TYPE_UINT64                                              G_TYPE_MAKE_FUNDAMENTAL (11)

#define G_TYPE_ENUM                                               G_TYPE_MAKE_FUNDAMENTAL (12)

#define G_TYPE_FLAGS                                                G_TYPE_MAKE_FUNDAMENTAL (13)

#define G_TYPE_FLOAT                                                G_TYPE_MAKE_FUNDAMENTAL (14)

#define G_TYPE_DOUBLE                                            G_TYPE_MAKE_FUNDAMENTAL (15)

#define G_TYPE_STRING                                             G_TYPE_MAKE_FUNDAMENTAL (16)

#define G_TYPE_POINTER                                           G_TYPE_MAKE_FUNDAMENTAL (17)

#define G_TYPE_BOXED                                               G_TYPE_MAKE_FUNDAMENTAL (18)

#define G_TYPE_PARAM                                             G_TYPE_MAKE_FUNDAMENTAL (19)

#define G_TYPE_OBJECT                                              G_TYPE_MAKE_FUNDAMENTAL (20)

#define                G_TYPE_VARIANT                  G_TYPE_MAKE_FUNDAMENTAL (21) //84

有个疑问:为什么要shift移位?:

#define                G_TYPE_FUNDAMENTAL_SHIFT               (2)
  1. 定义Type ID时,左移;
  2. 保存指针到数组时,又右移,取得数组的index
  if (!pnode)					      /* offset fundamental types */
    {
      node = G_STRUCT_MEMBER_P (node, SIZEOF_FUNDAMENTAL_INFO);
      static_fundamental_type_nodes[ftype >> G_TYPE_FUNDAMENTAL_SHIFT] = node;
      type = ftype;
    }
  1. 在从数组中提取时,又右移
static inline TypeNode*
lookup_type_node_I (register GType utype)
{
  if (utype > G_TYPE_FUNDAMENTAL_MAX)
    return (TypeNode*) (utype & ~TYPE_ID_MASK);
  else
    return static_fundamental_type_nodes[utype >> G_TYPE_FUNDAMENTAL_SHIFT];
}

这种左移,右移的移位操作,本身效率是高,但是为什么要这样做?

类函数何时用?

 

GType boilerplate:

模板文件,这些宏,在后面用户自定义GObject时非常有用,

要理解他们,用好他们;

 

Gtype.c:

/* --- structures --- */

struct _TypeNode

{

  guint volatile ref_count;

  GTypePlugin *plugin;

  guint        n_children; /* writable with lock */  //子辈的个数

  guint        n_supers : 8; //父辈的个数

  guint        n_prerequisites : 9;

  guint        is_classed : 1;

  guint        is_instantiatable : 1;

  guint        mutatable_check_cache : 1;   /* combines some common path checks */

GType       *children; /* writable with lock */ //指针数组,用来保持孩子的信息:pnode->children[i] = type; pnode->children = g_renew (GType, pnode->children, pnode->n_children);


  TypeData * volatile data;

  GQuark       qname;

  GData       *global_gdata;

  union {

    GAtomicArray iface_entries;                  /* for !iface types */

    GAtomicArray offsets;

  } _prot;

  GType       *prerequisites;

  GType        supers[1]; /* flexible array */ //直接用memory copy进行增长

};



#define NODE_TYPE(node)                                                         (node->supers[0]) //自己

#define NODE_PARENT_TYPE(node)                                      (node->supers[1]) //父亲

#define NODE_FUNDAMENTAL_TYPE(node)                      (node->supers[node->n_supers]) //最顶层的父亲,就是基本类型


/* --- type nodes --- */

static GHashTable       *static_type_nodes_ht = NULL;

static TypeNode                               *static_fundamental_type_nodes[(G_TYPE_FUNDAMENTAL_MAX >> G_TYPE_FUNDAMENTAL_SHIFT) + 1] = { NULL, }; //全局的指针数组,用来保存基本类型,256个

static GType                       static_fundamental_next = G_TYPE_RESERVED_USER_FIRST;


?为什么需要一个hash table和一个全局的指针数组来保存Node节点呢?

数组查找快?

下面这个函数,同时操作上面的hash table和全局数组static_fundamental_type_nodes[]


static TypeNode*

type_node_any_new_W (TypeNode             *pnode,

                                     GType                 ftype,

                                     const gchar          *name,

                                     GTypePlugin          *plugin,

                                     GTypeFundamentalFlags type_flags)

{

  guint n_supers;

  GType type;

  TypeNode *node;

  guint i, node_size = 0;


  n_supers = pnode ? pnode->n_supers + 1 : 0; //如果有父类,则父类加1,否则父类为0


  //如果没有父类,则按照基础类型大小

  if (!pnode)

node_size += SIZEOF_FUNDAMENTAL_INFO;                      /* fundamental type info */


  node_size += SIZEOF_BASE_TYPE_NODE ();            /* TypeNode structure */

node_size += (sizeof (GType) * (1 + n_supers + 1)); /* self + ancestors + (0) for ->supers[] */


//给新节点分配内存

node = g_malloc0 (node_size);


//如果没有父节点,则直接保存在基础类型static_fundamental_type_nodes数组中

  if (!pnode)                                                                              /* offset fundamental types */

    {

      node = G_STRUCT_MEMBER_P (node, SIZEOF_FUNDAMENTAL_INFO);

      static_fundamental_type_nodes[ftype >> G_TYPE_FUNDAMENTAL_SHIFT] = node;

      type = ftype;

    }

  else

    type = (GType) node; //如果有父节点,则新分配的节点作为当前节点


  g_assert ((type & TYPE_ID_MASK) == 0);


  node->n_supers = n_supers; //记录有几个父节点

  if (!pnode)

    { //如果没有父节点

      node->supers[0] = type; //第一个节点就是,自己

      node->supers[1] = 0;

     

      node->is_classed = (type_flags & G_TYPE_FLAG_CLASSED) != 0;

      node->is_instantiatable = (type_flags & G_TYPE_FLAG_INSTANTIATABLE) != 0;

     

      if (NODE_IS_IFACE (node))

                {

          IFACE_NODE_N_PREREQUISITES (node) = 0;

                  IFACE_NODE_PREREQUISITES (node) = NULL;

                }

      else

                _g_atomic_array_init (CLASSED_NODE_IFACES_ENTRIES (node));

    }

  else

    { //如果有父节点

      node->supers[0] = type; //第一个节点就是自己


      //node->supers+1,指针后移动

     //把父节点的所有数据,都复制一份给当前节点,作为当前节点的父类信息

      memcpy (node->supers + 1, pnode->supers, sizeof (GType) * (1 + pnode->n_supers + 1));

     

      node->is_classed = pnode->is_classed;

      node->is_instantiatable = pnode->is_instantiatable;

     

      if (NODE_IS_IFACE (node))

                {

                  IFACE_NODE_N_PREREQUISITES (node) = 0;

                  IFACE_NODE_PREREQUISITES (node) = NULL;

                }

      else

                {

                  guint j;

                  IFaceEntries *entries;


                  entries = _g_atomic_array_copy (CLASSED_NODE_IFACES_ENTRIES (pnode),

                                                                                  IFACE_ENTRIES_HEADER_SIZE,

                                                                                  0);

                  if (entries)

                    {

                      for (j = 0; j < IFACE_ENTRIES_N_ENTRIES (entries); j++)

                                {

                                  entries->entry[j].vtable = NULL;

                                  entries->entry[j].init_state = UNINITIALIZED;

                                }

                      _g_atomic_array_update (CLASSED_NODE_IFACES_ENTRIES (node),

                                                                      entries);

                    }

                }

      //再和父类建立好关系

      i = pnode->n_children++;

      pnode->children = g_renew (GType, pnode->children, pnode->n_children);

      pnode->children[i] = type;

    }


  TRACE(GOBJECT_TYPE_NEW(name, node->supers[1], type));


  node->plugin = plugin;

  node->n_children = 0;

  node->children = NULL;

  node->data = NULL;

  node->qname = g_quark_from_string (name);

  node->global_gdata = NULL;


 //同时压入hash table中

  g_hash_table_insert (static_type_nodes_ht,

                                       GUINT_TO_POINTER (node->qname),

                                       (gpointer) type);

  return node;

}

上面提到的那个静态全局数组:TypeNode * static_fundamental_type_nodes[256];

TypeNode *

TypeNode *

TypeNode *

……

TypeNode *

保存的基础节点,即:没有父类的节点类型:同时,这些type也是可以做父亲的类型

|
`Void

|
`GInterface
|
`GTypePlugin
|
`gchar
|
`guchar
|
`gboolean
|
`gint
|
`guint
|
`glong
|
`gulong
|
`gint64
|
`guint64
|
`GEnum
|
`GFlags
|
`gfloat
|
`gdouble
|
`gchararray
|
`gpointer
|
`GType
|
`GBoxed
|
`GValueArray
|
`GParam
|
`GParamVariant
|
`GObject
|
`GVariant

下面是个内联函数,可以取代宏,有编译器直接展开,效率高;

同时,也可以检查参数的有效性;

static inline TypeNode*

lookup_type_node_I (register GType utype)

{

  if (utype > G_TYPE_FUNDAMENTAL_MAX)

    return (TypeNode*) (utype & ~TYPE_ID_MASK);

  else

    return static_fundamental_type_nodes[utype >> G_TYPE_FUNDAMENTAL_SHIFT];

}

数组的直接访问,效率是非常高的。

 

另外一个Hash Table:  GHashTable       *static_type_nodes_ht = NULL;

只有一个函数进行了调用:

GType

g_type_from_name (const gchar *name)

{

  GType type = 0;

  GQuark quark;


  g_return_val_if_fail (name != NULL, 0);


  quark = g_quark_try_string (name);

  if (quark)

    {

      G_READ_LOCK (&type_rw_lock);

      type = (GType) g_hash_table_lookup (static_type_nodes_ht, GUINT_TO_POINTER (quark));

      G_READ_UNLOCK (&type_rw_lock);

    }


  return type;

}

根据“名字”来查询,Hash Table的效率要高;

 

gobjec相关学习文章的list.

如何查看GType节点,以及父子关系。

gobjec相关学习文章的list.

 

使用glib的gtype/gobject开发的gtk, gstreamer等,都离不开一个gtype, gobject.

 

Glib使用2个数据结构来保存type:

//1,用指针数组,保存基础类型,即一些父类型

static TypeNode		*static_fundamental_type_nodes[(G_TYPE_FUNDAMENTAL_MAX >> G_TYPE_FUNDAMENTAL_SHIFT) + 1] = { NULL, };

//2, 用散列表来保持所有的类型,包括父类型,子类型

static GHashTable       *static_type_nodes_ht = NULL;
static_type_nodes_ht = g_hash_table_new (g_direct_hash, g_direct_equal);

它使用指针作为键值

 

type创建的过程:

 

  1. 定义xxx_yyy_get_type(), 一般是用宏来定义的
  2. Init时,会调用g_type_class_ref(xxx_yyy_get_type())

如:

g_type_class_ref (gst_object_get_type ());

g_type_class_ref (gst_pad_get_type ());

g_type_class_ref (gst_element_factory_get_type ());

g_type_class_ref (gst_element_get_type ());

  1. xxx_yyy_get_type()会进行type的创建,保存到指针数组和hash table中:
  2. g_type_register_static()
  3. type_node_any_new_W() 首先检查该新建的type,是否由父亲;

如果没有的话,保持在static_fundamental_type_nodes;

如果有父类的话,就保持到父类的子类数组中pnode->children[i] = type;

同时把这个新的type 插入到hash table中:

g_hash_table_insert (static_type_nodes_ht,

GUINT_TO_POINTER (node->qname),

(gpointer) type);

 

如果查看type的list, 以及父子关系呢:

参考gobject_query.c

主要是把父子关系清晰的打印出来:

指针数组static_fundamental_type_nodes,存放了无父类的typenode;

所以只要循环这个指针数组,然后对基础typenode, 嵌套循环其子类,就可以了。

/* GObject - GLib Type, Object, Parameter and Signal Library
 * Copyright (C) 1998-1999, 2000-2001 Tim Janik and Red Hat, Inc.
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General
 * Public License along with this library; if not, write to the
 * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
 * Boston, MA 02111-1307, USA.
 */


#include <stdlib.h>
#include <string.h>

#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#include <fcntl.h>

#include <glib-object.h>
#include <glib/gprintf.h>

static GType root = G_TYPE_OBJECT;

static void
show_nodes (GType        type,
	    GType        sibling,
	    const gchar *indent)
{
	static gchar *indent_inc = NULL;
	static guint spacing = 1;
	static gboolean recursion = TRUE;

#define	O_SPACE	" "
#define	O_ESPACE ""
#define	O_BRANCH "+"
#define	O_VLINE "|"
#define	O_LLEAF	"`"
#define	O_KEY_FILL "_"

	GType   *children;
	guint i;

	if (!type)
		return;

	if (!indent_inc)
	{
		indent_inc = g_new (gchar, strlen (O_SPACE) + 1);
		*indent_inc = 0;
		strcpy (indent_inc, O_SPACE);
	}  
  
	children = g_type_children (type, NULL);

	if (type != root)
		for (i = 0; i < spacing; i++)
			fprintf(stderr, "%s%s\n", indent, O_VLINE);
  
	fprintf(stderr, "%s%s%s%s",
				indent,
				sibling ? O_BRANCH : (type != root ? O_LLEAF : O_SPACE),
				O_ESPACE,
				g_type_name (type));

	for (i = strlen (g_type_name (type)); i <= strlen (indent_inc); i++)
		fputs (O_KEY_FILL, stdout);
	fputc ('\n', stdout);

	if (children && recursion)
	{
		gchar *new_indent;
		GType   *child;

		if (sibling)
			new_indent = g_strconcat (indent, O_VLINE, indent_inc, NULL);
		else
			new_indent = g_strconcat (indent, O_SPACE, indent_inc, NULL);

		for (child = children; *child; child++)
			show_nodes (child[0], child[1], new_indent);

		g_free (new_indent);
	}

	g_free (children);
}

void list_type_node_tree(void)
{
	gint i;
	
  	root = ~0;
	for (i = 0; i <= G_TYPE_FUNDAMENTAL_MAX; i += G_TYPE_MAKE_FUNDAMENTAL (1))
	{
		const gchar *name = g_type_name (i);

		if (name)
			show_nodes (i, 0, "");
	}

}

g_type_init()后的type list, 以及父子关系:


id

|

`GInterface

  |

  `GTypePlugin

|

`gchar

|

`guchar

|

`gboolean

|

`gint

|

`guint

|

`glong

|

`gulong

|

`gint64

|

`guint64

|

`GEnum

|

`GFlags

|

`gfloat

|

`gdouble

|

`gchararray

|

`gpointer

  |

  `GType

|

`GBoxed

  |

  `GValueArray

|

`GParam

  |

  +GParamChar

  |

  +GParamUChar

  |

  +GParamBoolean

  |

  +GParamInt

  |

  +GParamUInt

  |

  +GParamLong

  |

  +GParamULong

  |

  +GParamInt64

  |

  +GParamUInt64

  |

  +GParamUnichar

  |

  +GParamEnum

  |

  +GParamFlags

  |

  +GParamFloat

  |

  +GParamDouble

  |

  +GParamString

  |

  +GParamParam

  |

  +GParamBoxed

  |

  +GParamPointer

  |

  +GParamValueArray

  |

  +GParamObject

  |

  +GParamOverride

  |

  +GParamGType

  |

  `GParamVariant

|

`GObject

|

`GVariant

 

gst_init()后 type/gobject list, 以及object的父子关系:

|

`void

|

`GInterface

  |

  +GTypePlugin

  |

  +GstChildProxy

  |

  `GstURIHandler

|

`gchar

|

`guchar

|

`gboolean

|

`gint

|

`guint

|

`glong

|

`gulong

|

`gint64

|

`guint64

|

`GEnum

  |

  +GstFormat

  |

  +GstPadDirection

  |

  +GstBufferListItem

  |

  +GstBusSyncReply

  |

  +GstClockReturn

  |

  +GstClockEntryType

  |

  +GstClockType

  |

  +GstState

  |

  +GstStateChangeReturn

  |

  +GstStateChange

  |

  +GstCoreError

  |

  +GstLibraryError

  |

  +GstResourceError

  |

  +GstStreamError

  |

  +GstEventType

  |

  +GstSeekType

  |

  +GstQOSType

  |

  +GstIndexCertainty

  |

  +GstIndexEntryType

  |

  +GstIndexLookupMethod

  |

  +GstIndexResolverMethod

  |

  +GstDebugLevel

  |

  +GstDebugColorFlags

  |

  +GstIteratorResult

  |

  +GstIteratorItem

  |

  +GstPadLinkReturn

  |

  +GstFlowReturn

  |

  +GstActivateMode

  |

  +GstPadPresence

  |

  +GstPluginError

  |

  +GstRank

  |

  +GstQueryType

  |

  +GstBufferingMode

  |

  +GstStreamStatusType

  |

  +GstStructureChangeType

  |

  +GstTagMergeMode

  |

  +GstTagFlag

  |

  +GstTaskState

  |

  +GstTypeFindProbability

  |

  +GstURIType

  |

  +GstParseError

  |

  +GstSearchMode

  |

  +GstProgressType

  |

  `GstCapsIntersectMode

|

`GFlags

  |

  +GstObjectFlags

  |

  +GstBinFlags

  |

  +GstBufferFlag

  |

  +GstBufferCopyFlags

  |

  +GstBusFlags

  |

  +GstCapsFlags

  |

  +GstClockFlags

  |

  +GstDebugGraphDetails

  |

  +GstElementFlags

  |

  +GstEventTypeFlags

  |

  +GstSeekFlags

  |

  +GstAssocFlags

  |

  +GstIndexFlags

  |

  +GstMessageType

  |

  +GstMiniObjectFlags

  |

  +GstPadLinkCheck

  |

  +GstPadFlags

  |

  +GstPadTemplateFlags

  |

  +GstPipelineFlags

  |

  +GstPluginFlags

  |

  +GstPluginDependencyFlags

  |

  +GstAllocTraceFlags

  |

  `GstParseFlags

|

`gfloat

|

`gdouble

|

`gchararray

|

`gpointer

  |

  `GType

|

`GBoxed

  |

  +GValueArray

  |

  +GstCaps

  |

  +GstStructure

  |

  +GstDate

  |

  +GstDateTime

  |

  +GDate

  |

  +GstBufferListIterator

  |

  +GstParseContext

  |

  `GError

|

`GParam

  |

  +GParamChar

  |

  +GParamUChar

  |

  +GParamBoolean

  |

  +GParamInt

  |

  +GParamUInt

  |

  +GParamLong

  |

  +GParamULong

  |

  +GParamInt64

  |

  +GParamUInt64

  |

  +GParamUnichar

  |

  +GParamEnum

  |

  +GParamFlags

  |

  +GParamFloat

  |

  +GParamDouble

  |

  +GParamString

  |

  +GParamParam

  |

  +GParamBoxed

  |

  +GParamPointer

  |

  +GParamValueArray

  |

  +GParamObject

  |

  +GParamOverride

  |

  +GParamGType

  |

  +GParamVariant

  |

  `GstParamFraction

|

`GObject

  |

  +GstObject

  | |

  | +GstPad

  | |

  | +GstPadTemplate

  | |

  | +GstPluginFeature

  | | |

  | | +GstElementFactory

  | | |

  | | +GstTypeFindFactory

  | | |

  | | `GstIndexFactory

  | |

  | +GstElement

  | | |

  | | `GstBin

  | |   |

  | |   `GstPipeline

  | |

  | +GstBus

  | |

  | +GstTask

  | |

  | +GstTaskPool

  | |

  | +GstClock

  | |

  | +GstPlugin

  | |

  | `GstRegistry

  |

  `GstSignalObject

|

`GVariant

|

`GstMiniObject

  |

  +GstQuery

  |

  +GstMessage

  |

  +GstBuffer

  |

  +GstEvent

  |

  `GstBufferList

|

`GstFourcc

|

`GstIntRange

|

`GstInt64Range

|

`GstDoubleRange

|

`GstFractionRange

|

`GstValueList

|

`GstValueArray

|

`GstFraction

gobjec相关学习文章的list.

GObject-Glib Type, Object, Parameter and Signal

gobjec相关学习文章的list.

https://developer.gnome.org/gobject/stable/index.html

GObject的动态类型系统允许程序在运行时进行类型注册,它的最主要目的有两个:
1)使用面向对象的设计方法来编程。使用纯C语言设计出来的一整套面向对象的编程环境。
2)多语言交互。使Perl或者Python等解释型的脚本语言能使用GLIB提供的函数。这一目的是最主要的,所以,在学习GObject的设计时,需要牢记这一首要目标,这对理解GObject的一些奇怪的设计及特性是有较大帮助的。

Type

GValueType

(基本类型,以及操作API)

这里注册 基础类型:

1.gchar
2.guchar
3.gboolean
4.gint
5.guint
6.glong
7.gulong
8.gint64
9.guint64
10.gfloat
11.gdouble
12.gchararray
13.gpointer
14.gvariant

 

const GTypeFundamentalInfo finfo = { G_TYPE_FLAG_DERIVABLE, };

这些基础类型,是可以派生的;不可类化;不可实例化;不可深度派生

这些基础类型,可以放到下面的容器中:GValue中

并且对每种基本类型提供如下API集合:

struct _GTypeValueTable
{
  void     (*value_init)         (GValue       *value);
  void     (*value_free)         (GValue       *value);
  void     (*value_copy)         (const GValue *src_value,
				  GValue       *dest_value);
  /* varargs functionality (optional) */
  gpointer (*value_peek_pointer) (const GValue *value);
  gchar	    *collect_format;
  gchar*   (*collect_value)      (GValue       *value,
				  guint         n_collect_values,
				  GTypeCValue  *collect_values,
				  guint		collect_flags);
  gchar	    *lcopy_format;
  gchar*   (*lcopy_value)        (const GValue *value,
				  guint         n_collect_values,
				  GTypeCValue  *collect_values,
				  guint		collect_flags);
};

 

GValue  (泛型)

(基本类型的容器)

Generic values — A polymorphic(多态的) type that can hold values of any other type

在C语言里,通用类型我们一般是用void *以表示任何类型的数据。但GObject的设计初衷是为了解决多语言交互问题,所以必须设计出一套能容纳任何数据类型的通用数据类型。以便在不同的编程语言之间进行数据转换操作。这个数据类型就是GValue。

/**
 * GValue:
 * 
 * An opaque structure used to hold different types of values.
 * The data within the structure has protected scope: it is accessible only
 * to functions within a #GTypeValueTable structure, or implementations of
 * the g_value_*() API. That is, code portions which implement new fundamental
 * types.
 * #GValue users can not make any assumptions about how data is stored
 * within the 2 element @data union, and the @g_type member should
 * only be accessed through the G_VALUE_TYPE() macro.
 */
struct _GValue
{
  /*< private >*/
  GType		g_type;

  /* public for GTypeValueTable methods */
  union {
    gint	v_int;
    guint	v_uint;
    glong	v_long;
    gulong	v_ulong;
    gint64      v_int64;
    guint64     v_uint64;
    gfloat	v_float;
    gdouble	v_double;
    gpointer	v_pointer;
  } data[2];
};

还可以容纳用户自定义的类型;

GValueArray

(Value的容器)

上面的通用类型,还可以放到一个数组中进行有效的管理:GValueArray

它最主要的目的:是为了object property

Glib2.32以后,用GArray代替GValueArray了

GValueTransform

(Value的工具函数)

这个比较简单:不同类型之间的转换

GValueCollector

(Value的工具函数)

这个是把可变参数vararg à 一般的Value(gint, glong, gdouble, gpointer)

Gobject中,g_object_new()等函数可以使用可变参数,这个类型的API来提供这种转换功能。

 

 

GBoxed

对任意C结构的一个通用封装机制

这个box是不透明的,用户只要copy/free它即可。

很多类型,都被定义成了box类型:G_TYPE_BOX作为父类型

Boxed Type机制是用来包装(wrap)C语言结构体的一种机制。这里所谓的包装,其实就是在GType类型系统中注册该类型,并且该类型将成为GBoxed的子类。之后,这一类型就能够使用和GBoxed类型有关的所有函数了,如g_value_get_boxed等等。

 

下面这些类型会被注册为GBoxed的子类:

					
#define             G_TYPE_HASH_TABLE
#define             G_TYPE_DATE
#define             G_TYPE_GSTRING
#define             G_TYPE_STRV
#define             G_TYPE_REGEX
#define             G_TYPE_MATCH_INFO
#define             G_TYPE_ARRAY
#define             G_TYPE_BYTE_ARRAY
#define             G_TYPE_PTR_ARRAY
#define             G_TYPE_BYTES
#define             G_TYPE_VARIANT_TYPE
#define             G_TYPE_ERROR
#define             G_TYPE_DATE_TIME
#define             G_TYPE_TIME_ZONE
#define             G_TYPE_IO_CHANNEL
#define             G_TYPE_IO_CONDITION
#define             G_TYPE_VARIANT_BUILDER
#define             G_TYPE_KEY_FILE
#define             G_TYPE_MAIN_CONTEXT
#define             G_TYPE_MAIN_LOOP
#define             G_TYPE_MARKUP_PARSE_CONTEXT
#define             G_TYPE_SOURCE
#define             G_TYPE_POLLFD
#define             G_TYPE_THREAD
typedef             GStrv;

					
何时注册?

 

GBoxed的理解,参考:

http://nanjingabcdefg.is-programmer.com/posts/24152.html

 

 

GEnumValue,GFlagValue

注册2个基础类型:

  1. GEnum
  2. GFlags

Flag和Enum比较类似,Flag可以与bitwise进行位操作

  static const GTypeFundamentalInfo finfo = {

    G_TYPE_FLAG_CLASSED | G_TYPE_FLAG_DERIVABLE,

}; 可派生,可类化;不可深度派生;不可实例化

?为什么要能类化?

GObject的Property会大量用到GEnumValue, GFlagValue, 主要是派生很多;

GParam

(属性)

GObject中Property会用name/value对,来表示某某property;

标准的属性名字和它的值:

/**
 * GParameter:
 * @name: the parameter name
 * @value: the parameter value
 * 
 * The <structname>GParameter</structname> struct is an auxiliary structure used
 * to hand parameter name/value pairs to g_object_newv().
 */
struct _GParameter /* auxillary structure for _setv() variants */
{
  const gchar *name;
  GValue       value;
};

g_param_type_register_static()注册1个基础类型:

GParamSpec

(属性规格)

GParamSpec is an object structure that encapsulates the metadata required to specify parameters, such as e.g. GObject properties.

(主要用于GObject的Properties的元数据的封装)

上面提过属性规格,在Glib中被称作!GParamSpec,它保存了对象的gtype,对象的属性名称,属性枚举ID,属性默认值,边界值等,类型系统用!GParamSpec来将属性的字符串名转换为枚举的属性ID,GParamSpec也是一个能把所有东西都粘在一起的大胶水。
  当咱们须要配置或者获取一个属性的值时,传入属性的名字,并且带上GValue用来保存咱们要配置的值,调用g_object_set/get_property。g_object_set_property函数将在GParamSpec中查找咱们要配置的属性名称,查找咱们对象的类,并且调用对象的set_property要领。这意味着假如咱们要添加一个新的属性,就必须要覆盖默认的set/get_property要领。并且基类包含的属性将被它自身的set/get_property要领所正常处理,因为!GParamSpec就是从基类传递下来的。结尾,应该记得,咱们必须事先议决对象的class_init要领来传入GParamSpec参数,用于安装上属性!

对于这些基本类型,都会提供Gvalue的copied, transformed and compared函数;

用一个全局的数组:

/* --- type initialization --- */
GType *g_param_spec_types = NULL;

来保持这些属性

`GParam (派生22个属性类型)

  |

  +GParamChar  //Char型属性

  |

  +GParamUChar //UChar型属性

  |

  +GParamBoolean

  |

  +GParamInt

  |

  +GParamUInt

  |

  +GParamLong

  |

  +GParamULong

  |

  +GParamInt64

  |

  +GParamUInt64

  |

  +GParamUnichar

  |

  +GParamEnum

  |

  +GParamFlags

  |

  +GParamFloat

  |

  +GParamDouble

  |

  +GParamString

  |

  +GParamParam

  |

  +GParamBoxed

  |

  +GParamPointer

  |

  +GParamValueArray

  |

  +GParamObject

  |

  +GParamOverride

  |

  +GParamGType

  |

  `GParamVariant

每个类型都注册了一组基本的GValue的函数表;

如何来用他们?

GMarshal

列集(Marshaling)是将数据从某种格式存为流格式的操作;

散集(Unmarshaling)则是列集的反操作,将信息从流格式中还原出来。

列集的概念:

http://baike.baidu.com/view/10283079.htm

http://wenku.baidu.com/view/48d00321dd36a32d73758175.html

 

先看这个:

https://developer.gnome.org/gobject/stable/gobject-Closures.html

glib有一些标准的列集函数,在gmarshal.h中定义。例如g_cclosure_marshal_VOID__STRING,

这个函数适合只有一个字符串参数的信号。如果gmarshal.h没有提供适合的列集函数,我们可以用一个叫

glib-genmarshal的工具自动生成列集函数。

 

后面我们会看到,无论是标准列集函数还是生成的列集函数都是既可以用于列集也可以用于散集,这些函数通常都被称作列集函数。

在COM中,Marshalling的作用是对象之间传递数据时:对数据打包和解包。

Marshalling在很多地方都可以用:

  1. 线程之间数据传递时:需要Marshalling 对参数进行转换
  2. 进程之间 (如:dbus的server/client)
  3. 不同语言之间 (如:glib 和Native的C)

信号的列集函数:

http://wenku.baidu.com/view/1e1ae6dfad51f01dc281f186.html

GCClosure

Marshal/closure的关系比较紧密。

https://developer.gnome.org/gobject/stable/gobject-Closures.html

要理解透彻,否则对于很多东西还是一知半解。

GClosure(闭包):表示程序员提供的回调。

GClosure组成:Callback + Marshaller

GClosure的作用:

  1. 调用时,把参数(GValue形式)—> 合适的形式
  2. 调用callback(使用转换过的参数)
  3. 把返回值再à GValue形式

GClosure的一个重要作用是实现Signal机制。

GClosure的好处:不仅仅是callback/data

  1. 允许被调用者(callee)获取callback参数,在多语言绑定时,不用手写glue函数
  2.   blabla
  3.   blabla

 

具体过程:

假设:

Caller: C程序员

Callee: Glib/GObject

 

Step 1: C 程序员定义callback

Step 2: C 程序员提供自己marshal, 或者直接使用glib提供的

Step 3: 定义GCClosure, 并且把callback, marshal注册上去

Step 4: g_closure_invoke()实现 closure的作用(3个)

 

函数指针、回调函数与 GObject 闭包 (写的非常好)

http://garfileo.is-programmer.com/2011/3/20/function-pointer-and-callback-function-and-closure.25453.html

GSignal

在gobject系统中, 信号是一种定制对象行为的手段, 也是一种多种用途的通知机制. 每一个信号都是和能发出信号的类型一起注册到系统中的.
使用 GObject信号机制,一般有三个步骤:

  1. 信号注册, 主要解决信号与数据类型的关联问题
  2. 信号连接, 主要处理信号与闭包的连接问题
  3. 信号发射, 调用callback进行处理

GObject 的信号机制——概览:

http://garfileo.is-programmer.com/2011/3/21/gobject-signal.25477.html

对g_signal_new()参数的解释:

http://nanjingabcdefg.is-programmer.com/posts/24116.html

GObject 信号机制——信号 Accumulator:

http://garfileo.is-programmer.com/2011/3/27/gobject-signal-extra-2.25621.html

GObject

 

 

GPlugin

 

参考:

GObject 学习笔记汇总

http://garfileo.is-programmer.com/categories/6934/posts

快速上手GObject:

http://blog.csdn.net/acs713/article/details/7778051

 

gobjec相关学习文章的list.