gobject->qdata的作用很大。
可以在&gobject->data上面绑定任何数据
ID | quark name | 说明 | |
1 | quark_closure_array | ||
2 | quark_weak_refs | ||
3 | quark_toggle_refs | ||
4 | property_notify_context.quark_notify_queue | 实现gobject property change的Notify功能 | |
5 | 用户自定义的各种其他quark data |
与属性相关的几个定义:
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 g_object_do_class_init (GObjectClass * class ) { 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; class ->set_property = g_object_do_set_property; class ->get_property = g_object_do_get_property; class ->dispatch_properties_changed = g_object_dispatch_properties_changed; class ->notify = NULL; gobject_signals[NOTIFY] = g_signal_new (g_intern_static_string ( "notify" ), G_TYPE_FROM_CLASS ( class ), G_SIGNAL_RUN_FIRST | G_SIGNAL_NO_RECURSE | G_SIGNAL_DETAILED | G_SIGNAL_NO_HOOKS | G_SIGNAL_ACTION, G_STRUCT_OFFSET (GObjectClass, notify), NULL, NULL, g_cclosure_marshal_VOID__PARAM, G_TYPE_NONE, 1, G_TYPE_PARAM); g_type_add_interface_check (NULL, object_interface_check_properties); } |
//这两个基本上没有东西,需要被子类override:
class->set_property = g_object_do_set_property;
class->get_property = g_object_do_get_property;
我们从GObject 内部property机制/ 用户(使用GObject Property) 的2个角度看:
用户(使用GObject Property) |
1. install properties g_object_class_install_property //用的多 g_object_class_install_properties
2. 提供override GObjectClass的set/get property 类成员接口 如:
3. 调用GObject提供的系列get/set, 修改/获取property, 并且发信号“Notify"
? user 关心这个"notify"信号吗? 仅仅是get/set property的value?
如果user: g_signal_connect (obj, "notify", G_CALLBACK (on_notify), &data); 下面的APIs会激发notifiy queue去发射signal " notifiy": g_object_set g_object_notify_by_pspec g_object_notify 然后去执行用户的callback
|
||||||||||||||
GObject 内部property机制 |
1. 提供一个全局的pspec pool, 保存用户install的properties 2. 一个quark:quark_notify_queue, 用来标识Notify queue; 1)这个notify queue是保存pspec链表
2)notify queue作为qdata绑定给gobject上面
3. 一个dispatcher, 作用就是发射signal: "notify" 4. 与这个"notify"信号相关 1)定义一个信号GObject::notify 并绑定default handler: G_STRUCT_OFFSET (GObjectClass, notify), class->notify = NULL; 2)g_object_notify_queue_thaw
如果用户user, 不用g_signal_connect(), 这样user level的c handler也是NULL new signal时,default handler = NULL 难道没有人care 这个"notify" signal吗?那还要这个spec notifcation机制干什么?
5. 提供给上层user使用的几个get/set property的API:
上面的6个APIs, 以及g_object_new(), g_object_newv, g_object_new_vlist 都会触发g_object_notify_queue_thaw(),从而对所有的属性都发"notify" 信号? |
gobject property的使用,参考一下:
glib/gobject/tests/properties.c:
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 | #include <stdlib.h> #include <gstdio.h> #include <glib-object.h> typedef struct _TestObject { GObject parent_instance; gint foo; gboolean bar; gchar *baz; } TestObject; typedef struct _TestObjectClass { GObjectClass parent_class; } TestObjectClass; enum { PROP_0, PROP_FOO, PROP_BAR, PROP_BAZ, N_PROPERTIES }; static GParamSpec *properties[N_PROPERTIES] = { NULL, }; G_DEFINE_TYPE (TestObject, test_object, G_TYPE_OBJECT); static void test_object_set_foo (TestObject *obj, gint foo) { if (obj->foo != foo) { obj->foo = foo; g_assert (properties[PROP_FOO] != NULL); g_object_notify_by_pspec (G_OBJECT (obj), properties[PROP_FOO]); } } static void test_object_set_bar (TestObject *obj, gboolean bar) { bar = !!bar; if (obj->bar != bar) { obj->bar = bar; g_assert (properties[PROP_BAR] != NULL); g_object_notify_by_pspec (G_OBJECT (obj), properties[PROP_BAR]); } } static void test_object_set_baz (TestObject *obj, const gchar *baz) { if (g_strcmp0 (obj->baz, baz) != 0) { g_free (obj->baz); obj->baz = g_strdup (baz); g_assert (properties[PROP_BAZ] != NULL); g_object_notify_by_pspec (G_OBJECT (obj), properties[PROP_BAZ]); } } static void test_object_finalize (GObject *gobject) { g_free (((TestObject *) gobject)->baz); G_OBJECT_CLASS (test_object_parent_class)->finalize (gobject); } static void test_object_set_property (GObject *gobject, guint prop_id, const GValue *value, GParamSpec *pspec) { TestObject *tobj = (TestObject *) gobject; g_assert_cmpint (prop_id, !=, 0); g_assert_cmpint (prop_id, !=, N_PROPERTIES); g_assert (pspec == properties[prop_id]); switch (prop_id) { case PROP_FOO: test_object_set_foo (tobj, g_value_get_int (value)); break ; case PROP_BAR: test_object_set_bar (tobj, g_value_get_boolean (value)); break ; case PROP_BAZ: test_object_set_baz (tobj, g_value_get_string (value)); break ; default : g_assert_not_reached (); } } static void test_object_get_property (GObject *gobject, guint prop_id, GValue *value, GParamSpec *pspec) { TestObject *tobj = (TestObject *) gobject; g_assert_cmpint (prop_id, !=, 0); g_assert_cmpint (prop_id, !=, N_PROPERTIES); g_assert (pspec == properties[prop_id]); switch (prop_id) { case PROP_FOO: g_value_set_int (value, tobj->foo); break ; case PROP_BAR: g_value_set_boolean (value, tobj->bar); break ; case PROP_BAZ: g_value_set_string (value, tobj->baz); break ; default : g_assert_not_reached (); } } static void test_object_class_init (TestObjectClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); properties[PROP_FOO] = g_param_spec_int ( "foo" , "Foo" , "Foo" , -1, G_MAXINT, 0, G_PARAM_READWRITE); properties[PROP_BAR] = g_param_spec_boolean ( "bar" , "Bar" , "Bar" , FALSE, G_PARAM_READWRITE); properties[PROP_BAZ] = g_param_spec_string ( "baz" , "Baz" , "Baz" , NULL, G_PARAM_READWRITE); gobject_class->set_property = test_object_set_property; gobject_class->get_property = test_object_get_property; gobject_class->finalize = test_object_finalize; g_object_class_install_properties (gobject_class, N_PROPERTIES, properties); } static void test_object_init (TestObject *self) { self->foo = 42; self->bar = TRUE; self->baz = g_strdup ( "Hello" ); } static void properties_install ( void ) { TestObject *obj = g_object_new (test_object_get_type (), NULL); GParamSpec *pspec; g_assert (properties[PROP_FOO] != NULL); pspec = g_object_class_find_property (G_OBJECT_GET_CLASS (obj), "foo" ); g_assert (properties[PROP_FOO] == pspec); g_object_unref (obj); } typedef struct { const gchar *name; GParamSpec *pspec; } TestNotifyClosure; static void on_notify (GObject *gobject, GParamSpec *pspec, TestNotifyClosure *clos) { g_assert (clos->pspec == pspec); g_assert_cmpstr (clos->name, ==, pspec->name); } static void properties_notify ( void ) { TestObject *obj = g_object_new (test_object_get_type (), NULL); TestNotifyClosure clos; g_assert (properties[PROP_FOO] != NULL); clos.name = "foo" ; clos.pspec = properties[PROP_FOO]; g_signal_connect (obj, "notify" , G_CALLBACK (on_notify), &clos); g_object_set (obj, "foo" , 47, NULL); g_object_unref (obj); } static void properties_construct ( void ) { TestObject *obj; gint val; g_test_bug ( "630357" ); /* more than 16 args triggers a realloc in g_object_new_valist() */ obj = g_object_new (test_object_get_type (), "foo" , 1, "foo" , 2, "foo" , 3, "foo" , 4, "foo" , 5, "foo" , 6, "foo" , 7, "foo" , 8, "foo" , 9, "foo" , 10, "foo" , 11, "foo" , 12, "foo" , 13, "foo" , 14, "foo" , 15, "foo" , 16, "foo" , 17, "foo" , 18, NULL); g_object_get (obj, "foo" , &val, NULL); g_assert (val == 18); g_object_unref (obj); } int main ( int argc, char *argv[]) { g_type_init (); g_test_init (&argc, &argv, NULL); g_test_add_func ( "/properties/install" , properties_install); g_test_add_func ( "/properties/notify" , properties_notify); g_test_add_func ( "/properties/construct" , properties_construct); return g_test_run (); } |
2025年3月25日 18:40
Usually I do not learn post on blogs, but I would like to say that this write-up very forced me to check out and do so! Your writing style has been amazed me. Thank you, quite nice article. 바카라사이트