|
数据定义 |
说明 |
gtype |
一个全局指针数组, 用来保存基本类型; 通过基本类型顺藤摸瓜,可以找到其子类型 |
|
static GHashTable *static_type_nodes_ht = NULL; |
一个全局的Hash Table 这个Hash Table一般是通过“名字”来查询TypeNode时使用 |
|
|
|
|
Signal |
双指针 == 指针数组? |
|
static GBSearchArray *g_signal_key_bsa = NULL; | 方便根据signal name/type来查询signal_id | |
|
信号处理函数用hash table |
|
|
|
|
|
static Emission *g_restart_emissions = NULL; |
|
|
||
object |
这个和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 |
用Hash Table来保存Object的ParamSpec |
|
|
/* --- type initialization --- */ |
一个全局数组 |
1. 定义:
1 2 3 4 5 | //这个用处比较少,只是用“名字”来查询时用 static GHashTable *static_type_nodes_ht = NULL; //这个用的比较多,访问数组查询效率高 static TypeNode *static_fundamental_type_nodes[(G_TYPE_FUNDAMENTAL_MAX >> G_TYPE_FUNDAMENTAL_SHIFT) + 1] = { NULL, }; |
2. 初始化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | 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中。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 | 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,直接访问数组
1 2 3 4 5 6 7 8 | 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比较快:
这个函数目前看,使用还不是很多。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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; } |
1. 定义一个全局指针g_param_spec_types,引用时也可以用数组的方式进行:
1 2 | /* --- type initialization --- */ GType *g_param_spec_types = NULL; |
2. 初始化
首先分配一块内存给g_param_spec_types:
然后注册23个基本的参数类型,同时对每种参数类型,都提供相应的处理函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | 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个参数类型:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | +GParamChar | +GParamUChar | +GParamBoolean | +GParamInt | +GParamUInt | +GParamLong | +GParamULong | +GParamInt64 | +GParamUInt64 | +GParamUnichar | +GParamEnum | +GParamFlags | +GParamFloat | +GParamDouble | +GParamString | +GParamParam | +GParamBoxed | +GParamPointer | +GParamValueArray | +GParamObject | +GParamOverride | +GParamGType | `GParamVariant |
3. 引用这个数组:
初始化后,就可以直接使用这个数组了:
今后就用宏直接访问该参数类型,以及其关联的处理函数了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | #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]) |
例如,创建参数类型实例:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | 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时,会大量使用上面这类函数:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 | 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.c中,
1. 定义一个静态全局变量:
1 | static GParamSpecPool *pspec_pool = NULL; |
属性池其实就是:互斥保护+散列表
2. 申请一块内存:
1 2 3 4 5 6 7 8 9 10 11 | 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中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | 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. 从属性池中查询属性:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | 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
安装属性,其实就是把属性放到hash table中:
1 2 3 4 | void g_object_class_install_property (GObjectClass * class , guint property_id, GParamSpec *pspec) |
1 2 3 4 | void g_object_class_install_properties (GObjectClass *oclass, guint n_pspecs, GParamSpec **pspecs) |
1 2 3 4 5 6 7 8 9 10 11 12 13 | 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中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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的回调,实际上是为了处理用户定义的signal/callback.
1. 定义个数据结构:
1 2 3 4 5 | typedef struct { GObject *object; guint n_closures; GClosure *closures[1]; /* flexible array */ } CArray; //closure Array |
同时定义一个标识:
1 | static GQuark quark_closure_array = 0; |
1 2 3 4 5 | 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的回调数组 中拿掉一个回调:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | 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)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 | 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中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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联系在一起了:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | 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. 进一步的封装:可以链接一串信号
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 | 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:
1 2 3 4 5 6 | /* 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中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | 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); |
1. 定义一个双指针
双指针,类似于指针数组;由于数组大小未知,定义为双指针。
1 2 3 | /* --- signal nodes --- */ static guint g_n_signal_nodes = 0 ; static SignalNode **g_signal_nodes = NULL; |
如果知道了g_signal_nodes的大小,
可以像TypeNode那样定义:
1 | 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. 初始化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | 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]中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 | 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时,直接访问指针数组:
1 2 3 4 5 6 7 8 | 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; } |
上面定义的数组g_signal_nodes[signal_id]; 在知道signal_id已知的情况下,可以直接访问数组,提取SignalNode*,
但是,很多情况下,我们不知道signal_id, 而知道signal_name.
如果通过signal_name如何查询与之对应的signal id等信息呢?
1 在前面New Signal时,我们就看到:为了方便查询,留了后手:
1 2 3 4 5 6 7 8 9 | 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来查找:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 | /* --- 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 再封装一次,提供给外界使用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | 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:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 | 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); } |
这里的处理有点意思,也不知道到底是否高效:
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:
1 2 3 4 5 6 7 8 | 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | 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中 (各种插入)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 | 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中
具体参考代码:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | 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
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 | 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()是调用:
比如:
1 2 3 4 5 6 7 | gulong g_signal_connect_data (gpointer instance, const gchar *detailed_signal, GCallback c_handler, gpointer data, GClosureNotify destroy_data, GConnectFlags connect_flags) |
1 2 3 4 5 | gulong g_signal_connect_closure (gpointer instance, const gchar *detailed_signal, GClosure *closure, gboolean after) |
1 2 3 4 5 6 | 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个链表呢?
1 | static Emission *g_recursive_emissions = NULL; |
1 | static Emission *g_restart_emissions = NULL; |
2. 再定义3个内联函数:
把临时emission, 放入全局的list中:push
查找:find
弹出临时emission: pop
1 2 3 4 5 6 7 8 | 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); |
Read the document and source code.
https://developer.gnome.org/gobject/unstable/
static GType gst_signal_object_get_type (void); 其实还有一个宏: G_DEFINE_ABSTRACT_TYPE (GstObject,gst_object, G_TYPE_OBJECT); |
#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() */ |
static gboolean init_post (GOptionContext * context, GOptionGroup * group, gpointer data, GError ** error) { //…. g_type_class_ref (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; } |
document | HEAD | ||
---|---|---|---|
Application Development Manual (Read this first) | HTML | PostScript | |
Frequently Asked Questions | HTML | PostScript | |
Plugin Writer's Guide | HTML | PostScript | |
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 |
document | HEAD | ||
---|---|---|---|
GStreamer Base Plugins Libraries Reference | HTML |
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 |
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库中的数组GArray类型很像C++标准容器库中的vector容器。要使用glib库中的数组中需要声明一个指向GArray类型的指针。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | struct _GArray { gchar *data; guint len; }; struct _GByteArray { guint8 *data; guint len; }; struct _GPtrArray { gpointer *pdata; guint len; }; |
双向链表与单向链表的区别是,从一个节点,不仅能访问到它的下一个节点,还能访问到它的上一个节点,其定义如下:
1 2 3 4 5 6 7 8 | typedef struct _GList GList; struct _GList { gpointer data; GList *next; GList *prev; }; |
1. GLib Reference Manual
http://developer.gimp.org/api/2.0/glib/index.html (完整的)
https://developer.gnome.org/glib/stable/
2. g
http://wenku.baidu.com/view/c72d83222f60ddccda38a07b.html
3. 如
http://wenku.baidu.com/view/29d6911ffc4ffe473368abb8.html
4. G
http://wenku.baidu.com/view/28dd2e0590c69ec3d5bb7564.html?pn=51
glib/gobject的一个网友的:
http://socol.iteye.com/category/86299
glib中用的非常多的:
指针,指针数组,数组指针,函数指针,指针函数:
Read the source code!
看再多的文档,最后都要回归到code上面来。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | /* 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 |
1 | #define G_TYPE_FUNDAMENTAL_SHIFT (2) |
这种左移,右移的移位操作,本身效率是高,但是为什么要这样做? |
模板文件,这些宏,在后面用户自定义GObject时非常有用,
要理解他们,用好他们;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | /* --- 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[]
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 | 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也是可以做父亲的类型
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | | `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 |
下面是个内联函数,可以取代宏,有编译器直接展开,效率高;
同时,也可以检查参数的有效性;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | 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;
只有一个函数进行了调用:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | 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的效率要高;
使用glib的gtype/gobject开发的gtk, gstreamer等,都离不开一个gtype, gobject.
//1,用指针数组,保存基础类型,即一些父类型
1 | static TypeNode *static_fundamental_type_nodes[(G_TYPE_FUNDAMENTAL_MAX >> G_TYPE_FUNDAMENTAL_SHIFT) + 1] = { NULL, }; |
//2, 用散列表来保持所有的类型,包括父类型,子类型
1 | static GHashTable *static_type_nodes_ht = NULL; |
1 | static_type_nodes_ht = g_hash_table_new (g_direct_hash, g_direct_equal); |
它使用指针作为键值
如:
如果没有的话,保持在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); |
参考gobject_query.c
主要是把父子关系清晰的打印出来:
指针数组static_fundamental_type_nodes,存放了无父类的typenode;
所以只要循环这个指针数组,然后对基础typenode, 嵌套循环其子类,就可以了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 | /* 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, 以及父子关系:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 | 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 |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 | | ` 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 |
https://developer.gnome.org/gobject/stable/index.html
GObject的动态类型系统允许程序在运行时进行类型注册,它的最主要目的有两个:
1)使用面向对象的设计方法来编程。使用纯C语言设计出来的一整套面向对象的编程环境。
2)多语言交互。使Perl或者Python等解释型的脚本语言能使用GLIB提供的函数。这一目的是最主要的,所以,在学习GObject的设计时,需要牢记这一首要目标,这对理解GObject的一些奇怪的设计及特性是有较大帮助的。
Type |
|||||||
GValueType (基本类型,以及操作API) |
这里注册 基础类型:
这些基础类型,是可以派生的;不可类化;不可实例化;不可深度派生 这些基础类型,可以放到下面的容器中:GValue中 并且对每种基本类型提供如下API集合:
|
||||||
GValue (泛型) (基本类型的容器) |
Generic values — A polymorphic(多态的) type that can hold values of any other type 在C语言里,通用类型我们一般是用void *以表示任何类型的数据。但GObject的设计初衷是为了解决多语言交互问题,所以必须设计出一套能容纳任何数据类型的通用数据类型。以便在不同的编程语言之间进行数据转换操作。这个数据类型就是GValue。
还可以容纳用户自定义的类型; |
||||||
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的理解,参考: |
||||||
|
|
||||||
GEnumValue,GFlagValue |
注册2个基础类型:
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; 标准的属性名字和它的值:
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的copied, transformed and compared函数; 用一个全局的数组:
来保持这些属性
每个类型都注册了一组基本的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在很多地方都可以用:
信号的列集函数: |
||||||
GCClosure |
Marshal/closure的关系比较紧密。 https://developer.gnome.org/gobject/stable/gobject-Closures.html 要理解透彻,否则对于很多东西还是一知半解。 GClosure(闭包):表示程序员提供的回调。 GClosure组成:Callback + Marshaller GClosure的作用:
GClosure的一个重要作用是实现Signal机制。 GClosure的好处:不仅仅是callback/data
具体过程: 假设: 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 闭包 (写的非常好) |
||||||
GSignal |
在gobject系统中, 信号是一种定制对象行为的手段, 也是一种多种用途的通知机制. 每一个信号都是和能发出信号的类型一起注册到系统中的.
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 |
|
参考:
http://garfileo.is-programmer.com/categories/6934/posts
快速上手GObject:
http://blog.csdn.net/acs713/article/details/7778051