非常に低レベルのコードに取り組もうとしている場合を除き、本当に気にする必要があるのは、GValue と GParamType の 2 つだけです。
私はから始めますGParamType
GParamType
プロパティを GObject に登録するために使用されます。たとえば、Person という GObject サブクラスがあり、Name と Age の 2 つのプロパティを持たせたいとします。関数では、class_init
これらを次のように登録します
{
GParamSpec *pspec;
. . .
pspec = g_param_spec_string ("name", "Name", "The name of the person", "", G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
g_object_class_install_property (object_class, PROP_NAME, pspec);
pspec = g_param_spec_int ("age", "Age", "The age of the person", 0, G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
g_object_class_install_property (object_class, PROP_AGE, spec);
. . .
}
これで、これらのプロパティに対してg_object_get
orを呼び出すことができ、システムはそれを処理する方法を認識しますg_object_set
char *name;
int age;
g_object_set (G_OBJECT (person), "name", "Steve", "age", 37, NULL);
g_object_get (G_OBJECT (person), "name", &name, "age", &age, NULL);
g_print ("%s is %d years old\n", name, age);
// And because the type system knows when a property is a string, it knows how to give
// you a copy of the string, so you need to free it once you've finished with it
g_free (name);
様々なパラメータはここで説明されています: GParamSpecすべての標準型 (strings、bools、ints など) には GValue 型があり、GStreamer などの他のいくつかのライブラリは独自のカスタムのものを登録します。
GObjectClass にプロパティをインストールする以外に、GParamSpec を扱う必要はほとんどありません。それらが現れる 2 つの主な機会は、GObjectClass の set/get_property メソッドと GObject 通知シグナルです。最後のケースでは、 を呼び出して、どのプロパティが通知シグナルを受信したかを検出するのに役立ちますがg_param_spec_get_name
、実際には次のように、より具体的な通知シグナルを使用することをお勧めします。
g_signal_connect (person, "notify::name", G_CALLBACK (name_changed_cb), NULL);
g_signal_connect (person, "notify::age", G_CALLBACK (age_changed_cb), NULL);
それよりも
g_signal_connect (person, "notify", G_CALLBACK (something_changed_cb), NULL);
独自の構造を作成し、それらをプロパティに使用したい場合があります。たとえば、私が持っていた場合
struct _PersonDetails {
char *name;
int age;
}
そして、Person オブジェクトに 2 つのプロパティを持たせる代わりに、「詳細」と呼ばれる 1 つのプロパティが必要でした。GLib 型システムは、カスタムを処理する方法を認識していないstruct _PersonDetails
ため、Glib 内部で渡される構造を正しくコピー/解放する方法を認識できるように、ボックス化された型を作成する必要があります。そして、そこにGValue
出番です。
GValue
異なる型の値をラップして、(必要な場合) 正しくコピーおよび解放できるようにし、汎用関数を使用できるようにするためのものです。
たとえば、GObjectClass メソッド set_property のプロトタイプは
void set_property (GObject *object, guint property_id, const GValue *value, GParamSpec *pspec)
つまり、GValue で表すことができる任意の型を渡すことができ、set_int_property、set_string_property、set_bool_property などの特定の関数は必要ありません。
また、プロパティ「名前」が文字列型として登録されており、その文字列をコピー/解放するために必要な関数を持っていることを知っているため、渡されたパラメーターを処理する方法を関数が知っていることも意味しg_object_set
ますg_object_get
。
GValue の詳細については、ここを参照してください -一般的な値
カスタムstruct _PersonDetails
を GLib 型システムに登録するには、カスタムの Boxed 型を作成し、それをコピーして解放する方法をシステムに指示します。詳細はこちら:ボックス型
G_DEFINE_BOXED_TYPE (PersonDetails, person_details,
person_details_copy,
person_details_free)
. . .
static gpointer
person_details_copy (gpointer data)
{
struct _PersonDetails *details = (struct _PersonDetails *)data;
struct _PersonDetails *copy = g_new (struct _PersonDetails, 1);
// We need to copy the string
copy->name = g_strdup (details->name);
copy->age = details->age;
return (gpointer) copy;
}
static void
person_details_free (gpointer data)
{
struct _PersonDetails *details = (struct _PersonDetails *)data;
// name was allocated so it needs freed as well
g_free (details->name);
g_free (details);
}
これで、次を使用してタイプを登録できます
pspec = g_param_spec_boxed ("details", "Details", "The person's details", person_details_get_type (), G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
g_object_class_install_property (object_class, PROP_DETAILS, pspec);