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.

Attic/PyGI/Marshalling (last edited 2013-11-23 00:12:54 by WilliamJonMcCann)