mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-03-03 14:42:10 +01:00
Documentation fixes. Recommend macro type names such as
2007-11-13 Cody Russell <bratsche@gnome.org> * docs/reference/gobject/gobject-docs.sgml: * docs/reference/gobject/tut_gsignal.xml: * docs/reference/gobject/tut_gtype.xml: * docs/reference/gobject/tut_intro.xml: * docs/reference/gobject/tut_tools.xml: * docs/reference/gobject/tut_howto.xml: * docs/reference/gobject/tut_gobject.xml: Documentation fixes. Recommend macro type names such as NAUTILUS_TYPE_WINDOW (not NAUTILUS_WINDOW_TYPE). Fixed text which erroneously stated that superclass initializers don't run when an object is instantiated. Fixed numerous spelling mistakes. Minor grammar edits. (#490637, Adam Dingle) svn path=/trunk/; revision=5857
This commit is contained in:
parent
1d174f072b
commit
515f42c9ed
15
ChangeLog
15
ChangeLog
@ -1,3 +1,18 @@
|
||||
2007-11-13 Cody Russell <bratsche@gnome.org>
|
||||
|
||||
* docs/reference/gobject/gobject-docs.sgml:
|
||||
* docs/reference/gobject/tut_gsignal.xml:
|
||||
* docs/reference/gobject/tut_gtype.xml:
|
||||
* docs/reference/gobject/tut_intro.xml:
|
||||
* docs/reference/gobject/tut_tools.xml:
|
||||
* docs/reference/gobject/tut_howto.xml:
|
||||
* docs/reference/gobject/tut_gobject.xml: Documentation fixes.
|
||||
Recommend macro type names such as NAUTILUS_TYPE_WINDOW (not
|
||||
NAUTILUS_WINDOW_TYPE). Fixed text which erroneously stated that
|
||||
superclass initializers don't run when an object is
|
||||
instantiated. Fixed numerous spelling mistakes. Minor grammar
|
||||
edits. (#490637, Adam Dingle)
|
||||
|
||||
2007-11-09 Matthias Clasen <mclasen@redhat.com>
|
||||
|
||||
* glib/gkeyfile.c: Coding style cleanups and doc
|
||||
|
@ -42,7 +42,7 @@
|
||||
types and algorithms (linked lists, hash tables and so forth), the
|
||||
GLib Object System provides the required implementations of a
|
||||
flexible extensible and intentionally easy to map (into other
|
||||
languages) object oriented framework for C.
|
||||
languages) object-oriented framework for C.
|
||||
The substantial elements that are provided can be summarized as:
|
||||
<itemizedlist>
|
||||
<listitem><para>
|
||||
|
@ -3,7 +3,7 @@
|
||||
<title>The GObject base class</title>
|
||||
|
||||
<para>
|
||||
The two previous chapters discussed the details of Glib's Dynamic Type System
|
||||
The two previous chapters discussed the details of GLib's Dynamic Type System
|
||||
and its signal control system. The GObject library also contains an implementation
|
||||
for a base fundamental type named <type><link linkend="GObject">GObject</link></type>.
|
||||
</para>
|
||||
@ -16,13 +16,13 @@
|
||||
<listitem><para>Generic per-object properties with set/get function pairs</para></listitem>
|
||||
<listitem><para>Easy use of signals</para></listitem>
|
||||
</itemizedlist>
|
||||
All the GNOME libraries which use the GLib type system (like Gtk+ and GStreamer)
|
||||
All the GNOME libraries which use the GLib type system (like GTK+ and GStreamer)
|
||||
inherit from <type><link linkend="GObject">GObject</link></type> which is why it is important to understand
|
||||
the details of how it works.
|
||||
</para>
|
||||
|
||||
<sect1 id="gobject-instanciation">
|
||||
<title>Object instanciation</title>
|
||||
<sect1 id="gobject-instantiation">
|
||||
<title>Object instantiation</title>
|
||||
|
||||
<para>
|
||||
The <function><link linkend="g-object-new">g_object_new</link></function> family of functions can be used to instantiate any
|
||||
@ -162,7 +162,7 @@ MamanBar *bar = g_object_new (MAMAN_TYPE_BAR, NULL);
|
||||
is how we can find the parent constructor. An approach (used in GTK+ source code) would be
|
||||
to save the original constructor in a static variable from <function>maman_bar_class_init</function>
|
||||
and then to re-use it from <function>maman_bar_constructor</function>. This is clearly possible
|
||||
and very simple but I was told it was not nice and the prefered way is to use the
|
||||
and very simple but I was told it was not nice and the preferred way is to use the
|
||||
<function><link linkend="g-type-class-peek">g_type_class_peek</link></function> and <function><link linkend="g-type-class-peek-parent">g_type_class_peek_parent</link></function> functions.
|
||||
</para>
|
||||
|
||||
@ -174,7 +174,7 @@ MamanBar *bar = g_object_new (MAMAN_TYPE_BAR, NULL);
|
||||
was registered. After instance_init returns, the object is fully initialized and should be
|
||||
ready to answer any user-request. When <function><link linkend="g-type-create-instance">g_type_create_instance</link></function>
|
||||
returns, <function>g_object_constructor</function> sets the construction properties
|
||||
(ie: the properties which were given to <function><link linkend="g-object-new">g_object_new</link></function>) and returns
|
||||
(i.e. the properties which were given to <function><link linkend="g-object-new">g_object_new</link></function>) and returns
|
||||
to the user's constructor which is then allowed to do useful instance initialization...
|
||||
</para>
|
||||
|
||||
@ -325,7 +325,7 @@ void g_object_run_dispose (GObject *object);
|
||||
increase and decrease the reference count.These functions are thread-safe as of GLib 2.8.
|
||||
The reference count is, unsurprisingly, initialized to one by
|
||||
<function><link linkend="g-object-new">g_object_new</link></function> which means that the caller
|
||||
is currenly the sole owner of the newly-created reference.
|
||||
is currently the sole owner of the newly-created reference.
|
||||
When the reference count reaches zero, that is,
|
||||
when <function><link linkend="g-object-unref">g_object_unref</link></function> is called by the last client holding
|
||||
a reference to the object, the <emphasis>dispose</emphasis> and the
|
||||
@ -515,7 +515,7 @@ void g_object_run_dispose (GObject *object);
|
||||
<para>
|
||||
One of GObject's nice features is its generic get/set mechanism for object
|
||||
properties. When an object
|
||||
is instanciated, the object's class_init handler should be used to register
|
||||
is instantiated, the object's class_init handler should be used to register
|
||||
the object's properties with <function><link linkend="g-object-class-install-property">g_object_class_install_property</link></function>
|
||||
(implemented in <filename>gobject.c</filename>).
|
||||
</para>
|
||||
@ -657,7 +657,7 @@ g_object_set_property (G_OBJECT (bar), "papa-number", &val);
|
||||
relying on these transformations.
|
||||
</para>
|
||||
</footnote>
|
||||
which matches and conversion will be caried out if needed.
|
||||
which matches and conversion will be carried out if needed.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
@ -704,12 +704,12 @@ g_object_set_property (G_OBJECT (bar), "papa-number", &val);
|
||||
property modifications through the "notify" signal. It is important to remember that
|
||||
even if properties are changed while property change notification is frozen, the "notify"
|
||||
signal will be emitted once for each of these changed properties as soon as the property
|
||||
change notification is thawn: no property change is lost for the "notify" signal. Signal
|
||||
change notification is thawed: no property change is lost for the "notify" signal. Signal
|
||||
can only be delayed by the notification freezing mechanism.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
It sounds like a tedious task to set up GValues everytime when one wants to modify a property.
|
||||
It sounds like a tedious task to set up GValues every time when one wants to modify a property.
|
||||
In practice one will rarely do this. The functions <function><link linkend="g-object-set-property">g_object_set_property</link></function>
|
||||
and <function><link linkend="g-object-get-property">g_object_get_property</link></function>
|
||||
are meant to be used by language bindings. For application there is an easier way and
|
||||
@ -760,7 +760,7 @@ g_object_set (G_OBJECT (foo),
|
||||
|
||||
</sect2>
|
||||
|
||||
<!-- @todo tell here about how to pass use handle properties in derived classe -->
|
||||
<!-- @todo tell here about how to pass use handle properties in derived classes -->
|
||||
|
||||
</sect1>
|
||||
|
||||
|
@ -7,7 +7,7 @@
|
||||
|
||||
<para>
|
||||
Closures are central to the concept of asynchronous signal delivery
|
||||
which is widely used throughout GTK+ and GNOME applications. A Closure is an
|
||||
which is widely used throughout GTK+ and GNOME applications. A closure is an
|
||||
abstraction, a generic representation of a callback. It is a small structure
|
||||
which contains three objects:
|
||||
<itemizedlist>
|
||||
@ -32,12 +32,12 @@ return_type function_callback (... , gpointer user_data);
|
||||
closure implementations: there exists a different Closure implementation for
|
||||
each separate runtime which wants to use the GObject type system.
|
||||
<footnote><para>
|
||||
In Practice, Closures sit at the boundary of language runtimes: if you are
|
||||
writing python code and one of your Python callback receives a signal from
|
||||
one of GTK+ widgets, the C code in GTK+ needs to execute your Python
|
||||
code. The Closure invoked by the GTK+ object invokes the Python callback:
|
||||
In practice, closures sit at the boundary of language runtimes: if you are
|
||||
writing Python code and one of your Python callbacks receives a signal from
|
||||
a GTK+ widget, the C code in GTK+ needs to execute your Python
|
||||
code. The closure invoked by the GTK+ object invokes the Python callback:
|
||||
it behaves as a normal C object for GTK+ and as a normal Python object for
|
||||
python code.
|
||||
Python code.
|
||||
</para></footnote>
|
||||
The GObject library provides a simple <type><link linkend="GCClosure">GCClosure</link></type> type which
|
||||
is a specific implementation of closures to be used with C/C++ callbacks.
|
||||
@ -48,7 +48,7 @@ return_type function_callback (... , gpointer user_data);
|
||||
<listitem><para>
|
||||
Invocation (<function><link linkend="g-closure-invoke">g_closure_invoke</link></function>): this is what closures
|
||||
were created for: they hide the details of callback invocation from the
|
||||
callback invocator.</para>
|
||||
callback invoker.</para>
|
||||
</listitem>
|
||||
<listitem><para>
|
||||
Notification: the closure notifies listeners of certain events such as
|
||||
@ -57,12 +57,12 @@ return_type function_callback (... , gpointer user_data);
|
||||
(finalization notification), <function><link linkend="g-closure-add-invalidate-notifier">g_closure_add_invalidate_notifier</link></function>
|
||||
(invalidation notification) and
|
||||
<function><link linkend="g-closure-add-marshal-guards">g_closure_add_marshal_guards</link></function> (invocation notification).
|
||||
There exist symmetric de-registration functions for finalization and invalidation
|
||||
There exist symmetric deregistration functions for finalization and invalidation
|
||||
events (<function><link linkend="g-closure-remove-finalize-notifier">g_closure_remove_finalize_notifier</link></function> and
|
||||
<function><link linkend="g-closure-remove-invalidate-notifier">g_closure_remove_invalidate_notifier</link></function>) but not for the invocation
|
||||
process.
|
||||
<footnote><para>
|
||||
Closures are refcounted and notify listeners of their destruction in a two-stage
|
||||
Closures are reference counted and notify listeners of their destruction in a two-stage
|
||||
process: the invalidation notifiers are invoked before the finalization notifiers.
|
||||
</para></footnote></para>
|
||||
</listitem>
|
||||
@ -74,7 +74,7 @@ return_type function_callback (... , gpointer user_data);
|
||||
|
||||
<para>
|
||||
If you are using C or C++
|
||||
to connect a callback to a given event, you will either use the simple <type><link linkend="GCClosure">GCClosure</link></type>s
|
||||
to connect a callback to a given event, you will either use simple <type><link linkend="GCClosure">GCClosure</link></type>s
|
||||
which have a pretty minimal API or the even simpler <function><link linkend="g-signal-connect">g_signal_connect</link></function>
|
||||
functions (which will be presented a bit later :).
|
||||
<programlisting>
|
||||
@ -106,10 +106,10 @@ GClosure* g_signal_type_cclosure_new (GType itype,
|
||||
</sect2>
|
||||
|
||||
<sect2>
|
||||
<title>non-C closures (for the fearless).</title>
|
||||
<title>Non-C closures (for the fearless)</title>
|
||||
|
||||
<para>
|
||||
As was explained above, Closures hide the details of callback invocation. In C,
|
||||
As was explained above, closures hide the details of callback invocation. In C,
|
||||
callback invocation is just like function invocation: it is a matter of creating
|
||||
the correct stack frame for the called function and executing a <emphasis>call</emphasis>
|
||||
assembly instruction.
|
||||
@ -156,12 +156,12 @@ g_cclosure_marshal_VOID__INT (GClosure *closure,
|
||||
|
||||
<para>
|
||||
Of course, there exist other kinds of marshallers. For example, James Henstridge
|
||||
wrote a generic Python marshaller which is used by all python Closures (a python closure
|
||||
is used to have python-based callback be invoked by the closure invocation process).
|
||||
This python marshaller transforms the input GValue list representing the function
|
||||
parameters into a Python tuple which is the equivalent structure in python (you can
|
||||
wrote a generic Python marshaller which is used by all Python closures (a Python closure
|
||||
is used to have Python-based callback be invoked by the closure invocation process).
|
||||
This Python marshaller transforms the input GValue list representing the function
|
||||
parameters into a Python tuple which is the equivalent structure in Python (you can
|
||||
look in <function>pyg_closure_marshal</function> in <filename>pygtype.c</filename>
|
||||
in the <emphasis>pygobject</emphasis> module in GNOME cvs server).
|
||||
in the <emphasis>pygobject</emphasis> module in the GNOME Subversion server).
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
|
@ -1,9 +1,9 @@
|
||||
<?xml version='1.0' encoding="ISO-8859-1"?>
|
||||
<chapter id="chapter-gtype">
|
||||
<title>The Glib Dynamic Type System</title>
|
||||
<title>The GLib Dynamic Type System</title>
|
||||
|
||||
<para>
|
||||
A type, as manipulated by the Glib type system, is much more generic than what
|
||||
A type, as manipulated by the GLib type system, is much more generic than what
|
||||
is usually understood as an Object type. It is best explained by looking at the
|
||||
structure and the functions used to register new types in the type system.
|
||||
<programlisting>
|
||||
@ -53,7 +53,7 @@ GType g_type_register_fundamental (GType type_id,
|
||||
new fundamental types.
|
||||
<footnote>
|
||||
<para>
|
||||
Please, note that there exist another registration function: the
|
||||
Please note that there exists another registration function: the
|
||||
<function><link linkend="g-type-register-dynamic">g_type_register_dynamic</link></function>. We will not discuss this
|
||||
function here since its use is very similar to the <function>_static</function>
|
||||
version.
|
||||
@ -71,7 +71,7 @@ GType g_type_register_fundamental (GType type_id,
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Fundamental and non-Fundamental types are defined by:
|
||||
Fundamental and non-fundamental types are defined by:
|
||||
<itemizedlist>
|
||||
<listitem><para>
|
||||
class size: the class_size field in <type><link linkend="GTypeInfo">GTypeInfo</link></type>.
|
||||
@ -89,7 +89,7 @@ GType g_type_register_fundamental (GType type_id,
|
||||
<type><link linkend="GTypeInfo">GTypeInfo</link></type>.
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
instanciation policy (C++ type of new operator): the n_preallocs
|
||||
instantiation policy (C++ type of new operator): the n_preallocs
|
||||
field in <type><link linkend="GTypeInfo">GTypeInfo</link></type>.
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
@ -102,7 +102,7 @@ GType g_type_register_fundamental (GType type_id,
|
||||
</itemizedlist>
|
||||
Fundamental types are also defined by a set of <type><link linkend="GTypeFundamentalFlags">GTypeFundamentalFlags</link></type>
|
||||
which are stored in a <type><link linkend="GTypeFundamentalInfo">GTypeFundamentalInfo</link></type>.
|
||||
Non-Fundamental types are furthermore defined by the type of their parent which is
|
||||
Non-fundamental types are furthermore defined by the type of their parent which is
|
||||
passed as the parent_type parameter to <function><link linkend="g-type-register-static">g_type_register_static</link></function>
|
||||
and <function><link linkend="g-type-register-dynamic">g_type_register_dynamic</link></function>.
|
||||
</para>
|
||||
@ -111,7 +111,7 @@ GType g_type_register_fundamental (GType type_id,
|
||||
<title>Copy functions</title>
|
||||
|
||||
<para>
|
||||
The major common point between <emphasis>all</emphasis> glib types (fundamental and
|
||||
The major common point between <emphasis>all</emphasis> GLib types (fundamental and
|
||||
non-fundamental, classed and non-classed, instantiable and non-instantiable) is that
|
||||
they can all be manipulated through a single API to copy/assign them.
|
||||
</para>
|
||||
@ -177,7 +177,7 @@ static void test_object (void)
|
||||
g_object_unref (G_OBJECT (obj));
|
||||
}
|
||||
</programlisting>
|
||||
The important point about the above code is that the exact semantic of the copy calls
|
||||
The important point about the above code is that the exact semantics of the copy calls
|
||||
is undefined since they depend on the implementation of the copy function. Certain
|
||||
copy functions might decide to allocate a new chunk of memory and then to copy the
|
||||
data from the source to the destination. Others might want to simply increment
|
||||
@ -215,7 +215,7 @@ struct _GTypeValueTable
|
||||
you will ever need to specify a value_table during type registration
|
||||
because these value_tables are inherited from the parent types for
|
||||
non-fundamental types which means that unless you want to write a
|
||||
fundamental type (not a great idea !), you will not need to provide
|
||||
fundamental type (not a great idea!), you will not need to provide
|
||||
a new value_table since you will inherit the value_table structure
|
||||
from your parent type.
|
||||
</para>
|
||||
@ -238,7 +238,7 @@ struct _GTypeValueTable
|
||||
If your library (or application) is named <emphasis>Maman</emphasis>,
|
||||
<footnote>
|
||||
<para>
|
||||
<emphasis>Maman</emphasis> is the french word for <emphasis>mum</emphasis>
|
||||
<emphasis>Maman</emphasis> is the French word for <emphasis>mum</emphasis>
|
||||
or <emphasis>mother</emphasis> - nothing more and nothing less.
|
||||
</para>
|
||||
</footnote>
|
||||
@ -329,7 +329,7 @@ G_DEFINE_TYPE (MamanBar, maman_bar, G_TYPE_OBJECT)
|
||||
</sect1>
|
||||
|
||||
<sect1 id="gtype-non-instantiable">
|
||||
<title>Non-Instantiable non-classed fundamental types</title>
|
||||
<title>Non-instantiable non-classed fundamental types</title>
|
||||
|
||||
<para>
|
||||
A lot of types are not instantiable by the type system and do not have
|
||||
@ -372,7 +372,7 @@ G_DEFINE_TYPE (MamanBar, maman_bar, G_TYPE_OBJECT)
|
||||
|
||||
<para>
|
||||
Having non-instantiable types might seem a bit useless: what good is a type
|
||||
if you cannot instanciate an instance of that type ? Most of these types
|
||||
if you cannot instantiate an instance of that type ? Most of these types
|
||||
are used in conjunction with <type><link linkend="GValue">GValue</link></type>s: a GValue is initialized
|
||||
with an integer or a string and it is passed around by using the registered
|
||||
type's value_table. <type><link linkend="GValue">GValue</link></type>s (and by extension these trivial fundamental
|
||||
@ -390,7 +390,7 @@ G_DEFINE_TYPE (MamanBar, maman_bar, G_TYPE_OBJECT)
|
||||
Although <type><link linkend="GObject">GObject</link></type>s (detailed in <xref linkend="chapter-gobject"/>)
|
||||
are the most well known type of instantiable
|
||||
classed types, other kinds of similar objects used as the base of an inheritance
|
||||
hierarchy have been externally developped and they are all built on the fundamental
|
||||
hierarchy have been externally developed and they are all built on the fundamental
|
||||
features described below.
|
||||
</para>
|
||||
|
||||
@ -515,14 +515,14 @@ B *b;
|
||||
<title>Initialization and Destruction</title>
|
||||
|
||||
<para>
|
||||
Instanciation of these types can be done with
|
||||
instantiation of these types can be done with
|
||||
<function><link linkend="g-type-create-instance">g_type_create_instance</link></function>:
|
||||
<programlisting>
|
||||
GTypeInstance* g_type_create_instance (GType type);
|
||||
void g_type_free_instance (GTypeInstance *instance);
|
||||
</programlisting>
|
||||
<function><link linkend="g-type-create-instance">g_type_create_instance</link></function> will lookup the type information
|
||||
structure associated to the type requested. Then, the instance size and instanciation
|
||||
<function><link linkend="g-type-create-instance">g_type_create_instance</link></function> will look up the type information
|
||||
structure associated to the type requested. Then, the instance size and instantiation
|
||||
policy (if the n_preallocs field is set to a non-zero value, the type system allocates
|
||||
the object's instance structures in chunks rather than mallocing for every instance)
|
||||
declared by the user are used to get a buffer to hold the object's instance
|
||||
@ -569,7 +569,7 @@ void g_type_free_instance (GTypeInstance *instance);
|
||||
(in <filename>gtype.c</filename>.
|
||||
</para>
|
||||
</footnote>
|
||||
(the concept of destruction is sometimes partly refered to as finalization
|
||||
(the concept of destruction is sometimes partly referred to as finalization
|
||||
in GType) is the symmetric process of the initialization: interfaces are
|
||||
destroyed first.
|
||||
Then, the most derived
|
||||
@ -581,27 +581,19 @@ void g_type_free_instance (GTypeInstance *instance);
|
||||
|
||||
<para>
|
||||
As many readers have now understood it, the base initialization/finalization process is
|
||||
very similar to the C++ Constructor/Destructor paradigm. The practical details are quite different
|
||||
though and it is important not to get confused by the superficial similarities. Typically, what
|
||||
most users have grown to know as a C++ constructor (that is, a list of
|
||||
object methods invoked on the object instance once for each type of the inheritance hierachy) does
|
||||
not exist in GType and must be built on top of the facilities offered by GType. Similarly,
|
||||
very similar to the C++ constructor/destructor paradigm. The practical details are different
|
||||
though and it is important not to get confused by superficial similarities.
|
||||
GTypes have no instance destruction mechanism. It is
|
||||
the user's responsibility to implement correct destruction semantics on top
|
||||
of the existing GType code. (this is what GObject does. See
|
||||
<xref linkend="chapter-gobject"/>)
|
||||
</para>
|
||||
|
||||
<para>
|
||||
For example, if the object B which derives from A is instantiated, GType will only invoke the
|
||||
instance_init callback of object B while a C++ runtime will invoke the constructor of the object
|
||||
type A first and then of the object type B. Furthermore, the C++ code equivalent to the base_init
|
||||
Furthermore, C++ code equivalent to the base_init
|
||||
and class_init callbacks of GType is usually not needed because C++ cannot really create object
|
||||
types at runtime.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The instanciation/finalization process can be summarized as follows:
|
||||
The instantiation/finalization process can be summarized as follows:
|
||||
<table id="gtype-init-fini-table">
|
||||
<title>GType Instantiation/Finalization</title>
|
||||
<tgroup cols="3">
|
||||
@ -666,15 +658,15 @@ void g_type_free_instance (GTypeInstance *instance);
|
||||
</sect1>
|
||||
|
||||
<sect1 id="gtype-non-instantiable-classed">
|
||||
<title>Non-instantiable classed types: Interfaces.</title>
|
||||
<title>Non-instantiable classed types: interfaces</title>
|
||||
|
||||
<para>
|
||||
GType's Interfaces are very similar to Java's interfaces. They allow
|
||||
GType's interfaces are very similar to Java's interfaces. They allow
|
||||
to describe a common API that several classes will adhere to.
|
||||
Imagine the play, pause and stop buttons on hifi equipment - those can
|
||||
be seen as a playback interface. Once you know what the do, you can
|
||||
control your cd-player, mp3-player or anything that uses these symbols.
|
||||
To declare an interfacce you have to register a non-instantiable
|
||||
Imagine the play, pause and stop buttons on hi-fi equipment - those can
|
||||
be seen as a playback interface. Once you know what they do, you can
|
||||
control your CD player, MP3 player or anything that uses these symbols.
|
||||
To declare an interface you have to register a non-instantiable
|
||||
classed type which derives from
|
||||
<type><link linkend="GTypeInterface">GTypeInterface</link></type>. The following piece of code declares such an interface.
|
||||
<programlisting>
|
||||
@ -886,7 +878,7 @@ maman_ibaz_base_init (gpointer g_iface)
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
It is highly unlikely (ie: I do not know of <emphasis>anyone</emphasis> who actually
|
||||
It is highly unlikely (i.e. I do not know of <emphasis>anyone</emphasis> who actually
|
||||
used it) you will ever need other more fancy things such as the ones described in the
|
||||
following section (<xref linkend="gtype-non-instantiable-classed-dest"/>).
|
||||
</para>
|
||||
|
@ -2,20 +2,20 @@
|
||||
<partintro>
|
||||
<para>
|
||||
This chapter tries to answer the real-life questions of users and presents
|
||||
the most common scenario use-cases I could come up with.
|
||||
The use-cases are presented from most likely to less likely.
|
||||
the most common scenario use cases I could come up with.
|
||||
The use cases are presented from most likely to less likely.
|
||||
</para>
|
||||
</partintro>
|
||||
|
||||
<chapter id="howto-gobject">
|
||||
<title>How To define and implement a new GObject?</title>
|
||||
<title>How to define and implement a new GObject</title>
|
||||
|
||||
<para>
|
||||
Clearly, this is one of the most common question people ask: they just want to crank code and
|
||||
Clearly, this is one of the most common questions people ask: they just want to crank code and
|
||||
implement a subclass of a GObject. Sometimes because they want to create their own class hierarchy,
|
||||
sometimes because they want to subclass one of GTK+'s widget. This chapter will focus on the
|
||||
implementation of a subtype of GObject. The sample source code
|
||||
associated to this section can be found in the documentation's source tarball, in the
|
||||
associated with this section can be found in the documentation's source tarball, in the
|
||||
<filename>sample/gobject</filename> directory:
|
||||
<itemizedlist>
|
||||
<listitem><para><filename>maman-bar.{h|c}</filename>: this is the source for a object which derives from
|
||||
@ -42,7 +42,7 @@
|
||||
which is followed not only by GTK+'s code but also by most users of GObject. If you feel the need
|
||||
not to obey the rules stated below, think about it twice:
|
||||
<itemizedlist>
|
||||
<listitem><para>If your users are a bit accustomed to GTK+ code or any Glib code, they will
|
||||
<listitem><para>If your users are a bit accustomed to GTK+ code or any GLib code, they will
|
||||
be a bit surprised and getting used to the conventions you decided upon will take time (money) and
|
||||
will make them grumpy (not a good thing)
|
||||
</para></listitem>
|
||||
@ -84,7 +84,7 @@
|
||||
|
||||
<para>
|
||||
The basic conventions for any header which exposes a GType are described in
|
||||
<xref linkend="gtype-conventions"/>. Most GObject-based code also obeys onf of the following
|
||||
<xref linkend="gtype-conventions"/>. Most GObject-based code also obeys one of of the following
|
||||
conventions: pick one and stick to it.
|
||||
<itemizedlist>
|
||||
<listitem><para>
|
||||
@ -121,7 +121,7 @@ struct _MamanBarClass {
|
||||
/* class members */
|
||||
};
|
||||
|
||||
/* used by MAMAN_BAR_TYPE */
|
||||
/* used by MAMAN_TYPE_BAR */
|
||||
GType maman_bar_get_type (void);
|
||||
|
||||
/*
|
||||
@ -181,13 +181,13 @@ maman_bar_init (GTypeInstance *instance, gpointer g_class) {
|
||||
</para></listitem>
|
||||
|
||||
<listitem><para>
|
||||
A similar alternative, available since Glib version 2.4, is to define a private structure in the .c file,
|
||||
A similar alternative, available since GLib version 2.4, is to define a private structure in the .c file,
|
||||
declare it as a private structure in <function>maman_bar_class_init</function> using
|
||||
<function><link linkend="g-type-class-add-private">g_type_class_add_private</link></function>.
|
||||
Instead of allocating memory in <function>maman_bar_init</function> a pointer to the private memory area is
|
||||
stored in the instance to allow convenient access to this structure.
|
||||
A private structure will then be attached to each newly created object by the GObject system.
|
||||
You dont need to free or allocate the private structure, only the objects or pointers that it may contain.
|
||||
You don't need to free or allocate the private structure, only the objects or pointers that it may contain.
|
||||
Another advantage of this to the previous version is that is lessens memory fragmentation,
|
||||
as the public and private parts of the instance memory are allocated at once.
|
||||
<programlisting>
|
||||
@ -208,7 +208,7 @@ maman_bar_class_init (MamanBarClass *klass)
|
||||
static void
|
||||
maman_bar_init (GTypeInstance *instance, gpointer g_class) {
|
||||
MamanBar *self = MAMAN_BAR (instance);
|
||||
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, MAMAN_BAR_TYPE, MamanBarPrivate);
|
||||
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self, MAMAN_TYPE_BAR, MamanBarPrivate);
|
||||
/* do stuff */
|
||||
}
|
||||
</programlisting>
|
||||
@ -308,7 +308,7 @@ maman_bar_get_type (void)
|
||||
|
||||
<para>
|
||||
<xref linkend="gobject-construction-table"/> shows what user-provided functions
|
||||
are invoked during object instanciation and in which order they are invoked.
|
||||
are invoked during object instantiation and in which order they are invoked.
|
||||
A user looking for the equivalent of the simple C++ constructor function should use
|
||||
the instance_init method. It will be invoked after all the parent's instance_init
|
||||
functions have been invoked. It cannot take arbitrary construction parameters
|
||||
@ -333,7 +333,7 @@ maman_bar_init (GTypeInstance *instance,
|
||||
self->private = g_new0 (MamanBarPrivate, 1);
|
||||
|
||||
/* initialize all public and private members to reasonable default values. */
|
||||
/* If you need specific consruction properties to complete initialization,
|
||||
/* If you need specific construction properties to complete initialization,
|
||||
* delay initialization completion until the property is set.
|
||||
*/
|
||||
}
|
||||
@ -386,7 +386,7 @@ bar_class_init (MamanBarClass *klass)
|
||||
|
||||
<para>Some people sometimes need to construct their object but only after the construction properties
|
||||
have been set. This is possible through the use of the constructor class method as described in
|
||||
<xref linkend="gobject-instanciation"/>. However, I have yet to see <emphasis>any</emphasis> reasonable
|
||||
<xref linkend="gobject-instantiation"/>. However, I have yet to see <emphasis>any</emphasis> reasonable
|
||||
use of this feature. As such, to initialize your object instances, use by default the base_init function
|
||||
and construction properties.
|
||||
</para>
|
||||
@ -685,21 +685,21 @@ maman_bar_subtype_class_init (MamanBarSubTypeClass *klass)
|
||||
<itemizedlist>
|
||||
<listitem><para>You need to change the behaviour of a class without modifying its code. You create
|
||||
a subclass to inherit its implementation, re-implement a public virtual method to modify the behaviour
|
||||
slightly and chain up to ensure that the previous behaviour is not really modifed, just extended.
|
||||
slightly and chain up to ensure that the previous behaviour is not really modified, just extended.
|
||||
</para></listitem>
|
||||
<listitem><para>You are lazy, you have access to the source code of the parent class but you don't want
|
||||
to modify it to add method calls to new specialized method calls: it is faster to hack the child class
|
||||
to chain up than to modify the parent to call down.</para></listitem>
|
||||
<listitem><para>You need to implement the Chain Of Responsability pattern: each object of the inheritance
|
||||
tree chains up to its parent (typically, at the begining or the end of the method) to ensure that
|
||||
<listitem><para>You need to implement the Chain Of Responsibility pattern: each object of the inheritance
|
||||
tree chains up to its parent (typically, at the beginning or the end of the method) to ensure that
|
||||
they each handler is run in turn.</para></listitem>
|
||||
</itemizedlist>
|
||||
I am personally not really convinced any of the last two uses are really a good idea but since this
|
||||
programming idiom is often used, this section attemps to explain how to implement it.
|
||||
programming idiom is often used, this section attempts to explain how to implement it.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
To explicitely chain up to the implementation of the virtual method in the parent class,
|
||||
To explicitly chain up to the implementation of the virtual method in the parent class,
|
||||
you first need a handle to the original parent class structure. This pointer can then be used to
|
||||
access the original class function pointer and invoke it directly.
|
||||
<footnote>
|
||||
@ -746,10 +746,10 @@ b_method_to_call (B *obj, int a)
|
||||
|
||||
|
||||
<chapter id="howto-interface">
|
||||
<title>How To define and implement Interfaces?</title>
|
||||
<title>How to define and implement interfaces</title>
|
||||
|
||||
<sect1 id="howto-interface-define">
|
||||
<title>How To define Interfaces?</title>
|
||||
<title>How to define interfaces</title>
|
||||
|
||||
<para>
|
||||
The bulk of interface definition has already been shown in <xref linkend="gtype-non-instantiable-classed"/>
|
||||
@ -814,7 +814,7 @@ void maman_ibaz_do_action (MamanIbaz *self);
|
||||
to make sure not to run the initialization code twice (as described in
|
||||
<xref linkend="gtype-non-instantiable-classed-init"/>,
|
||||
<function>base_init</function> is run once for each interface implementation
|
||||
instanciation)</para></listitem>
|
||||
instantiation)</para></listitem>
|
||||
<listitem><para><function>maman_ibaz_do_action</function> dereferences the class
|
||||
structure to access its associated class function and calls it.
|
||||
</para></listitem>
|
||||
@ -1089,7 +1089,7 @@ maman_bar_get_type (void)
|
||||
<title>Interface Properties</title>
|
||||
|
||||
<para>
|
||||
Starting from version 2.4 of glib, GObject interfaces can also have properties.
|
||||
Starting from version 2.4 of GLib, GObject interfaces can also have properties.
|
||||
Declaration of the interface properties is similar to declaring the properties of
|
||||
ordinary GObject types as explained in <xref linkend="gobject-properties"/>,
|
||||
except that <function><link linkend="g-object-interface-install-property">g_object_interface_install_property</link></function> is used to
|
||||
@ -1135,7 +1135,7 @@ maman_ibaz_base_init (gpointer g_iface)
|
||||
|
||||
<para>
|
||||
One point worth noting is that the declared property wasn't assigned an
|
||||
integer ID. The reason being that integer IDs of properities are utilized only
|
||||
integer ID. The reason being that integer IDs of properties are utilized only
|
||||
inside the get and set methods and since interfaces do not implement properties,
|
||||
there is no need to assign integer IDs to interface properties.
|
||||
</para>
|
||||
@ -1146,7 +1146,7 @@ maman_ibaz_base_init (gpointer g_iface)
|
||||
explained in <xref linkend="gobject-properties"/>, except for one small
|
||||
change: it shall declare the properties of the interface it implements using
|
||||
<function><link linkend="g-object-class-override-property">g_object_class_override_property</link></function> instead of
|
||||
<function><link linkend="g-object-class-install-property">g_object_class_install_property</link></function>. The following code snipet
|
||||
<function><link linkend="g-object-class-install-property">g_object_class_install_property</link></function>. The following code snippet
|
||||
shows the modifications needed in the <type>MamanBaz</type> declaration and
|
||||
implementation above:
|
||||
<programlisting>
|
||||
@ -1260,14 +1260,14 @@ maman_baz_get_property (GObject * object, guint prop_id,
|
||||
<!-- End Howto Interfaces -->
|
||||
|
||||
<chapter id="howto-signals">
|
||||
<title>Howto create and use signals</title>
|
||||
<title>How to create and use signals</title>
|
||||
|
||||
|
||||
<para>
|
||||
The signal system which was built in GType is pretty complex and flexible: it is possible for its users
|
||||
to connect at runtime any number of callbacks (implemented in any language for which a binding exists)
|
||||
<footnote>
|
||||
<para>A python callback can be connected to any signal on any C-based GObject.
|
||||
<para>A Python callback can be connected to any signal on any C-based GObject.
|
||||
</para>
|
||||
</footnote>
|
||||
|
||||
@ -1311,7 +1311,7 @@ klass->write_signal_id =
|
||||
0 /* n_params */,
|
||||
NULL /* param_types */);
|
||||
</programlisting>
|
||||
and the signal is emited in <function>maman_file_write</function>:
|
||||
and the signal is emitted in <function>maman_file_write</function>:
|
||||
<programlisting>
|
||||
void maman_file_write (MamanFile *self, guint8 *buffer, guint32 size)
|
||||
{
|
||||
@ -1330,7 +1330,7 @@ void maman_file_write (MamanFile *self, guint8 *buffer, guint32 size)
|
||||
The signature of the signal handler in the above example is defined as
|
||||
<function>g_cclosure_marshal_VOID__VOID</function>. Its name follows
|
||||
a simple convention which encodes the function parameter and return value
|
||||
types in the function name. Specifically, the value infront of the double
|
||||
types in the function name. Specifically, the value in front of the double
|
||||
underscore is the type of the return value, while the value(s) after the
|
||||
double underscore denote the parameter types.
|
||||
The header <filename>gobject/gmarshal.h</filename> defines a set of commonly
|
||||
@ -1357,7 +1357,7 @@ void maman_file_write (MamanFile *self, guint8 *buffer, guint32 size)
|
||||
<para>
|
||||
The first step to implement this idea is to change the signature of the signal: we need to pass
|
||||
around the buffer to write and its size. To do this, we use our own marshaller which will be generated
|
||||
through glib's genmarshall tool. We thus create a file named <filename>marshall.list</filename> which contains
|
||||
through GLib's genmarshall tool. We thus create a file named <filename>marshall.list</filename> which contains
|
||||
the following single line:
|
||||
<programlisting>
|
||||
VOID:POINTER,UINT
|
||||
@ -1488,11 +1488,11 @@ Complex Write event after: 0xbfffe280, 50
|
||||
there is a much <emphasis>simpler</emphasis>
|
||||
<footnote>
|
||||
<para>I personally think that this method is horribly mind-twisting: it adds a new indirection
|
||||
which unecessarily complicates the overall code path. However, because this method is widely used
|
||||
which unnecessarily complicates the overall code path. However, because this method is widely used
|
||||
by all of GTK+ and GObject code, readers need to understand it. The reason why this is done that way
|
||||
in most of GTK+ is related to the fact that the ancestor of GObject did not provide any other way to
|
||||
create a signal with a default handler than this one. Some people have tried to justify that it is done
|
||||
that way because it is better, faster (I am extremly doubtfull about the faster bit. As a matter of fact,
|
||||
that way because it is better, faster (I am extremely doubtful about the faster bit. As a matter of fact,
|
||||
the better bit also mystifies me ;-). I have the feeling no one really knows and everyone does it
|
||||
because they copy/pasted code from code which did the same. It is probably better to leave this
|
||||
specific trivia to hacker legends domain...
|
||||
@ -1527,7 +1527,7 @@ struct _MamanFileSimpleClass {
|
||||
void (*write) (MamanFileSimple *self, guint8 *buffer, guint size);
|
||||
};
|
||||
</programlisting>
|
||||
The <function>write</function> function pointer is initialied in the class_init function of the object
|
||||
The <function>write</function> function pointer is initialized in the class_init function of the object
|
||||
to <function>default_write_signal_handler</function>:
|
||||
<programlisting>
|
||||
static void
|
||||
@ -1565,7 +1565,7 @@ klass->write_signal_id =
|
||||
</para>
|
||||
|
||||
<para>
|
||||
While the complete code for this type of default handler looks less clutered as shown in
|
||||
While the complete code for this type of default handler looks less cluttered as shown in
|
||||
<filename>sample/signal/maman-file-simple.{h|c}</filename>, it contains numerous subtleties.
|
||||
The main subtle point which everyone must be aware of is that the signature of the default
|
||||
handler created that way does not have a user_data argument:
|
||||
@ -1600,7 +1600,7 @@ klass->write_signal_id =
|
||||
<itemizedlist>
|
||||
<listitem><para>stop the emission of the signal at anytime</para></listitem>
|
||||
<listitem><para>override the default handler of the signal if it is stored as a function
|
||||
pointer in the class structure (which is the prefered way to create a default signal handler,
|
||||
pointer in the class structure (which is the preferred way to create a default signal handler,
|
||||
as discussed in the previous section).</para></listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
|
@ -13,10 +13,10 @@
|
||||
</para>
|
||||
|
||||
<para>
|
||||
A lot of programmers are used to work with compiled-only or dynamically interpreted-only
|
||||
A lot of programmers are used to working with compiled-only or dynamically interpreted-only
|
||||
languages and do not understand the challenges associated with cross-language interoperability.
|
||||
This introduction tries to provide an insight into these challenges. describes briefly
|
||||
the solution choosen by GLib.
|
||||
This introduction tries to provide an insight into these challenges and briefly describes
|
||||
the solution chosen by GLib.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
@ -47,7 +47,7 @@
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Perl and Python which are interpreted languages do not really provide type definitions similar
|
||||
Perl and Python are interpreted languages which do not really provide type definitions similar
|
||||
to those used by C. Perl and Python programmers manipulate variables and the type of the variables
|
||||
is decided only upon the first assignment or upon the first use which forces a type on the variable.
|
||||
The interpreter also often provides a lot of automatic conversions from one type to the other. For example,
|
||||
@ -57,7 +57,7 @@
|
||||
my $tmp = 10;
|
||||
print "this is an integer converted to a string:" . $tmp . "\n";
|
||||
</programlisting>
|
||||
Of course, it is also often possible to explicitely specify conversions when the default conversions provided
|
||||
Of course, it is also often possible to explicitly specify conversions when the default conversions provided
|
||||
by the language are not intuitive.
|
||||
</para>
|
||||
|
||||
@ -79,12 +79,12 @@ print "this is an integer converted to a string:" . $tmp . "\n";
|
||||
function calling convention and the mapping of the C types to the machine types used by the platform you
|
||||
are on, you can resolve the name of each function to find where the code associated to this function
|
||||
is located in memory, and then construct a valid argument list for the function. Finally, all you have to
|
||||
do is triger a call to the target C function with the argument list.
|
||||
do is trigger a call to the target C function with the argument list.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
For the sake of discussion, here is a sample C function and the associated 32 bit x86
|
||||
assembly code generated by gcc on my linux box:
|
||||
assembly code generated by GCC on my Linux box:
|
||||
<programlisting>
|
||||
static void function_foo (int foo)
|
||||
{}
|
||||
@ -101,35 +101,35 @@ push $0xa
|
||||
call 0x80482f4 <function_foo>
|
||||
</programlisting>
|
||||
The assembly code shown above is pretty straightforward: the first instruction pushes
|
||||
the hexadecimal value 0xa (decimal value 10) as a 32 bit integer on the stack and calls
|
||||
the hexadecimal value 0xa (decimal value 10) as a 32-bit integer on the stack and calls
|
||||
<function>function_foo</function>. As you can see, C function calls are implemented by
|
||||
gcc by native function calls (this is probably the fastest implementation possible).
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Now, let's say we want to call the C function <function>function_foo</function> from
|
||||
a python program. To do this, the python interpreter needs to:
|
||||
a Python program. To do this, the Python interpreter needs to:
|
||||
<itemizedlist>
|
||||
<listitem><para>Find where the function is located. This means probably find the binary generated by the C compiler
|
||||
which exports this functions.</para></listitem>
|
||||
<listitem><para>Find where the function is located. This probably means finding the binary generated by the C compiler
|
||||
which exports this function.</para></listitem>
|
||||
<listitem><para>Load the code of the function in executable memory.</para></listitem>
|
||||
<listitem><para>Convert the python parameters to C-compatible parameters before calling
|
||||
<listitem><para>Convert the Python parameters to C-compatible parameters before calling
|
||||
the function.</para></listitem>
|
||||
<listitem><para>Call the function with the right calling convention</para></listitem>
|
||||
<listitem><para>Convert the return values of the C function to python-compatible
|
||||
variables to return them to the python code.</para></listitem>
|
||||
<listitem><para>Call the function with the right calling convention.</para></listitem>
|
||||
<listitem><para>Convert the return values of the C function to Python-compatible
|
||||
variables to return them to the Python code.</para></listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The process described above is pretty complex and there are a lot of ways to make it entirely automatic
|
||||
and transparent to the C and the Python programmers:
|
||||
and transparent to C and Python programmers:
|
||||
<itemizedlist>
|
||||
<listitem><para>The first solution is to write by hand a lot of glue code, once for each function exported or imported,
|
||||
which does the python to C parameter conversion and the C to python return value conversion. This glue code is then
|
||||
linked with the interpreter which allows python programs to call a python functions which delegates the work to the
|
||||
C function.</para></listitem>
|
||||
<listitem><para>Another nicer solution is to automatically generate the glue code, once for each function exported or
|
||||
which does the Python-to-C parameter conversion and the C-to-Python return value conversion. This glue code is then
|
||||
linked with the interpreter which allows Python programs to call Python functions which delegate work to
|
||||
C functions.</para></listitem>
|
||||
<listitem><para>Another, nicer solution is to automatically generate the glue code, once for each function exported or
|
||||
imported, with a special compiler which
|
||||
reads the original function signature.</para></listitem>
|
||||
<listitem><para>The solution used by GLib is to use the GType library which holds at runtime a description of
|
||||
|
@ -30,7 +30,7 @@
|
||||
Yet another tool that you may find helpful when working with
|
||||
GObjects is <ulink
|
||||
url="http://sourceforge.net/projects/g-inspector">G-Inspector</ulink>. It
|
||||
is able to display Glib/Gtk+ objects and their properties.
|
||||
is able to display GLib/GTK+ objects and their properties.
|
||||
</para>
|
||||
</chapter>
|
||||
|
||||
@ -47,8 +47,8 @@
|
||||
which can be used to automate the task of tracking down the location
|
||||
of invalid code with regard to reference counting. This application
|
||||
intercepts the reference counting calls and tries to detect invalid behavior.
|
||||
It suports a filter-rule mechanism to let you trace only the objects you are
|
||||
interested in and it can be used together with gdb.
|
||||
It supports a filter-rule mechanism to let you trace only the objects you are
|
||||
interested in and it can be used together with GDB.
|
||||
</para>
|
||||
<para>
|
||||
<indexterm><primary>g_trap_object_ref</primary></indexterm>
|
||||
@ -66,14 +66,14 @@ static volatile GObject *g_trap_object_ref;
|
||||
<chapter id="tools-gtkdoc">
|
||||
<title>Writing API docs</title>
|
||||
|
||||
<para>The API documentation for most of the Glib, GObject, GTK+ and GNOME
|
||||
<para>The API documentation for most of the GLib, GObject, GTK+ and GNOME
|
||||
libraries is built with a combination of complex tools. Typically, the part of
|
||||
the documentation which describes the behavior of each function is extracted
|
||||
from the specially-formatted source code comments by a tool named gtk-doc which
|
||||
generates docbook xml and merges this docbook xml with a set of master xml
|
||||
docbook files. These xml docbook files are finally processed with xsltproc
|
||||
(a small program part of the libxslt library) to generate the final html
|
||||
output. Other tools can be used to generate pdf output from the source xml.
|
||||
generates DocBook XML and merges this DocBook XML with a set of master XML
|
||||
DocBook files. These XML DocBook files are finally processed with xsltproc
|
||||
(a small program part of the libxslt library) to generate the final HTML
|
||||
output. Other tools can be used to generate PDF output from the source XML.
|
||||
The following code excerpt shows what these comments look like.
|
||||
<programlisting>
|
||||
/**
|
||||
@ -92,9 +92,9 @@ gtk_widget_freeze_child_notify (GtkWidget *widget)
|
||||
</programlisting>
|
||||
</para>
|
||||
<para>
|
||||
The great thoroughful
|
||||
Thorough
|
||||
<ulink url="http://developer.gnome.org/arch/doc/authors.html">documentation</ulink>
|
||||
on how to setup and use gtk-doc in your
|
||||
project is provided on the gnome developer website.
|
||||
on how to set up and use gtk-doc in your
|
||||
project is provided on the GNOME developer website.
|
||||
</para>
|
||||
</chapter>
|
||||
|
Loading…
x
Reference in New Issue
Block a user