Well, perhaps not exactly, but still -- I think it should work.
I've recently started poking around the GObject library, which is part of GLib. GObject is a C library aimed at providing OOP programmability that easily integrates with (usually) dynamic third-party languages. Basically, it allows you to write "glue" code between
$your_dynamic_language
and the GObject library just once, and then hook into any libraries created with GObject without writing further glue.A good, detailed tutorial is available here, which I've been working through. After getting the gist of something, I get itchy for some sample code to play around with. So I Googled and found this how-to. An older version of the documentation mentioned some sample code that I was never able to find.
After giving up on that, I decided that I should be able to use the tutorial to scrap together my own sample. The tutorial was pretty detailed, after all, and apparently referenced a sample that did (or does) exist somewhere. So that's what I did. I've created a fully functioning sample based more-or-less on the tutorial mentioned above. The code is below, with comments.
I have compiled this on my Ubuntu 8.10 and 9.04 machines using the following command:
gcc `pkg-config --libs gtk+-2.0` `pkg-config --cflags gtk+-2.0` maman-bar.c
maman-bar.h
/*
* Copyright/Licensing information.
*
* Reference:
*
* http://library.gnome.org/devel/gobject/unstable/howto-gobject.html
* http://library.gnome.org/devel/gobject/unstable/chapter-gobject.html
*
*
*/
/* inclusion guard */
#ifndef __MAMAN_BAR_H__
#define __MAMAN_BAR_H__
#include <glib-object.h>
/*
* Potentially, include other headers on which this header depends.
*/
/*
* Type macros.
*/
#define MAMAN_TYPE_BAR (maman_bar_get_type ())
#define MAMAN_BAR(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), MAMAN_TYPE_BAR, MamanBar))
#define MAMAN_IS_BAR(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), MAMAN_TYPE_BAR))
#define MAMAN_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), MAMAN_TYPE_BAR, MamanBarClass))
#define MAMAN_IS_BAR_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), MAMAN_TYPE_BAR))
#define MAMAN_BAR_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), MAMAN_TYPE_BAR, MamanBarClass))
typedef struct _MamanBar MamanBar;
typedef struct _MamanBarClass MamanBarClass;
/*
* Private instance fields
* Uses the Pimpl method:
*
* http://www.gotw.ca/gotw/024.htm
* http://www.gotw.ca/gotw/028.htm
*
*/
typedef struct _MamanBarPrivate MamanBarPrivate;
/* object */
struct _MamanBar
{
GObject parent_instance;
/* public */
int public_int;
/*< private >*/
MamanBarPrivate *priv;
};
/* class */
struct _MamanBarClass
{
GObjectClass parent_class;
/* class members */
/* Virtual public method */
void (*do_action_virt) (MamanBar *self, gchar *msg);
};
/*
* Non-virtual public method
*/
void maman_bar_do_action (MamanBar *self, gchar *msg /*, other params */);
/* Virtual method call declaration */
void maman_bar_do_action_virt (MamanBar *self, gchar *msg /*, other params */);
/* Virtual method default 'super' class method */
void maman_bar_do_action_virt_default (MamanBar *self, gchar *msg);
#endif /* __MAMAN_BAR_H__ */
maman-bar.c
#include "maman-bar.h"
/*
http://library.gnome.org/devel/gobject/2.21/gobject-Type-Information.html#G-DEFINE-TYPE--CAPS
A convenience macro for type implementations, which declares a class
initialization function, an instance initialization function (see GTypeInfo
for information about these) and a static variable named t_n_parent_class
pointing to the parent class. Furthermore, it defines a *_get_type()
function. See G_DEFINE_TYPE_EXTENDED() for an example.
*/
G_DEFINE_TYPE (MamanBar, maman_bar, G_TYPE_OBJECT);
/* Define the private structure in the .c file */
#define MAMAN_BAR_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), MAMAN_TYPE_BAR, MamanBarPrivate))
struct _MamanBarPrivate
{
int hsize;
gchar *msg;
};
/* Init functions */
static void
maman_bar_class_init (MamanBarClass *klass)
{
g_type_class_add_private (klass, sizeof (MamanBarPrivate));
/* Setup the default handler for virtual method */
klass->do_action_virt = maman_bar_do_action_virt_default;
}
static void
maman_bar_init (MamanBar *self)
{
g_print("maman_bar_init() - init object\n");
/* Initialize all public and private members to reasonable default values. */
/* Initialize public fields */
self->public_int = 99;
g_print(" initializing public_int to %d\n", self->public_int);
/* Initialize private fields */
MamanBarPrivate *priv;
self->priv = priv = MAMAN_BAR_GET_PRIVATE(self);
priv->hsize = 42;
g_print(" init'd private variable priv->hsize to %d\n", priv->hsize);
/* If you need specific construction properties to complete initialization,
* delay initialization completion until the property is set.
*/
}
/* Object non-virtual method */
void maman_bar_do_action (MamanBar *self, gchar *msg) {
/* First test that 'self' is of the correct type */
g_return_if_fail (MAMAN_IS_BAR (self));
// Assign to private 'msg'
self->priv->msg = msg;
g_print("maman_bar_do_action() - %s\n", self->priv->msg);
}
/* Object virtual method call - performs the override */
void maman_bar_do_action_virt (MamanBar *self, gchar *msg) {
/* First test that 'self' is of the correct type */
g_return_if_fail (MAMAN_IS_BAR (self));
g_print("maman_bar_do_action_virt() -> ");
MAMAN_BAR_GET_CLASS (self)->do_action_virt(self, msg);
}
/* Object virtual method default action (can be overridden) */
void maman_bar_do_action_virt_default (MamanBar *self, gchar *msg) {
g_print("maman_bar_do_action_virt_default() - %s\n", msg );
}
int
main (int argc, char *argv[])
{
/*
* Prior to any use of the type system, g_type_init() has to be called
* to initialize the type system and assorted other code portions
* (such as the various fundamental type implementations or the signal
* system).
*/
g_type_init();
/* Create our object */
MamanBar *bar = g_object_new (MAMAN_TYPE_BAR, NULL);
bar->public_int +=1;
g_print("incremented bar->public_int: %d\n", bar->public_int);
/* Call object method */
maman_bar_do_action(bar, "helowrld");
/* Call virtual object method - we could subclass and override... */
maman_bar_do_action_virt(bar, "HELOWRLD");
return 0;
}
And here's what I get when I run a.out:
ok ./a.outYou can download the source files directly from here.
maman_bar_init() - init object
initializing public_int to 99
init'd private variable priv->hsize to 42
incremented bar->public_int: 100
maman_bar_do_action() - helowrld
maman_bar_do_action_virt() -> maman_bar_do_action_virt_default() - HELOWRLD
Your working GObject example is a great help. I've been working on getting a small DBus/Glib demonstration together and this completed the picture for me. Many thanks!
ReplyDeleteMost welcome. :)
ReplyDeleteHello JA,
ReplyDeleteYour tutorial was VERY helpful for me, thank you:-)) I am trying though to implement the singleton as described here:
http://library.gnome.org/devel/gobject/unstable/gobject-The-Base-Object-Type.html#GObjectClass
but it does not behave as a singleton for me.
I do the following(pseudo-code):
single1 = g_object_new(MY_TYPE_SINGLE,...);
my_single_set_foo(single1, 10);
single2 = g_object_new(MY_TYPE_SINGLE...);
int foo = my_single_get_foo(single2);
but 'foo' is not 10.
do you have any idea?
cheers
simon:)
Great job! It really helped me! You could add some properties to demonstrate how they work though
ReplyDeleteI guess I *have* been ignoring the blog for a while. Sorry I didn't see the comments earlier.
ReplyDeletesimonbolek, I'm not entirely sure, but on first blush I'd say be certain that you're doing what they propose in Example 1 at the URL you provided, in the constructor function - maman_bar_init().
Line 15 of Example 1 should probably be something like:
the_singleton = MAMAN_BAR (object);
This doesn't work on linux mint for me..
ReplyDeletegcc `pkg-config --libs gtk+-2.0` `pkg-config --cflags gtk+-2.0` maman-bar.c
dies with a bunch of linker errors similar to this:
"undefined reference to `g_type_class_peek_parent'"
this does..
gcc `pkg-config --cflags gtk+-2.0` maman-bar.c `pkg-config --libs gtk+-2.0`
... for newbies.
Also thanks for putting the code up. I've found it quite fiddly to get right from the code snippets.
DeleteMod parent up!
Deletehi, I added a comment in
ReplyDeletehttps://bugzilla.gnome.org/show_bug.cgi?id=658766
hoping that your files may become part of the official tutorial