8

GObject ライブラリは非常にドキュメント化されています。作成されたエンティティの目的を理解するのは非常に困難です。GValueつまり、 、GTypeValueTableGTypeInfoGParamSpecの役割がわかりませんTypeData

簡単に言えば、タイプ登録のプロセスは次のとおりです。各タイプは構造体で表されTypeNodeます。TypeNode構造体には 2 つのストレージがあります。静的な基本型のstatic_fundamental_type_nodes array格納用と、静的な非基本型用のハッシュ テーブルです。それぞれは、非基本型の場合は対応するメモリアドレス、基本型の場合はインデックスです。動的型はどうなりますか - わかりません。できれば説明してください。対応するコードは、型システムの初期化を担当する gtype_init 関数にあります: http://git.gnome.org/browse/glib/tree/gobject/gtype.c#n4323TypeNodesstatic_type_nodes_htGTypeTypeNodeTypeNodestatic_fundamental_type_nodes

ここに画像の説明を入力

GValueGParamSpecおよびそれ自体であるため、型として登録されますGObjectGTypes

GValueそれを介して新しい型の値を登録するために使用されることを意図していますが、どのように?.

GParametersタイプの登録にGParamSpec必要なようですGObject(よくわかりません)。それはどのように正確に行われますか?それぞれの役割は?

最も重要なこと: と の役割はGTypeValueTableGTypeInfoですかTypeData? TypeDataによって参照され、BoxedData、ClassData、IFaceData、InstanceData のサブ構造と同様TypeNodeに含まれます (なぜ Instance、型を登録しないのですか?)。GTypeValueTableさらに、それらは互いに重複しているように見えます。それらのすべてに base_init/finalize への参照が含まれているため、class_init/finalize には への参照がありGTypeValueTableます。

ですから、GObject パパス、これを読んでいるなら、説明してください! 使用する構造の目的を説明してください。

4

1 に答える 1

18

非常に低レベルのコードに取り組もうとしている場合を除き、本当に気にする必要があるのは、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_getorを呼び出すことができ、システムはそれを処理する方法を認識します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);
于 2013-02-13T07:48:04.493 に答える