Friday, January 30, 2009

boilerplate

When I read a blog about boilerplate in Qt, I tried to remember how to write boilerplate code with Gobject. The following code is a frame that I took from 1 year ago I wrote. It is not really hard to understand or write, just need to copy & paste, or use simple tool to auto generate the code. It always need to write more lines in C (GObject) than using C++ for OO. But I don't feel the goodness. I am not feel that is the benifit of C, so I am not sure OO is really good for a Unix developer, so if I can avoid I would avoid the idea of OO in unix platform. (Linux Kernel is not written in OO)


/* macros*/
G_BEGIN_DECLS

#define GST_TYPE_MIDISRC (gst_my_midisrc_get_type())
#define GST_MIDISRC(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_MIDISRC,GstMidisrc))
#define GST_MIDISRC_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_MIDISRC,GstMidisrcClass))
#define GST_IS_MIDISRC(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_MIDISRC))
#define GST_IS_MIDISRC_CLASS(obj) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_MIDISRC))

/* standard function returning type information */
GType gst_my_midisrc_get_type (void);


/* definition a class of this element */
typedef struct _GstMidisrc GstMidisrc;
struct _GstMidisrc
{
GstBaseSrc parent;
[...]
};

typedef struct _GstMidisrcClass GstMidisrcClass;

struct _GstMidisrcClass
{
GstBaseSrcClass parent_class;
};

G_END_DECLS


Now we can make the boilerplate:

GST_BOILERPLATE (GstMidisrc, gst_my_midisrc, GstBaseSrc, GST_TYPE_BASE_SRC);


After that is the element details.


static GstElementDetails midisrc_details = {
"A Gstreamer Plug-in",
"Src/Audio",
"audio src for GStreamer Plug-in",
""
};

/* set detail with _base_init function when register the plugin */
static void
gst_my_midisrc_base_init (gpointer klass)
{
GstElementClass *element_class = GST_ELEMENT_CLASS (klass);

gst_element_class_add_pad_template (element_class, gst_static_pad_template_get (&src_factory));

gst_element_class_set_details (element_class, &midisrc_details);

}


Then implementation:



/* create the class, here we define which function need to be re-implmented from the base class, and add property for the class */
static void
gst_my_midisrc_class_init (GstMidisrcClass *klass)
{

GObjectClass *gobject_class;
GstBaseSrcClass *basesrc_class;
gobject_class = G_OBJECT_CLASS (klass);
basesrc_class = GST_BASE_SRC_CLASS (klass);
gobject_class->set_property = gst_midisrc_set_property;
gobject_class->get_property = gst_midisrc_get_property;


/* basesrc_class->get_caps = gst_midisrc_get_caps;
basesrc_class->set_caps = gst_midisrc_set_caps; */
basesrc_class->start = gst_midisrc_start;
basesrc_class->stop = gst_midisrc_stop;
basesrc_class->create = gst_midisrc_create;

/* install a property for the class as an example */
g_object_class_install_property (
gobject_class, ARG_LOCATION,
g_param_spec_string ("location", "File Location",
"Location of the file to read", NULL, G_PARAM_READWRITE));



}

/* create the object */
static void
gst_my_midisrc_init (GstMidisrc *midisrc, GstMidisrcClass *klass)
{
[...]
}



Now the reset part:


/* set property sample */
static gboolean
gst_midisrc_set_location (GstMidisrc * src, const gchar * location)
{
/* the element must be stopped in order to do this */
GST_STATE_LOCK (src);
{
GstState state;

state = GST_STATE (src);
if (state != GST_STATE_READY && state != GST_STATE_NULL)
goto wrong_state;
}
GST_STATE_UNLOCK (src);

g_free (src->filename);
g_free (src->uri);

/* clear the filename if we get a NULL (is that possible?) */
if (location == NULL) {
src->filename = NULL;
src->uri = NULL;
} else {
src->filename = g_strdup (location);
}
return TRUE;

/* ERROR */
wrong_state:
{
GST_DEBUG_OBJECT (src, "setting location in wrong state");
GST_STATE_UNLOCK (src);
return FALSE;
}
}
static void
gst_midisrc_set_property (GObject * object,
guint prop_id, const GValue * value, GParamSpec * pspec)
{
GstMidisrc *midisrc;
int tmp = 0;
g_return_if_fail (GST_IS_MIDISRC (object));
midisrc = GST_MIDISRC (object);

switch (prop_id) {
case ARG_LOCATION:
gst_midisrc_set_location(midisrc, g_value_get_string (value));
printf("set location done!\n");
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}

static void
gst_midisrc_get_property (GObject * object,
guint prop_id, GValue * value, GParamSpec * pspec)
{
GstMidisrc *midisrc;

g_return_if_fail (GST_IS_MIDISRC (object));
midisrc = GST_MIDISRC (object);

switch (prop_id) {
case ARG_LOCATION:
g_value_set_string(value, midisrc->filename);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}

static gboolean
gst_midisrc_start (GstBaseSrc * src)
{
GstMidisrc *midisrc = GST_MIDISRC (src);
[...]
}

static GstFlowReturn
gst_midisrc_create (GstBaseSrc * src,
guint64 offset,
guint length,
GstBuffer ** buffer)
{
GstMidisrc *midisrc = GST_MIDISRC (src);
if (midisrc->eos_reached)
return GST_FLOW_UNEXPECTED;
return( gst_midisrc_get_read (src, buffer));
}

static GstFlowReturn
gst_midisrc_get_read (GstBaseSrc * basesrc, GstBuffer ** buffer)
{
GstFlowReturn res;
GstMidisrc *midisrc = GST_MIDISRC (basesrc);
[...]

[...]
}


I would like to put my time on learning Git (I was heard git is written by a Unix kernal developer), for desktops, such as gnome or KDE I don't have a lot of interests, I may feel KDE is better since it is written in C++, but who knows.