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

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

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

与属性相关的几个定义:

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

如:

  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链表

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

 

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

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

context->dispatcher (object, n_pspecs, pspecs);
property_notify_context.dispatcher = g_object_notify_dispatcher;
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);
}

 

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:

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:

#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 ();
}

 


登录 *


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