Implementing Vala interfaces in GObject/C ​
Vala interfaces behave much like Java or C#: classes can implement one or more of them. You are not required to implement those interfaces in Vala; a GObject type written in C can implement them as well. This walkthrough is adapted from the archived GNOME Wiki page Projects/Vala/MultiImplementInC.
Vala interface definitions ​
test-testone.vala:
namespace Test {
public interface TestOne {
public abstract void method_one ();
}
}test-testtwo.vala:
namespace Test {
public interface TestTwo {
public abstract void method_two ();
}
}Generate C headers and sources for the interfaces (and optionally compile the objects to verify your toolchain):
valac -C test-testone.vala
valac -C test-testtwo.vala
gcc -c test-testone.c $(pkg-config --cflags glib-2.0 gobject-2.0)
gcc -c test-testtwo.c $(pkg-config --cflags glib-2.0 gobject-2.0)C implementation (test-impl.c) ​
#include "test-impl.h"
static void
test_impl_finalize (GObject *object)
{
}
static void
test_impl_class_init (TestImplClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->finalize = test_impl_finalize;
}
static void
test_impl_init (TestImpl *self)
{
}
static void
test_impl_method_one (TestTestOne *self)
{
}
static void
test_impl_method_two (TestTestTwo *self)
{
}
static void
test_test_one_iface_init (TestTestOneIface *iface)
{
iface->method_one = test_impl_method_one;
}
static void
test_test_two_iface_init (TestTestTwoIface *iface)
{
iface->method_two = test_impl_method_two;
}
G_DEFINE_TYPE_WITH_CODE (TestImpl, test_impl, G_TYPE_OBJECT,
G_IMPLEMENT_INTERFACE (TEST_TYPE_TEST_ONE, test_test_one_iface_init)
G_IMPLEMENT_INTERFACE (TEST_TYPE_TEST_TWO, test_test_two_iface_init))C header (test-impl.h) ​
#ifndef __TEST_IMPL_H__
#define __TEST_IMPL_H__
#include <glib.h>
#include <glib-object.h>
G_BEGIN_DECLS
#define TEST_TYPE_IMPL (test_impl_get_type ())
#define TEST_IMPL(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), TEST_TYPE_IMPL, TestImpl))
#define TEST_IMPL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TEST_TYPE_IMPL, TestImplClass))
#define TEST_IS_IMPL(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), TEST_TYPE_IMPL))
#define TEST_IS_IMPL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TEST_TYPE_IMPL))
#define TEST_IMPL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TEST_TYPE_IMPL, TestImplClass))
typedef struct _TestImpl TestImpl;
typedef struct _TestImplClass TestImplClass;
struct _TestImpl {
GObject parent;
};
struct _TestImplClass {
GObjectClass parent_class;
};
GType test_impl_get_type (void);
TestImpl *test_impl_new (void);
G_END_DECLS
#endif /* __TEST_IMPL_H__ */Generating a VAPI for TestImpl ​
The wiki described using gen-introspect and vapigen from a Vala installation prefix. On current systems the tool names and paths differ; use the vapigen and GObject introspection utilities provided by your distribution’s Vala and gobject-introspection packages.
After generation, adjust the class declaration in test-impl.vapi so it lists the implemented interfaces:
public class Impl : GLib.Object, TestOne, TestTwo {If you prefer to author the VAPI by hand:
[CCode (cprefix = "Test", lower_case_cprefix = "test_")]
namespace Test {
[CCode (cheader_filename = "test-impl.h")]
public class Impl : GLib.Object, TestOne, TestTwo {
public Impl ();
}
[CCode (cheader_filename = "test-impl.h")]
public class ImplClass {
}
}Autotools sketch (Makefile.am) ​
The wiki included a Makefile.am fragment that runs valac -C on the Vala sources, links test-impl.c, and ships the hand-written test-impl.vapi. Modern projects more often use Meson or CMake instead of Automake; treat this as historical structure for the file list, not as a requirement.
Vala test program (tester.vala) ​
namespace Test {
public class Application {
public static int main (string[] args) {
var t = new Impl ();
t.method_one ();
t.method_two ();
return 0;
}
}
}Wire the generated interface C sources, test-impl.c, and the VAPI into one valac invocation (or your build system’s equivalent) so the linker sees every translation unit.
