OOP Using GObject (9) – A Dynamic Type

Recall there are 3 types in GObject type system: Fundamental, static and dynamic. A fundamental type is a top-most type which has no parent type. Most of them are pre-defined. Static types never load/unload its class type (say, their class struct) at runtime, since they are static. On the contrary, dynamic types can be dynamically loaded/unloaded at runtime. They are normally used within a module.

We can call g_type_register_dynamic() to register a dynamic type. When used in a module of GObject library (may be a GTypeModule type), We can also call g_type_module_register_type() to create your dynamic types. g_type_register_dynamic() is invoked for you in that function. Let’s go through the code:

NOTE: PLEASE READ ALL COMMENT CAREFULLY.

The implementation structure may be a little different with the stuff when creating a static type. An additional parameter GTypeModule is passed in. It represents the module your dynamic type belongs to. So, when the module is unloaded, all dynamic types in it are unaccessible.

Also note the bar_type_class_finalize() function. We use it to override the finalize() virtual function in GObjectClass. Now you can do un-initialiation in this function. It is like the destructor in a C++ class.

Let’s move on to the module type. This type inherits GTypeModule:

GTypeModule is an abstract type. We should implements its load() and unload() virtual function.

Our test code:

Another dynamic type BarType is defined in addition to FooType to demo the usage. The output maybe:

See the init/finalize process?

At the end of my note, Let me summarize to compare GObject library with C++ implementation:

1. Member Variables:

GObject C++
in class struct class meta info
in object struct class instance member
global variable class static member

2. Function Callbacks:

GObject C++
base_init init class dynamic meta info
base_finalize finalize dynamic class meta info, only dynamic types use it
class_init init class static meta info
class_finalize finalize class static meta info, only dynamic types use it
instance_init init instace, like C++ constructor
override finalize in GObjectClass finalize instance, like C++ destructor

All source code is available in my skydrive: http://cid-481cbe104492a3af.office.live.com/browse.aspx/share/dev/TestOO. In the TestGObject-{date}.zip/TestGObject7 folder.

OOP Using GObject (8) – An interface

Interfaces usage in library is like class usage. We need to define a interface struct, but no object struct is needed:

NOTE: PLEASE READ ALL COMMENT CAREFULLY.

Then we register the interface using g_type_register_static() with G_TYPE_INTERFACE as first parameter. For interfaces, we only need to assign base_init() and base_finalize()callbacks.

As described in the official document, we should allocate dynamic memebers of class struct in base_init(). Otherwise, all copies of the class struct share only one copy of dynamic members. This leads to problems.

Let’s define the type which implements the interface:

Note the naming convention I used here. Our FakeDesktop class will implement the FakeIServer interface and another FakeIClient interface. This time do not use corresponding interface struct as the first members of FakeDesktop and FakeDesktopClass. Interface info will be added dynamically when initialize a real instance of FakeDesktop. Let’s move to the *.c code:

Note the g_type_add_interface_static() function call to add interface info. The interface info is defined in a GInterfaceInfo struct. We just make use of the interface_init() callback. In it, we assign function pointers of corresponding interface to our implementation function. We can add multiple interface infos to implement them.

Finally, the test code:

In runtime, if your classed type implements an interface, it will be considered as the interface type (is-a).

All source code is available in my skydrive: http://cid-481cbe104492a3af.office.live.com/browse.aspx/share/dev/TestOO. In the TestGObject-{date}.zip/TestGObject6 folder.

OOP Using GObject (7) – Signals

Signals in GObject are used to support a event-driven programming. Signals can be connected to callback handlers. When they are emitted, these handlers are invoked. To add signals to a type, notice following lines of code:

NOTE: PLEASE READ ALL COMMENT CAREFULLY.

Like properties, signals can be inherited too. Use signals like:

The callback functions are defined simply like:

All source code is available in my skydrive: http://cid-481cbe104492a3af.office.live.com/browse.aspx/share/dev/TestOO. In the TestGObject-{date}.zip/TestGObject5 folder.

OOP Using GObject (6) – Properties

Properties are supported by the GObject library. To use it, you should override the set_property() and get_property() function in GObjectClass:

NOTE: PLEASE READ ALL COMMENT CAREFULLY.

All APIs are clear and easy to use, please refer to the official document. Last but not least, properties can be inherited by derived classes. Here’s my test code:

As you see, we can get/set properties one by one or using a parameter list.

All source code is available in my skydrive: http://cid-481cbe104492a3af.office.live.com/browse.aspx/share/dev/TestOO. In the TestGObject-{date}.zip/TestGObject5 folder.

OOP Using GObject (5) – Private Members

Here’s some trivial note on using GObject library.

1. Private members

Recall our definition of Base type:

NOTE: PLEASE READ ALL COMMENT CAREFULLY.

It expose the visibility of base_instance_i field. We should keep encapsulation in OOP. GObject library has support for this. We can define the class as:

We declare a new FakeBasePrivate struct to contain all private field used in FakeBase type. And the private struct is defined in *.c file, so its internal representation remains invisible. Then in *.c file, we got:

The private member is malloc in class_init() callback, and is ready to use after invoking instance_init(). When we will use property mechanism to get/set these private field later.

2. Naming convention

Official document: http://library.gnome.org/devel/gobject/stable/gtype-conventions.html. Just follow it to make your code more readable.

All source code is available in my skydrive: http://cid-481cbe104492a3af.office.live.com/browse.aspx/share/dev/TestOO. In the TestGObject-{date}.zip/TestGObject5 folder.

OOP Using GObject (4) – An Inheritable Class

Now, we will begin to implement some real OO mechanism using GObject library. In this article, we will make our fundamental type Inheritable.

Here’s comes our Base type:

NOTE: PLEASE READ ALL COMMENT CAREFULLY.

In base_instance_init(), we assigned the base_instance_dump() callback. Thus, we can invoke this function by both global function or instance function of BaseClass class. Additional flags G_TYPE_FLAG_DERIVABLE and G_TYPE_FLAG_DEEP_DERIVABLE are also passed to the GTypeFundamentalInfo struct to enable inheritance.

It’s time to define our Derived type:

Our Derived type inherits Base by replacing GTypeClass and GTypeInstance with the corresponding struct of the Base type. According to the memory layout of structs, GTypeClass and GTypeInstance are still the first member of corresponding struct. In derived_get_type(), we register Derived type using g_type_register_static() since it’s not a fundamental at all. And the first parameter is the type id of Base type.

Let’s have some time to look up how to implement polymorphism. In derived_class_init(), we re-assign the base_instance_dump() callback to from the Base‘s implementation to Derived‘s implementation.

Test code:

All source code is available in my skydrive: http://cid-481cbe104492a3af.office.live.com/browse.aspx/share/dev/TestOO. In the TestGObject-{date}.zip/TestGObject4 folder.

OOP Using GObject (3) – An Instantiatable Class

We will make fundamental type instantiatable and complete our first usage sample in this article. An object class should be defined firstly:

NOTE: PLEASE READ ALL COMMENT CAREFULLY.

Also, we re-define the class struct:

GTypeClass should be the first member of a class struct, while TypeInstance the first member of a object struct. You may wonder why there’s two int variable in both struct. The foo_class_i is like a static variable in C++ class, while The foo_instance_i is like an instance variable in C++ class. And remember fields in a class struct? It is used as meta info.

The registry function also need modification:

We assigned the instance_init() callback. It is called when a instance of our Foo class is created. You may ask where is the corresponding instance_finalize() callback? Hey, we will discuss it in upcoming articles. The instance_init() callback can be regarded as the constructor of a C++ class. Note, an additional G_TYPE_FLAG_INSTANTIATABLE flag is also added in the GTypeFundamentalInfo struct.

Let’s see how to create an instance:

Congratulations! You’ve finished the learning of our fundamental sample.

All source code is available in my skydrive: http://cid-481cbe104492a3af.office.live.com/browse.aspx/share/dev/TestOO. In the TestGObject-{date}.zip/TestGObject3 folder.

OOP Using GObject (2) – A Classed Type

In last article, we defined a fundamental type. But nothing can be done with it. Now, we will extend it to be a classed type, say adding class info into our fundamental type. To do this, we should define a class struct, which can be regard as the meta info of a C++ class:

NOTE: PLEASE READ ALL COMMENT CAREFULLY.

GTypeClass should be the first member of a class struct. You can image the i field to be the version of the class. And we can add a string field to hold the author of this class. There’s also a function pointer bar(). As you may already know, it is used to implement polymorphism, which can be regard as virtual function of a C++ class.

When registering our fundamental type, additional field in GTypeInfo and GTypeFundamentalInfo are filled:

GTypeInfo is the key data structure of GObject type system. It defines how a classed type should be initialized and finalized. Here, we just assigned the class_init() callback. It is called when our FooClass needs initialization. For fundamental and static types, their class_finalize() are never called. We will demo the usage of this callback when introducing dynamic types. Please also note the G_TYPE_FLAG_CLASSED flag passed into GTypeFundamentalInfo struct.

Now, let’s implement our foo_class_init() function. This function is used to initialize fields and assign virtual functions in most time:

Now, we’ve finished our definition of the class struct. Let’s see how to use it:

See? We use g_type_class_ref() and g_type_class_unref() to ref/unref a class, and invoke a function. But its function is still limited. We can just get/set its meta info. It still cannot be instantiated. This will be discussed in the next article.

All source code is available in my skydrive: http://cid-481cbe104492a3af.office.live.com/browse.aspx/share/dev/TestOO. In the TestGObject-{date}.zip/TestGObject2 folder.

OOP Using GObject (1) – A Fundamental Type

These days, I tried to write C code with OO support. I found GObject is such a well-designed library to simplify my implementation. However, the official documents is not so clear sometimes.  It do not provide sufficient information about all its stuff. I had to write my own demo applications to test the usage of some function. Moreover, the source code were also checked for reference.

There are 3 types in GObject type system: Fundamental, static and dynamic. Fundamental types are top-most types. The do not have parent types. They are seldom used, since all fundamental types are pre-defined rather than user-defined.

In this article, I will try to define a fundamental type using in GObject.Here’s the code on how to register a basic fundamental type in GObject, and how it can be used.

NOTE: PLEASE READ ALL COMMENT CAREFULLY.

My fundamental type is created by calling g_type_register_fundamental() function. A GTypeInfo and a GTypeFundamentalInfo struct are passed as parameters. And here comes the linux Makefile. You can use pkg-config to replace my include and lib paths:

NOTE: REPLACE THE WHITESPACE WITH TAB IN MAKEFILES, IF YOU COPY THE CODE DIRECTLY.

The fundamental type is of no use at all presently. In the next article, I will extend my code to add class meta info.

All source code is available in my skydrive: http://cid-481cbe104492a3af.office.live.com/browse.aspx/share/dev/TestOO. In the TestGObject-{date}.zip/TestGObject1 folder.