Basic function calls and marshalling in PyGI
Booleans
gboolean
test_boolean (gboolean in)
{
return in;
}
In [2]: Everything.test_boolean(True) Out[2]: True In [3]: Everything.test_boolean(None) Out[3]: False
As you can see, not only exact booleans are accepted, but every Python object actually, since they all have a truth value.
Numbers
gint
test_int (gint in)
{
return in;
}
In [2]: Everything.test_int(42) Out[2]: 42 In [3]: class Number(object): ...: def __int__(self): ...: return 6*7 ...: In [4]: Everything.test_int(Number()) Out[4]: 42
The number protocol is supported.
8, 16, 32 and 64-bit integers, signed and unsigned are supported, along with float and double. They are all checked for overflow.
Strings
static const char utf8_const[] = "const \xe2\x99\xa5 utf8";
void
test_utf8_const_in (const char *in)
{
g_assert (strcmp (in, utf8_const) == 0);
}
G_CONST_RETURN char *
test_utf8_const_return (void)
{
return utf8_const;
}
In [2]: Everything.test_utf8_const_in('const ♥ utf8') In [3]: Everything.test_utf8_const_return() Out[3]: 'const \xe2\x99\xa5 utf8'
Strings must be Python string objects, not unicode ones.
Arrays
/**
* test_array_fixed_size_int_in:
* @ints: (array fixed-size=5) (transfer none):
*/
int
test_array_fixed_size_int_in (int *ints)
{
int i, sum = 0;
for (i = 0; i < 5; i++)
sum += ints[i];
return sum;
}
/**
* test_array_int_in:
* @n_ints:
* @ints: (array length=n_ints) (transfer none):
*/
int
test_array_int_in (int n_ints, int *ints)
{
int i, sum = 0;
for (i = 0; i < n_ints; i++)
sum += ints[i];
return sum;
}
/**
* test_strv_in:
* @arr: (array zero-terminated=1) (transfer none):
*/
gboolean
test_strv_in (char **arr)
{
if (g_strv_length (arr) != 3)
return FALSE;
if (strcmp (arr[0], "1") != 0)
return FALSE;
if (strcmp (arr[1], "2") != 0)
return FALSE;
if (strcmp (arr[2], "3") != 0)
return FALSE;
return TRUE;
}
/**
* test_array_fixed_size_int_return:
* Returns: (array fixed-size=5) (transfer full):
*/
int *
test_array_fixed_size_int_return (void)
{
int i, *ints;
ints = g_malloc0(sizeof(*ints) * 5);
for (i = 1; i < 5; i++)
ints[i] = ints[i-1] + 1;
return ints;
}
/**
* test_array_int_full_out:
* @len:
* Returns: (array length=len) (transfer full):
*/
int *
test_array_int_full_out (int *len)
{
int *result, i;
*len = 5;
result = g_malloc0(sizeof(*result) * (*len));
for (i=1; i < (*len); i++)
result[i] = result[i-1] + 1;
return result;
}
char **
test_strv_out (void)
{
int i = 0;
int n = 6;
char **ret = g_new (char *, n);
ret[i++] = g_strdup ("thanks");
ret[i++] = g_strdup ("for");
ret[i++] = g_strdup ("all");
ret[i++] = g_strdup ("the");
ret[i++] = g_strdup ("fish");
ret[i++] = NULL;
g_assert (i == n);
return ret;
}
In [2]: Everything.test_array_fixed_size_int_in((1, 2, 3, 4, -1)) Out[2]: 9 In [3]: Everything.test_array_int_in((1, 2, 3, -1)) Out[3]: 5 In [4]: class Sequence(object): ....: items = (1, 2, 3, -1) ....: def __len__(self): ....: return len(self.items) ....: def __getitem__(self, index): ....: return self.items[index] ....: In [5]: Everything.test_array_int_in(Sequence()) Out[5]: 5 In [6]: Everything.test_strv_in(('1', '2', '3')) Out[6]: True In [7]: Everything.test_array_fixed_size_int_return() Out[7]: (0, 1, 2, 3, 4) In [8]: Everything.test_array_int_full_out() Out[8]: (0, 1, 2, 3, 4) In [9]: Everything.test_strv_out() Out[9]: ('thanks', 'for', 'all', 'the', 'fish')
Any object that offers the sequence protocol is accepted.
Lists
static const char *test_sequence[] = {"1", "2", "3"};
/**
* test_glist_nothing_in:
* @in: (element-type utf8):
*/
void test_glist_nothing_in (const GList *in);
/**
* test_glist_everything_return:
* Returns: (element-type utf8) (transfer full):
*/
GList *test_glist_everything_return (void);
In [2]: Everything.test_glist_nothing_in(['1', '2', '3']) In [3]: Everything.test_glist_everything_return() Out[3]: ['1', '2', '3']
As for arrays, any object that offers the sequence protocol is accepted.
Hash tables
/**
* test_ghash_nothing_in:
* @in: (element-type utf8 utf8):
*/
void test_ghash_nothing_in (const GHashTable *in);
/**
* test_ghash_everything_return:
* Returns: (element-type utf8 utf8) (transfer full):
*/
GHashTable *test_ghash_everything_return (void);
In [2]: Everything.test_ghash_nothing_in({'foo': 'bar', 'baz': 'bat', 'qux': 'quux'}) In [3]: Everything.test_ghash_everything_return() Out[3]: {'baz': 'bat', 'foo': 'bar', 'qux': 'quux'}
Any object that implements the mapping protocol is accepted.
Generic values
/**
* test_value_arg:
* @v: (transfer none):
*/
int
test_int_value_arg (const GValue *v)
{
return g_value_get_int (v);
}
/**
* test_value_return:
* Returns: (transfer none):
*/
const GValue *
test_value_return (int i)
{
static GValue value;
memset (&value, '\0', sizeof(GValue));
g_value_init (&value, G_TYPE_INT);
g_value_set_int (&value, i);
return &value;
}
In [2]: Everything.test_int_value_arg(42) Out[2]: 42 In [3]: Everything.test_value_return(42) Out[3]: 42
Closures
int
test_closure_one_arg (GClosure *closure, int arg)
{
GValue return_value = {0, };
GValue arguments[1];
int ret;
g_value_init (&return_value, G_TYPE_INT);
memset (&arguments[0], 0, sizeof (arguments));
g_value_init (&arguments[0], G_TYPE_INT);
g_value_set_int (&arguments[0], arg);
g_closure_invoke (closure,
&return_value,
1, arguments,
NULL);
ret = g_value_get_int (&return_value);
g_value_unset(&return_value);
g_value_unset(&arguments[0]);
return ret;
}
In [2]: Everything.test_closure_one_arg(lambda x: 6 * x, 7) Out[2]: 42
Types
GType
test_gtype (GType in)
{
return in;
}
In [2]: import gobject In [3]: Everything.test_gtype(gobject.TYPE_INT) Out[3]: <GType gint (24)>
Other
Unions not supported yet.
Callbacks
/**
* test_simple_callback:
* @callback: (scope call) (allow-none):
*
**/
void
test_simple_callback (TestSimpleCallback callback)
{
if (callback != NULL)
callback();
return;
}
In [1]: import pygtk In [2]: pygtk.require('2.0') In [3]: from gi.repository import Everything In [4]: class TestCallback(): ...: called = False ...: def callback(self): ...: TestCallback.called = True ...: def test(self): ...: print TestCallback.called ...: Everything.test_simple_callback(self.callback) ...: print TestCallback.called ...: In [5]: t = TestCallback() In [6]: t.test() False True
Fancy function calls
Output arguments
/**
* test_utf8_out:
* @out: (out) (transfer full):
*/
void
test_utf8_out (char **out)
{
*out = g_strdup ("nonconst \xe2\x99\xa5 utf8");
}
/**
* test_utf8_out_out:
* @out0: (out) (transfer full):
* @out1: (out) (transfer full):
*/
void
test_utf8_out_out (char **out0, char **out1)
{
*out0 = g_strdup ("first");
*out1 = g_strdup ("second");
}
In [2]: Everything.test_utf8_out() Out[2]: 'nonconst \xe2\x99\xa5 utf8' In [3]: Everything.test_utf8_out_out() Out[3]: ('first', 'second')
Input and output arguments
/**
* test_utf8_inout:
* @inout: (inout) (transfer full):
*/
void
test_utf8_inout (char **inout)
{
g_assert (strcmp (*inout, "const \xe2\x99\xa5 utf8") == 0);
g_free(*inout);
*inout = g_strdup ("const \xe2\x99\xa5 utf8");
}
In [2]: Everything.test_utf8_inout('const ♥ utf8') Out[2]: 'nonconst \xe2\x99\xa5 utf8'
Return value and output arguments
/**
* test_utf8_out_nonconst_return:
* @out: (out) (transfer full):
* Returns: (transfer full):
*/
char *
test_utf8_out_nonconst_return (char **out)
{
*out = g_strdup ("second");
return g_strdup ("first");
}
In [2]: Everything.test_utf8_out_nonconst_return() Out[2]: ('first', 'second')
Nullable Arguments
/**
* test_ghash_null_in:
* @in: (element-type utf8 utf8) (allow-none):
*/
void test_ghash_null_in (const GHashTable *in)
{
g_assert (in == NULL);
}
/**
* test_ghash_null_out:
* @out: (element-type utf8 utf8) (allow-none) (out):
*/
void test_ghash_null_out (const GHashTable **out)
{
*out = NULL;
}
In [0]: Everything.test_ghash_null_in(None) In [1]: Everything.test_ghash_null_out() == None Out[1]: True
Other
Keyword arguments, default values are not supported yet.
Enumerations and flags
typedef enum
{
TEST_VALUE1,
TEST_VALUE2,
TEST_VALUE3 = 42
} TestEnum;
GType
test_enum_get_type (void)
{
static GType etype = 0;
if (G_UNLIKELY(etype == 0)) {
static const GEnumValue values[] = {
{ TEST_VALUE1, "TEST_VALUE1", "value1" },
{ TEST_VALUE2, "TEST_VALUE2", "value2" },
{ TEST_VALUE3, "TEST_VALUE3", "value3" },
{ 0, NULL, NULL }
};
etype = g_enum_register_static (g_intern_static_string ("TestEnum"), values);
}
return etype;
}
In [2]: Everything.TestEnum(42) Out[2]: <enum TEST_VALUE3 of type TestEnum> In [3]: Everything.TestEnum.VALUE3 Out[3]: <enum TEST_VALUE3 of type TestEnum> In [4]: int(Everything.TestEnum.VALUE3) Out[4]: 42
The same applies to flags.
Structures
typedef struct _TestStructA TestStructA;
typedef struct _TestStructB TestStructB;
struct _TestStructA
{
gint some_int;
gint8 some_int8;
gdouble some_double;
TestEnum some_enum;
};
void
test_struct_a_clone (TestStructA *a,
TestStructA *a_out)
{
*a_out = *a;
}
struct _TestStructB
{
gint8 some_int8;
TestStructA nested_a;
};
In [2]: a = Everything.TestStructA() In [3]: a.some_int = 42 In [4]: b = Everything.TestStructB() In [5]: a.clone(b.nested_a) In [6]: b.nested_a.some_int Out[6]: 42
Attention: Structures can be registered in the type system or not. If they are, they can be registered as boxed or pointer, and thus they'll inherit from either gobject.GBoxed or gobject.GPointer.
As any registered type, registered structures can be wrapped in generic values, and thus used in closures, signal callbacks, etc.
Arrays in structures aren't supported yet.
Interfaces
Interfaces are supported as subtypes of gobject.GInterface.
Since virtual functions are not supported yet, one cannot really implement an interface in Python.
Objects
#define TEST_TYPE_OBJ (test_obj_get_type ())
#define TEST_OBJECT(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), TEST_TYPE_OBJ, TestObj))
#define TEST_IS_OBJECT(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), TEST_TYPE_OBJ))
#define TEST_OBJ_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TEST_TYPE_OBJ, TestObjClass))
typedef struct _TestObj TestObj;
typedef struct _TestObjClass TestObjClass;
/**
* TestObj:
* @bare: (allow-none):
*/
struct _TestObj
{
GObject parent_instance;
GObject *bare;
TestBoxed *boxed;
};
struct _TestObjClass
{
GObjectClass parent_class;
int (*matrix) (TestObj *obj, const char *somestr);
guint test_signal;
guint test_signal_with_static_scope_arg;
};
GType test_obj_get_type (void);
TestObj* test_obj_new_from_file (const char *x, GError **error);
void test_obj_set_bare (TestObj *obj, GObject *bare);
int test_obj_instance_method (TestObj *obj);
double test_obj_static_method (int x);
int test_obj_do_matrix (TestObj *obj, const char *somestr);
In [2]: import gobject In [3]: issubclass(Everything.TestObj, gobject.GObject) Out[3]: True In [4]: Everything.TestObj.static_method(42) Out[4]: 42.0 In [5]: foo = Everything.TestObj('foo') In [6]: Everything.TestObj.new_from_file('bar') Out[6]: <TestObj object at 0x29072b0 (TestObj at 0x29050c0)> In [7]: foo.set_property('bare', Out[6]) In [8]: foo.bare Out[8]: <TestObj object at 0x29072b0 (TestObj at 0x29050c0)> In [9]: foo.instance_method() Out[9]: -1 In [10]: def cb(obj): .....: print 'Bip bip!' .....: In [11]: foo.connect('test', cb) Out[11]: 1L In [12]: foo.emit('test') Bip bip!
Virtual functions are not supported yet.
FIXME: The API shown above has slightly changed (the default constructur is always GObject's one, other constructors are still available as class methods).
Unions
Not supported yet.
Constants
Not supported yet.