gobject->qdata的使用(1: property notify and getter/setter)。

os posted @ 2013年9月13日 14:24 in GObject , 1333 阅读

gobjec相关学习文章的list.

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    

 

4 quark: property_notify_context.quark_notify_queue

与属性相关的几个定义:

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 类成员接口

如:

1
2
gobject_class->set_property = gst_base_audio_sink_set_property;
gobject_class->get_property = gst_base_audio_sink_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链表

1
nqueue->pspecs = g_slist_prepend (nqueue->pspecs, pspec);

 

   2)notify queue作为qdata绑定给gobject上面

1
2
g_datalist_id_set_data_full (&object->qdata, context->quark_notify_queue,
                   nqueue, g_object_notify_queue_free);

 

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

1
context->dispatcher (object, n_pspecs, pspecs);
1
property_notify_context.dispatcher = g_object_notify_dispatcher;
1
2
3
4
5
6
7
static void
g_object_notify_dispatcher (GObject     *object,
                guint        n_pspecs,
                GParamSpec **pspecs)
{
  G_OBJECT_GET_CLASS (object)->dispatch_properties_changed (object, n_pspecs, pspecs);
}

 

1
2
3
4
5
6
7
8
9
10
static void
g_object_dispatch_properties_changed (GObject     *object,
                      guint        n_pspecs,
                      GParamSpec **pspecs)
{
  guint i;
 
  for (i = 0; i < n_pspecs; i++)
    g_signal_emit (object, gobject_signals[NOTIFY], g_quark_from_string (pspecs[i]->name), pspecs[i]);
}

如果用户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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
void        g_object_set                      (gpointer        object,
                           const gchar    *first_property_name,
                           ...) G_GNUC_NULL_TERMINATED;
void        g_object_get                      (gpointer        object,
                           const gchar    *first_property_name,
                           ...) G_GNUC_NULL_TERMINATED;
void        g_object_set_valist               (GObject        *object,
                           const gchar    *first_property_name,
                           va_list         var_args);
void        g_object_get_valist               (GObject        *object,
                           const gchar    *first_property_name,
                           va_list         var_args);
void        g_object_set_property             (GObject        *object,
                           const gchar    *property_name,
                           const GValue   *value);
void        g_object_get_property             (GObject        *object,
                           const gchar    *property_name,
                           GValue         *value);

 上面的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_bug_base ("http://bugzilla.gnome.org/");
 
  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 ();
}

 

Avatar_small
Matthew Wade 说:
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. 바카라사이트


登录 *


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