summaryrefslogtreecommitdiff
path: root/gi
diff options
context:
space:
mode:
authorDongHun Kwak <dh0128.kwak@samsung.com>2017-07-12 08:35:42 +0900
committerDongHun Kwak <dh0128.kwak@samsung.com>2017-07-12 08:35:43 +0900
commitee96b8b4ed303ec374e37237f86555754cf2ae60 (patch)
tree6ad8344f0cf7f15b105be722ca87f77f16ee4c31 /gi
parentf29005349e245e146d416b2dc7a8f8a89a2e8a61 (diff)
downloadpygobject2-ee96b8b4ed303ec374e37237f86555754cf2ae60.tar.gz
pygobject2-ee96b8b4ed303ec374e37237f86555754cf2ae60.tar.bz2
pygobject2-ee96b8b4ed303ec374e37237f86555754cf2ae60.zip
Imported Upstream version 2.27.90
Change-Id: I23ecc791685b18ea66500f2af94287da6bec1436 Signed-off-by: DongHun Kwak <dh0128.kwak@samsung.com>
Diffstat (limited to 'gi')
-rw-r--r--gi/Makefile.am11
-rw-r--r--gi/Makefile.in19
-rw-r--r--gi/gimodule.c144
-rw-r--r--gi/module.py66
-rw-r--r--gi/overrides/GIMarshallingTests.py2
-rw-r--r--gi/overrides/GLib.py322
-rw-r--r--gi/overrides/Gdk.py50
-rw-r--r--gi/overrides/Gio.py99
-rw-r--r--gi/overrides/Gtk.py335
-rw-r--r--gi/overrides/Makefile.am6
-rw-r--r--gi/overrides/Makefile.in9
-rw-r--r--gi/overrides/Pango.py51
-rw-r--r--gi/overrides/__init__.py27
-rw-r--r--gi/pygi-argument.c180
-rw-r--r--gi/pygi-closure.c69
-rw-r--r--gi/pygi-foreign-cairo.c72
-rw-r--r--gi/pygi-foreign-gvariant.c4
-rw-r--r--gi/pygi-foreign-gvariant.h2
-rw-r--r--gi/pygi-foreign.c2
-rw-r--r--gi/pygi-info.c46
-rw-r--r--gi/pygi-invoke.c118
-rw-r--r--gi/pygi-invoke.h3
-rw-r--r--gi/pygi-property.c8
-rw-r--r--gi/pygi.h2
-rw-r--r--gi/repository/Makefile.am4
-rw-r--r--gi/repository/Makefile.in7
-rw-r--r--gi/types.py149
27 files changed, 1406 insertions, 401 deletions
diff --git a/gi/Makefile.am b/gi/Makefile.am
index 2fbb4ac..a98993b 100644
--- a/gi/Makefile.am
+++ b/gi/Makefile.am
@@ -1,7 +1,7 @@
PLATFORM_VERSION = 2.0
pkgincludedir = $(includedir)/pygtk-$(PLATFORM_VERSION)
-pkgpyexecdir = $(pyexecdir)/gtk-2.0
+pkgpyexecdir = $(pyexecdir)
SUBDIRS = \
repository \
@@ -24,7 +24,9 @@ _gi_la_LDFLAGS = \
-avoid-version \
-export-symbols-regex "init_gi|PyInit__gi"
_gi_la_LIBADD = \
- $(GI_LIBS)
+ $(GI_LIBS) \
+ $(PYTHON_LIBS) \
+ $(top_builddir)/glib/libpyglib-2.0-@PYTHON_BASENAME@.la
_gi_la_SOURCES = \
pygi-repository.c \
pygi-repository.h \
@@ -65,7 +67,8 @@ _gi_cairo_la_LDFLAGS = \
-export-symbols-regex "init_gi_cairo|PyInit__gi_cairo"
_gi_cairo_la_LIBADD = \
$(GI_LIBS) \
- $(PYCAIRO_LIBS)
+ $(PYCAIRO_LIBS) \
+ $(PYTHON_LIBS)
_gi_cairo_la_SOURCES = pygi-foreign-cairo.c
@@ -87,3 +90,5 @@ check-local: $(LTLIBRARIES:.la=.so)
clean-local:
rm -f $(LTLIBRARIES:.la=.so)
+
+-include $(top_srcdir)/git.mk
diff --git a/gi/Makefile.in b/gi/Makefile.in
index f0dd624..173abf6 100644
--- a/gi/Makefile.in
+++ b/gi/Makefile.in
@@ -73,7 +73,8 @@ am__base_list = \
am__installdirs = "$(DESTDIR)$(pygidir)" "$(DESTDIR)$(pygidir)"
LTLIBRARIES = $(pygi_LTLIBRARIES)
am__DEPENDENCIES_1 =
-_gi_la_DEPENDENCIES = $(am__DEPENDENCIES_1)
+_gi_la_DEPENDENCIES = $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) \
+ $(top_builddir)/glib/libpyglib-2.0-@PYTHON_BASENAME@.la
am__gi_la_OBJECTS = _gi_la-pygi-repository.lo _gi_la-pygi-info.lo \
_gi_la-pygi-invoke.lo _gi_la-pygi-foreign.lo \
_gi_la-pygi-foreign-gvariant.lo _gi_la-pygi-struct.lo \
@@ -89,7 +90,7 @@ _gi_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
$(LIBTOOLFLAGS) --mode=link $(CCLD) $(_gi_la_CFLAGS) $(CFLAGS) \
$(_gi_la_LDFLAGS) $(LDFLAGS) -o $@
_gi_cairo_la_DEPENDENCIES = $(am__DEPENDENCIES_1) \
- $(am__DEPENDENCIES_1)
+ $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1)
am__gi_cairo_la_OBJECTS = _gi_cairo_la-pygi-foreign-cairo.lo
_gi_cairo_la_OBJECTS = $(am__gi_cairo_la_OBJECTS)
_gi_cairo_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
@@ -228,6 +229,7 @@ LN_S = @LN_S@
LTLIBOBJS = @LTLIBOBJS@
MAINT = @MAINT@
MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
MKDIR_P = @MKDIR_P@
NM = @NM@
NMEDIT = @NMEDIT@
@@ -256,6 +258,7 @@ PYTHON = @PYTHON@
PYTHON_BASENAME = @PYTHON_BASENAME@
PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
PYTHON_INCLUDES = @PYTHON_INCLUDES@
+PYTHON_LIBS = @PYTHON_LIBS@
PYTHON_PLATFORM = @PYTHON_PLATFORM@
PYTHON_PREFIX = @PYTHON_PREFIX@
PYTHON_VERSION = @PYTHON_VERSION@
@@ -271,6 +274,7 @@ abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
abs_top_builddir = @abs_top_builddir@
abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
ac_ct_CC = @ac_ct_CC@
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
am__include = @am__include@
@@ -307,7 +311,7 @@ mandir = @mandir@
mkdir_p = @mkdir_p@
oldincludedir = @oldincludedir@
pdfdir = @pdfdir@
-pkgpyexecdir = $(pyexecdir)/gtk-2.0
+pkgpyexecdir = $(pyexecdir)
pkgpythondir = @pkgpythondir@
prefix = @prefix@
program_transform_name = @program_transform_name@
@@ -346,7 +350,9 @@ _gi_la_LDFLAGS = \
-export-symbols-regex "init_gi|PyInit__gi"
_gi_la_LIBADD = \
- $(GI_LIBS)
+ $(GI_LIBS) \
+ $(PYTHON_LIBS) \
+ $(top_builddir)/glib/libpyglib-2.0-@PYTHON_BASENAME@.la
_gi_la_SOURCES = \
pygi-repository.c \
@@ -390,7 +396,8 @@ _gi_cairo_la_LDFLAGS = \
_gi_cairo_la_LIBADD = \
$(GI_LIBS) \
- $(PYCAIRO_LIBS)
+ $(PYCAIRO_LIBS) \
+ $(PYTHON_LIBS)
_gi_cairo_la_SOURCES = pygi-foreign-cairo.c
pygi_LTLIBRARIES = _gi.la $(am__append_1)
@@ -995,6 +1002,8 @@ check-local: $(LTLIBRARIES:.la=.so)
clean-local:
rm -f $(LTLIBRARIES:.la=.so)
+-include $(top_srcdir)/git.mk
+
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:
diff --git a/gi/gimodule.c b/gi/gimodule.c
index f7624ae..f70d0f2 100644
--- a/gi/gimodule.c
+++ b/gi/gimodule.c
@@ -131,39 +131,25 @@ _wrap_pyg_register_interface_info (PyObject *self, PyObject *args)
Py_RETURN_NONE;
}
-static PyObject *
-_wrap_pyg_hook_up_vfunc_implementation (PyObject *self, PyObject *args)
+static void
+find_vfunc_info (GIBaseInfo *vfunc_info,
+ GType implementor_gtype,
+ gpointer *implementor_class_ret,
+ gpointer *implementor_vtable_ret,
+ GIFieldInfo **field_info_ret)
{
- PyGIBaseInfo *py_info;
- PyObject *py_type;
- PyObject *py_function;
- gpointer implementor_class = NULL;
GType ancestor_g_type = 0;
- GType implementor_gtype = 0;
- gpointer *method_ptr = NULL;
int length, i;
- GIBaseInfo *vfunc_info;
GIBaseInfo *ancestor_info;
GIStructInfo *struct_info;
+ gpointer implementor_class = NULL;
gboolean is_interface = FALSE;
- PyGICClosure *closure = NULL;
- if (!PyArg_ParseTuple (args, "O!O!O:hook_up_vfunc_implementation",
- &PyGIBaseInfo_Type, &py_info,
- &PyGTypeWrapper_Type, &py_type,
- &py_function))
- return NULL;
-
- implementor_gtype = pyg_type_from_object (py_type);
- g_assert (G_TYPE_IS_CLASSED (implementor_gtype));
-
- vfunc_info = py_info->info;
ancestor_info = g_base_info_get_container (vfunc_info);
is_interface = g_base_info_get_type (ancestor_info) == GI_INFO_TYPE_INTERFACE;
ancestor_g_type = g_registered_type_info_get_g_type (
(GIRegisteredTypeInfo *) ancestor_info);
-
implementor_class = g_type_class_ref (implementor_gtype);
if (is_interface) {
GTypeInstance *implementor_iface_class;
@@ -175,23 +161,23 @@ _wrap_pyg_hook_up_vfunc_implementation (PyObject *self, PyObject *args)
"Couldn't find GType of implementor of interface %s. "
"Forgot to set __gtype_name__?",
g_type_name (ancestor_g_type));
- return NULL;
+ return;
}
- g_type_class_unref (implementor_class);
- implementor_class = implementor_iface_class;
+ *implementor_vtable_ret = implementor_iface_class;
struct_info = g_interface_info_get_iface_struct ( (GIInterfaceInfo*) ancestor_info);
- } else
+ } else {
struct_info = g_object_info_get_class_struct ( (GIObjectInfo*) ancestor_info);
+ *implementor_vtable_ret = implementor_class;
+ }
+
+ *implementor_class_ret = implementor_class;
length = g_struct_info_get_n_fields (struct_info);
for (i = 0; i < length; i++) {
GIFieldInfo *field_info;
GITypeInfo *type_info;
- GIBaseInfo *interface_info;
- GICallbackInfo *callback_info;
- gint offset;
field_info = g_struct_info_get_field (struct_info, i);
@@ -202,18 +188,56 @@ _wrap_pyg_hook_up_vfunc_implementation (PyObject *self, PyObject *args)
}
type_info = g_field_info_get_type (field_info);
- if (g_type_info_get_tag (type_info) != GI_TYPE_TAG_INTERFACE) {
+ if (g_type_info_get_tag (type_info) == GI_TYPE_TAG_INTERFACE) {
g_base_info_unref (type_info);
- g_base_info_unref (field_info);
- continue;
+ *field_info_ret = field_info;
+ break;
}
+ g_base_info_unref (type_info);
+ g_base_info_unref (field_info);
+ }
+
+ g_base_info_unref (struct_info);
+}
+
+static PyObject *
+_wrap_pyg_hook_up_vfunc_implementation (PyObject *self, PyObject *args)
+{
+ PyGIBaseInfo *py_info;
+ PyObject *py_type;
+ PyObject *py_function;
+ GType implementor_gtype = 0;
+ gpointer implementor_class = NULL;
+ gpointer implementor_vtable = NULL;
+ GIFieldInfo *field_info = NULL;
+ gpointer *method_ptr = NULL;
+ PyGICClosure *closure = NULL;
+
+ if (!PyArg_ParseTuple (args, "O!O!O:hook_up_vfunc_implementation",
+ &PyGIBaseInfo_Type, &py_info,
+ &PyGTypeWrapper_Type, &py_type,
+ &py_function))
+ return NULL;
+
+ implementor_gtype = pyg_type_from_object (py_type);
+ g_assert (G_TYPE_IS_CLASSED (implementor_gtype));
+
+ find_vfunc_info (py_info->info, implementor_gtype, &implementor_class, &implementor_vtable, &field_info);
+ if (field_info != NULL) {
+ GITypeInfo *type_info;
+ GIBaseInfo *interface_info;
+ GICallbackInfo *callback_info;
+ gint offset;
+
+ type_info = g_field_info_get_type (field_info);
+
interface_info = g_type_info_get_interface (type_info);
g_assert (g_base_info_get_type (interface_info) == GI_INFO_TYPE_CALLBACK);
callback_info = (GICallbackInfo*) interface_info;
offset = g_field_info_get_offset (field_info);
- method_ptr = G_STRUCT_MEMBER_P (implementor_class, offset);
+ method_ptr = G_STRUCT_MEMBER_P (implementor_vtable, offset);
closure = _pygi_make_native_closure ( (GICallableInfo*) callback_info,
GI_SCOPE_TYPE_NOTIFIED, py_function, NULL);
@@ -223,17 +247,53 @@ _wrap_pyg_hook_up_vfunc_implementation (PyObject *self, PyObject *args)
g_base_info_unref (interface_info);
g_base_info_unref (type_info);
g_base_info_unref (field_info);
-
- break;
}
+ g_type_class_unref (implementor_class);
- g_base_info_unref (struct_info);
+ Py_RETURN_NONE;
+}
- if (!is_interface)
- g_type_class_unref (implementor_class);
+#if 0
+/* Not used, left around for future reference */
+static PyObject *
+_wrap_pyg_has_vfunc_implementation (PyObject *self, PyObject *args)
+{
+ PyGIBaseInfo *py_info;
+ PyObject *py_type;
+ PyObject *py_ret;
+ gpointer implementor_class = NULL;
+ gpointer implementor_vtable = NULL;
+ GType implementor_gtype = 0;
+ GIFieldInfo *field_info = NULL;
- Py_RETURN_NONE;
+ if (!PyArg_ParseTuple (args, "O!O!:has_vfunc_implementation",
+ &PyGIBaseInfo_Type, &py_info,
+ &PyGTypeWrapper_Type, &py_type))
+ return NULL;
+
+ implementor_gtype = pyg_type_from_object (py_type);
+ g_assert (G_TYPE_IS_CLASSED (implementor_gtype));
+
+ py_ret = Py_False;
+ find_vfunc_info (py_info->info, implementor_gtype, &implementor_class, &implementor_vtable, &field_info);
+ if (field_info != NULL) {
+ gpointer *method_ptr;
+ gint offset;
+
+ offset = g_field_info_get_offset (field_info);
+ method_ptr = G_STRUCT_MEMBER_P (implementor_vtable, offset);
+ if (*method_ptr != NULL) {
+ py_ret = Py_True;
+ }
+
+ g_base_info_unref (field_info);
+ }
+ g_type_class_unref (implementor_class);
+
+ Py_INCREF(py_ret);
+ return py_ret;
}
+#endif
static PyObject *
_wrap_pyg_variant_new_tuple (PyObject *self, PyObject *args)
@@ -258,7 +318,7 @@ _wrap_pyg_variant_new_tuple (PyObject *self, PyObject *args)
PyObject *value = PyTuple_GET_ITEM (py_values, i);
if (!PyObject_IsInstance (value, py_type)) {
- PyErr_Format (PyExc_TypeError, "argument %d is not a GLib.Variant", i);
+ PyErr_Format (PyExc_TypeError, "argument %" G_GSSIZE_FORMAT " is not a GLib.Variant", i);
return NULL;
}
@@ -315,11 +375,11 @@ PYGLIB_MODULE_START(_gi, "_gi")
PyObject *api;
if (pygobject_init (-1, -1, -1) == NULL) {
- return;
+ return PYGLIB_MODULE_ERROR_RETURN;
}
if (_pygobject_import() < 0) {
- return;
+ return PYGLIB_MODULE_ERROR_RETURN;
}
_pygi_repository_register_types (module);
@@ -330,7 +390,7 @@ PYGLIB_MODULE_START(_gi, "_gi")
api = PYGLIB_CPointer_WrapPointer ( (void *) &CAPI, "gi._API");
if (api == NULL) {
- return;
+ return PYGLIB_MODULE_ERROR_RETURN;
}
PyModule_AddObject (module, "_API", api);
}
diff --git a/gi/module.py b/gi/module.py
index c7b6557..9b935ed 100644
--- a/gi/module.py
+++ b/gi/module.py
@@ -82,14 +82,14 @@ class IntrospectionModule(object):
def __init__(self, namespace, version=None):
repository.require(namespace, version)
self._namespace = namespace
- self.version = version
+ self._version = version
self.__name__ = 'gi.repository.' + namespace
- repository.require(self._namespace, self.version)
+ repository.require(self._namespace, self._version)
self.__path__ = repository.get_typelib_path(self._namespace)
- if self.version is None:
- self.version = repository.get_version(self._namespace)
+ if self._version is None:
+ self._version = repository.get_version(self._namespace)
def __getattr__(self, name):
info = repository.find_by_name(self._namespace, name)
@@ -106,7 +106,7 @@ class IntrospectionModule(object):
wrapper = enum_add(g_type)
elif g_type.is_a(gobject.TYPE_NONE):
# An enum with a GType of None is an enum without GType
- wrapper = Enum
+ wrapper = type(info.get_name(), (Enum,), {})
else:
wrapper = flags_add(g_type)
@@ -114,8 +114,11 @@ class IntrospectionModule(object):
wrapper.__module__ = 'gi.repository.' + info.get_namespace()
for value_info in info.get_values():
- name = value_info.get_name().upper()
- setattr(wrapper, name, wrapper(value_info.get_value()))
+ value_name = value_info.get_name().upper()
+ setattr(wrapper, value_name, wrapper(value_info.get_value()))
+
+ if g_type != gobject.TYPE_NONE:
+ g_type.pytype = wrapper
elif isinstance(info, RegisteredTypeInfo):
g_type = info.get_g_type()
@@ -175,8 +178,17 @@ class IntrospectionModule(object):
return "<IntrospectionModule %r from %r>" % (self._namespace, path)
def __dir__ (self):
- attribs_list = repository.get_infos(self._namespace)
- return list(map(lambda x: x.get_name(), attribs_list))
+ # Python's default dir() is just dir(self.__class__) + self.__dict__.keys()
+ result = set(dir(self.__class__))
+ result.update(self.__dict__.keys())
+
+ # update *set* because some repository attributes have already been
+ # wrapped by __getattr__() and included in self.__dict__
+ namespace_infos = repository.get_infos(self._namespace)
+ result.update(info.get_name() for info in namespace_infos)
+
+ return list(result)
+
class DynamicGObjectModule(IntrospectionModule):
"""Wrapper for the GObject module
@@ -211,26 +223,27 @@ class DynamicGObjectModule(IntrospectionModule):
class DynamicModule(object):
def __init__(self, namespace):
self._namespace = namespace
- self.introspection_module = None
+ self._introspection_module = None
self._version = None
self._overrides_module = None
+ self.__path__ = None
def require_version(self, version):
- if self.introspection_module is not None and \
- self.introspection_module.version != version:
+ if self._introspection_module is not None and \
+ self._introspection_module._version != version:
raise RuntimeError('Module has been already loaded ')
self._version = version
def _import(self):
- self.introspection_module = IntrospectionModule(self._namespace,
- self._version)
+ self._introspection_module = IntrospectionModule(self._namespace,
+ self._version)
overrides_modules = __import__('gi.overrides', fromlist=[self._namespace])
self._overrides_module = getattr(overrides_modules, self._namespace, None)
self.__path__ = repository.get_typelib_path(self._namespace)
def __getattr__(self, name):
- if self.introspection_module is None:
+ if self._introspection_module is None:
self._import()
if self._overrides_module is not None:
@@ -247,9 +260,26 @@ class DynamicModule(object):
if key in registry:
return registry[key]
- return getattr(self.introspection_module, name)
+ return getattr(self._introspection_module, name)
def __dir__ (self):
+ if self._introspection_module is None:
+ self._import()
+
+ # Python's default dir() is just dir(self.__class__) + self.__dict__.keys()
+ result = set(dir(self.__class__))
+ result.update(self.__dict__.keys())
+
+ result.update(dir(self._introspection_module))
+ override_exports = getattr(self._overrides_module, '__all__', ())
+ result.update(override_exports)
+ return list(result)
+
+ def __repr__(self):
repository.require(self._namespace, self._version)
- attribs_list = repository.get_infos(self._namespace)
- return list(map(lambda x: x.get_name(), attribs_list))
+
+ path = repository.get_typelib_path(self._namespace)
+ return "<%s.%s %r from %r>" % (self.__class__.__module__,
+ self.__class__.__name__,
+ self._namespace,
+ path)
diff --git a/gi/overrides/GIMarshallingTests.py b/gi/overrides/GIMarshallingTests.py
index 25a882f..aac8883 100644
--- a/gi/overrides/GIMarshallingTests.py
+++ b/gi/overrides/GIMarshallingTests.py
@@ -21,7 +21,7 @@
from ..overrides import override
from ..importer import modules
-GIMarshallingTests = modules['GIMarshallingTests'].introspection_module
+GIMarshallingTests = modules['GIMarshallingTests']._introspection_module
__all__ = []
diff --git a/gi/overrides/GLib.py b/gi/overrides/GLib.py
index 78d8c35..ac783be 100644
--- a/gi/overrides/GLib.py
+++ b/gi/overrides/GLib.py
@@ -21,10 +21,21 @@
from ..importer import modules
from .._gi import variant_new_tuple, variant_type_from_string
-GLib = modules['GLib'].introspection_module
+GLib = modules['GLib']._introspection_module
__all__ = []
+def _create_variant(value):
+ '''Create a variant containing the variant "value".
+
+ This is usually done with the GLib.Variant.new_variant() leaf
+ constructor, but this is currently broken, see GNOME#639952.
+ '''
+ builder = GLib.VariantBuilder()
+ builder.init(variant_type_from_string('v'))
+ builder.add_value(value)
+ return builder.end()
+
class _VariantCreator(object):
_LEAF_CONSTRUCTORS = {
@@ -41,115 +52,242 @@ class _VariantCreator(object):
's': GLib.Variant.new_string,
'o': GLib.Variant.new_object_path,
'g': GLib.Variant.new_signature,
- 'v': GLib.Variant.new_variant,
+ #'v': GLib.Variant.new_variant,
+ 'v': _create_variant,
}
- def __init__(self, format_string, args):
- self._format_string = format_string
- self._args = args
+ def _create(self, format, args):
+ '''Create a GVariant object from given format and argument list.
- def create(self):
- if self._format_string_is_leaf():
- return self._new_variant_leaf()
+ This method recursively calls itself for complex structures (arrays,
+ dictionaries, boxed).
- format_char = self._pop_format_char()
- arg = self._pop_arg()
+ Return a tuple (variant, rest_format, rest_args) with the generated
+ GVariant, the remainder of the format string, and the remainder of the
+ arguments.
- if format_char == 'm':
- raise NotImplementedError()
- else:
- builder = GLib.VariantBuilder()
- if format_char == '(':
- builder.init(variant_type_from_string('r'))
- elif format_char == '{':
- builder.init(variant_type_from_string('{?*}'))
+ If args is None, then this won't actually consume any arguments, and
+ just parse the format string and generate empty GVariant structures.
+ This is required for creating empty dictionaries or arrays.
+ '''
+ # leaves (simple types)
+ constructor = self._LEAF_CONSTRUCTORS.get(format[0])
+ if constructor:
+ if args is not None:
+ if not args:
+ raise TypeError('not enough arguments for GVariant format string')
+ v = constructor(args[0])
+ return (constructor(args[0]), format[1:], args[1:])
else:
- raise NotImplementedError()
- format_char = self._pop_format_char()
- while format_char not in [')', '}']:
- builder.add_value(Variant(format_char, arg))
- format_char = self._pop_format_char()
- if self._args:
- arg = self._pop_arg()
- return builder.end()
-
- def _format_string_is_leaf(self):
- format_char = self._format_string[0]
- return not format_char in ['m', '(', '{']
-
- def _format_string_is_nnp(self):
- format_char = self._format_string[0]
- return format_char in ['a', 's', 'o', 'g', '^', '@', '*', '?', 'r',
- 'v', '&']
-
- def _new_variant_leaf(self):
- if self._format_string_is_nnp():
- return self._new_variant_nnp()
-
- format_char = self._pop_format_char()
- arg = self._pop_arg()
-
- return _VariantCreator._LEAF_CONSTRUCTORS[format_char](arg)
-
- def _new_variant_nnp(self):
- format_char = self._pop_format_char()
- arg = self._pop_arg()
-
- if format_char == '&':
- format_char = self._pop_format_char()
-
- if format_char == 'a':
- builder = GLib.VariantBuilder()
- builder.init(variant_type_from_string('a*'))
+ return (None, format[1:], None)
- element_format_string = self._pop_leaf_format_string()
+ if format[0] == '(':
+ return self._create_tuple(format, args)
- if isinstance(arg, dict):
- for element in arg.items():
- value = Variant(element_format_string, *element)
- builder.add_value(value)
- else:
- for element in arg:
- value = Variant(element_format_string, element)
- builder.add_value(value)
- return builder.end()
- elif format_char == '^':
- raise NotImplementedError()
- elif format_char == '@':
- raise NotImplementedError()
- elif format_char == '*':
- raise NotImplementedError()
- elif format_char == 'r':
- raise NotImplementedError()
- elif format_char == '?':
- raise NotImplementedError()
+ if format.startswith('a{'):
+ return self._create_dict(format, args)
+
+ if format[0] == 'a':
+ return self._create_array(format, args)
+
+ raise NotImplementedError('cannot handle GVariant type ' + format)
+
+ def _create_tuple(self, format, args):
+ '''Handle the case where the outermost type of format is a tuple.'''
+
+ format = format[1:] # eat the '('
+ builder = GLib.VariantBuilder()
+ builder.init(variant_type_from_string('r'))
+ if args is not None:
+ if not args or type(args[0]) != type(()):
+ raise (TypeError, 'expected tuple argument')
+
+ for i in range(len(args[0])):
+ if format.startswith(')'):
+ raise (TypeError, 'too many arguments for tuple signature')
+
+ (v, format, _) = self._create(format, args[0][i:])
+ builder.add_value(v)
+ args = args[1:]
+ return (builder.end(), format[1:], args)
+
+ def _create_dict(self, format, args):
+ '''Handle the case where the outermost type of format is a dict.'''
+
+ builder = GLib.VariantBuilder()
+ if args is None or not args[0]:
+ # empty value: we need to call _create() to parse the subtype,
+ # and specify the element type precisely
+ rest_format = self._create(format[2:], None)[1]
+ rest_format = self._create(rest_format, None)[1]
+ if not rest_format.startswith('}'):
+ raise ValueError('dictionary type string not closed with }')
+ rest_format = rest_format[1:] # eat the }
+ element_type = format[:len(format) - len(rest_format)]
+ builder.init(variant_type_from_string(element_type))
else:
- return _VariantCreator._LEAF_CONSTRUCTORS[format_char](arg)
+ builder.init(variant_type_from_string('a{?*}'))
+ for k, v in args[0].items():
+ (key_v, rest_format, _) = self._create(format[2:], [k])
+ (val_v, rest_format, _) = self._create(rest_format, [v])
- def _pop_format_char(self):
- format_char = self._format_string[0]
- self._format_string = self._format_string[1:]
- return format_char
+ if not rest_format.startswith('}'):
+ raise ValueError('dictionary type string not closed with }')
+ rest_format = rest_format[1:] # eat the }
- def _pop_leaf_format_string(self):
- # FIXME: This will break when the leaf is inside a tuple or dict entry
- format_string = self._format_string
- self._format_string = ''
- return format_string
+ entry = GLib.VariantBuilder()
+ entry.init(variant_type_from_string('{?*}'))
+ entry.add_value(key_v)
+ entry.add_value(val_v)
+ builder.add_value(entry.end())
- def _pop_arg(self):
- arg = self._args[0]
- self._args = self._args[1:]
- return arg
+ if args is not None:
+ args = args[1:]
+ return (builder.end(), rest_format, args)
+
+ def _create_array(self, format, args):
+ '''Handle the case where the outermost type of format is an array.'''
+
+ builder = GLib.VariantBuilder()
+ if args is None or not args[0]:
+ # empty value: we need to call _create() to parse the subtype,
+ # and specify the element type precisely
+ rest_format = self._create(format[1:], None)[1]
+ element_type = format[:len(format) - len(rest_format)]
+ builder.init(variant_type_from_string(element_type))
+ else:
+ builder.init(variant_type_from_string('a*'))
+ for i in range(len(args[0])):
+ (v, rest_format, _) = self._create(format[1:], args[0][i:])
+ builder.add_value(v)
+ if args is not None:
+ args = args[1:]
+ return (builder.end(), rest_format, args)
class Variant(GLib.Variant):
- def __new__(cls, format_string, *args):
- creator = _VariantCreator(format_string, args)
- return creator.create()
+ def __new__(cls, format_string, value):
+ '''Create a GVariant from a native Python object.
+
+ format_string is a standard GVariant type signature, value is a Python
+ object whose structure has to match the signature.
+
+ Examples:
+ GLib.Variant('i', 1)
+ GLib.Variant('(is)', (1, 'hello'))
+ GLib.Variant('(asa{sv})', ([], {'foo': GLib.Variant('b', True),
+ 'bar': GLib.Variant('i', 2)}))
+ '''
+ creator = _VariantCreator()
+ (v, rest_format, _) = creator._create(format_string, [value])
+ if rest_format:
+ raise TypeError('invalid remaining format string: "%s"' % rest_format)
+ return v
def __repr__(self):
return '<GLib.Variant(%s)>' % getattr(self, 'print')(True)
+ def unpack(self):
+ '''Decompose a GVariant into a native Python object.'''
+
+ LEAF_ACCESSORS = {
+ 'b': self.get_boolean,
+ 'y': self.get_byte,
+ 'n': self.get_int16,
+ 'q': self.get_uint16,
+ 'i': self.get_int32,
+ 'u': self.get_uint32,
+ 'x': self.get_int64,
+ 't': self.get_uint64,
+ 'h': self.get_handle,
+ 'd': self.get_double,
+ 's': self.get_string,
+ 'o': self.get_string, # object path
+ 'g': self.get_string, # signature
+ }
+
+ # simple values
+ la = LEAF_ACCESSORS.get(self.get_type_string())
+ if la:
+ return la()
+
+ # tuple
+ if self.get_type_string().startswith('('):
+ res = [self.get_child_value(i).unpack()
+ for i in range(self.n_children())]
+ return tuple(res)
+
+ # dictionary
+ if self.get_type_string().startswith('a{'):
+ res = {}
+ for i in range(self.n_children()):
+ v = self.get_child_value(i)
+ res[v.get_child_value(0).unpack()] = v.get_child_value(1).unpack()
+ return res
+
+ # array
+ if self.get_type_string().startswith('a'):
+ return [self.get_child_value(i).unpack()
+ for i in range(self.n_children())]
+
+ # variant (just unbox transparently)
+ if self.get_type_string().startswith('v'):
+ return self.get_variant().unpack()
+
+ raise NotImplementedError('unsupported GVariant type ' + self.get_type_string())
+
+ #
+ # Pythonic iterators
+ #
+ def __len__(self):
+ if self.get_type_string() in ['s', 'o', 'g']:
+ return len(self.get_string())
+ if self.get_type_string().startswith('a') or self.get_type_string().startswith('('):
+ return self.n_children()
+ raise TypeError('GVariant type %s does not have a length' % self.get_type_string())
+
+ def __getitem__(self, key):
+ # dict
+ if self.get_type_string().startswith('a{'):
+ try:
+ val = self.lookup_value(key, variant_type_from_string('*'))
+ if val is None:
+ raise KeyError(key)
+ return val.unpack()
+ except TypeError:
+ # lookup_value() only works for string keys, which is certainly
+ # the common case; we have to do painful iteration for other
+ # key types
+ for i in range(self.n_children()):
+ v = self.get_child_value(i)
+ if v.get_child_value(0).unpack() == key:
+ return v.get_child_value(1).unpack()
+ raise KeyError(key)
+
+ # array/tuple
+ if self.get_type_string().startswith('a') or self.get_type_string().startswith('('):
+ key = int(key)
+ if key < 0:
+ key = self.n_children() + key
+ if key < 0 or key >= self.n_children():
+ raise IndexError('list index out of range')
+ return self.get_child_value(key).unpack()
+
+ # string
+ if self.get_type_string() in ['s', 'o', 'g']:
+ return self.get_string().__getitem__(key)
+
+ raise TypeError('GVariant type %s is not a container' % self.get_type_string())
+
+ def keys(self):
+ if not self.get_type_string().startswith('a{'):
+ return TypeError, 'GVariant type %s is not a dictionary' % self.get_type_string()
+
+ res = []
+ for i in range(self.n_children()):
+ v = self.get_child_value(i)
+ res.append(v.get_child_value(0).unpack())
+ return res
+
@classmethod
def new_tuple(cls, *elements):
return variant_new_tuple(elements)
diff --git a/gi/overrides/Gdk.py b/gi/overrides/Gdk.py
index 08141d7..4ed71a6 100644
--- a/gi/overrides/Gdk.py
+++ b/gi/overrides/Gdk.py
@@ -22,7 +22,7 @@
from ..overrides import override
from ..importer import modules
-Gdk = modules['Gdk'].introspection_module
+Gdk = modules['Gdk']._introspection_module
__all__ = []
@@ -43,7 +43,7 @@ class Color(Gdk.Color):
Color = override(Color)
__all__.append('Color')
-if Gdk.version == '2.0':
+if Gdk._version == '2.0':
class Rectangle(Gdk.Rectangle):
def __init__(self, x, y, width, height):
@@ -62,12 +62,29 @@ if Gdk.version == '2.0':
Rectangle = override(Rectangle)
__all__.append('Rectangle')
-class Drawable(Gdk.Drawable):
- def cairo_create(self):
- return Gdk.cairo_create(self)
-
-Drawable = override(Drawable)
-__all__.append('Drawable')
+if Gdk._version == '2.0':
+ class Drawable(Gdk.Drawable):
+ def cairo_create(self):
+ return Gdk.cairo_create(self)
+
+ Drawable = override(Drawable)
+ __all__.append('Drawable')
+else:
+ class Window(Gdk.Window):
+ def __new__(cls, parent, attributes, attributes_mask):
+ # Gdk.Window had to be made abstract,
+ # this override allows using the standard constructor
+ return Gdk.Window.new(parent, attributes, attributes_mask)
+ def __init__(self, parent, attributes, attributes_mask):
+ pass
+ def cairo_create(self):
+ return Gdk.cairo_create(self)
+
+ Window = override(Window)
+ __all__.append('Window')
+
+Gdk.EventType._2BUTTON_PRESS = getattr(Gdk.EventType, "2BUTTON_PRESS")
+Gdk.EventType._3BUTTON_PRESS = getattr(Gdk.EventType, "3BUTTON_PRESS")
class Event(Gdk.Event):
_UNION_MEMBERS = {
@@ -76,8 +93,8 @@ class Event(Gdk.Event):
Gdk.EventType.EXPOSE: 'expose',
Gdk.EventType.MOTION_NOTIFY: 'motion',
Gdk.EventType.BUTTON_PRESS: 'button',
- #Gdk.EventType.2BUTTON_PRESS: 'button',
- #Gdk.EventType.3BUTTON_PRESS: 'button',
+ Gdk.EventType._2BUTTON_PRESS: 'button',
+ Gdk.EventType._3BUTTON_PRESS: 'button',
Gdk.EventType.BUTTON_RELEASE: 'button',
Gdk.EventType.KEY_PRESS: 'key',
Gdk.EventType.KEY_RELEASE: 'key',
@@ -101,9 +118,11 @@ class Event(Gdk.Event):
Gdk.EventType.DROP_FINISHED: 'dnd',
Gdk.EventType.CLIENT_EVENT: 'client',
Gdk.EventType.VISIBILITY_NOTIFY: 'visibility',
- Gdk.EventType.NO_EXPOSE: 'no_expose'
}
+ if Gdk._version == '2.0':
+ _UNION_MEMBERS[Gdk.EventType.NO_EXPOSE] = 'no_expose'
+
def __new__(cls, *args, **kwargs):
return Gdk.Event.__new__(cls)
@@ -112,11 +131,18 @@ class Event(Gdk.Event):
if real_event:
return getattr(getattr(self, real_event), name)
else:
- return getattr(self, name)
+ raise AttributeError("'%s' object has no attribute '%s'" % (self.__class__.__name__, name))
Event = override(Event)
__all__.append('Event')
+class DragContext(Gdk.DragContext):
+ def finish(self, success, del_, time):
+ Gtk = modules['Gtk']._introspection_module
+ Gtk.drag_finish(self, success, del_, time)
+
+DragContext = override(DragContext)
+__all__.append('DragContext')
import sys
diff --git a/gi/overrides/Gio.py b/gi/overrides/Gio.py
new file mode 100644
index 0000000..78affa2
--- /dev/null
+++ b/gi/overrides/Gio.py
@@ -0,0 +1,99 @@
+# -*- Mode: Python; py-indent-offset: 4 -*-
+# vim: tabstop=4 shiftwidth=4 expandtab
+#
+# Copyright (C) 2010 Ignacio Casal Quinteiro <icq@gnome.org>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+# USA
+
+from ..overrides import override
+from ..importer import modules
+
+from gi.repository import GLib
+
+Gio = modules['Gio']._introspection_module
+
+__all__ = []
+
+class FileEnumerator(Gio.FileEnumerator):
+ def __iter__(self):
+ return self
+
+ def __next__(self):
+ file_info = self.next_file(None)
+
+ if file_info is not None:
+ return file_info
+ else:
+ raise StopIteration
+
+ # python 2 compat for the iter protocol
+ next = __next__
+
+
+FileEnumerator = override(FileEnumerator)
+__all__.append('FileEnumerator')
+
+class Settings(Gio.Settings):
+ '''Provide dictionary-like access to GLib.Settings.'''
+
+ def __init__(self, schema, path=None, backend=None):
+ Gio.Settings.__init__(self, schema=schema, backend=backend, path=path)
+
+ def __contains__(self, key):
+ return key in self.list_keys()
+
+ def __len__(self):
+ return len(self.list_keys())
+
+ def __bool__(self):
+ # for "if mysettings" we don't want a dictionary-like test here, just
+ # if the object isn't None
+ return True
+
+ # alias for Python 2.x object protocol
+ __nonzero__ = __bool__
+
+ def __getitem__(self, key):
+ # get_value() aborts the program on an unknown key
+ if not key in self:
+ raise KeyError('unknown key: %r' % (key,))
+
+ return self.get_value(key).unpack()
+
+ def __setitem__(self, key, value):
+ # set_value() aborts the program on an unknown key
+ if not key in self:
+ raise KeyError('unknown key: %r' % (key,))
+
+ # determine type string of this key
+ range = self.get_range(key)
+ type_ = range.get_child_value(0).get_string()
+ v = range.get_child_value(1)
+ if type_ == 'type':
+ # v is boxed empty array, type of its elements is the allowed value type
+ type_str = v.get_child_value(0).get_type_string()
+ assert type_str.startswith('a')
+ type_str = type_str[1:]
+ else:
+ raise NotImplementedError('Cannot handle allowed type range class' + str(type_))
+
+ self.set_value(key, GLib.Variant(type_str, value))
+
+ def keys(self):
+ return self.list_keys()
+
+Settings = override(Settings)
+__all__.append('Settings')
diff --git a/gi/overrides/Gtk.py b/gi/overrides/Gtk.py
index a2f38ac..6c22829 100644
--- a/gi/overrides/Gtk.py
+++ b/gi/overrides/Gtk.py
@@ -21,7 +21,6 @@
import sys
import gobject
-from gi.repository import Gdk
from gi.repository import GObject
from ..overrides import override
from ..importer import modules
@@ -33,7 +32,7 @@ else:
_basestring = basestring
_callable = callable
-Gtk = modules['Gtk'].introspection_module
+Gtk = modules['Gtk']._introspection_module
__all__ = []
class Widget(Gtk.Widget):
@@ -49,6 +48,21 @@ __all__.append('Widget')
class Container(Gtk.Container, Widget):
+ def __len__(self):
+ return len(self.get_children())
+
+ def __contains__(self, child):
+ return child in self.get_children()
+
+ def __iter__(self):
+ return iter(self.get_children())
+
+ def __bool__(self):
+ return True
+
+ # alias for Python 2.x object protocol
+ __nonzero__ = __bool__
+
def get_focus_chain(self):
success, widgets = super(Container, self).get_focus_chain()
if success:
@@ -74,7 +88,24 @@ class Editable(Gtk.Editable):
Editable = override(Editable)
__all__.append("Editable")
+class Action(Gtk.Action):
+ def __init__(self, name, label, tooltip, stock_id, **kwds):
+ Gtk.Action.__init__(self, name=name, label=label, tooltip=tooltip, stock_id=stock_id, **kwds)
+
+Action = override(Action)
+__all__.append("Action")
+
+class RadioAction(Gtk.RadioAction):
+ def __init__(self, name, label, tooltip, stock_id, value, **kwds):
+ Gtk.RadioAction.__init__(self, name=name, label=label, tooltip=tooltip, stock_id=stock_id, value=value, **kwds)
+
+RadioAction = override(RadioAction)
+__all__.append("RadioAction")
+
class ActionGroup(Gtk.ActionGroup):
+ def __init__(self, name, **kwds):
+ super(ActionGroup, self).__init__(name = name, **kwds)
+
def add_actions(self, entries, user_data=None):
"""
The add_actions() method is a convenience method that creates a number
@@ -107,7 +138,7 @@ class ActionGroup(Gtk.ActionGroup):
raise TypeError('entries must be iterable')
def _process_action(name, stock_id=None, label=None, accelerator=None, tooltip=None, callback=None):
- action = Gtk.Action(name=name, label=label, tooltip=tooltip, stock_id=stock_id)
+ action = Action(name, label, tooltip, stock_id)
if callback is not None:
action.connect('activate', callback, user_data)
@@ -152,7 +183,7 @@ class ActionGroup(Gtk.ActionGroup):
raise TypeError('entries must be iterable')
def _process_action(name, stock_id=None, label=None, accelerator=None, tooltip=None, callback=None, is_active=False):
- action = Gtk.ToggleAction(name=name, label=label, tooltip=tooltip, stock_id=stock_id)
+ action = Gtk.ToggleAction(name, label, tooltip, stock_id)
action.set_active(is_active)
if callback is not None:
action.connect('activate', callback, user_data)
@@ -200,7 +231,7 @@ class ActionGroup(Gtk.ActionGroup):
first_action = None
def _process_action(group_source, name, stock_id=None, label=None, accelerator=None, tooltip=None, entry_value=0):
- action = Gtk.RadioAction(name=name, label=label, tooltip=tooltip, stock_id=stock_id, value=entry_value)
+ action = RadioAction(name, label, tooltip, stock_id, entry_value)
# FIXME: join_group is a patch to Gtk+ 3.0
# otherwise we can't effectively add radio actions to a
@@ -237,6 +268,9 @@ class UIManager(Gtk.UIManager):
return Gtk.UIManager.add_ui_from_string(self, buffer, length)
+ def insert_action_group(self, buffer, length=-1):
+ return Gtk.UIManager.insert_action_group(self, buffer, length)
+
UIManager = override(UIManager)
__all__.append('UIManager')
@@ -278,8 +312,7 @@ class Builder(Gtk.Builder):
else:
gobj.connect(signal_name, handler)
- self.connect_signals_full(_full_callback,
- obj_or_map);
+ self.connect_signals_full(_full_callback, obj_or_map)
def add_from_string(self, buffer):
if not isinstance(buffer, _basestring):
@@ -316,7 +349,7 @@ class Dialog(Gtk.Dialog, Container):
# keyword to work around this
if _buttons_property is not None:
kwds['buttons'] = _buttons_property
-
+
Gtk.Dialog.__init__(self, **kwds)
if title:
self.set_title(title)
@@ -380,6 +413,14 @@ class MessageDialog(Gtk.MessageDialog, Dialog):
**kwds)
Dialog.__init__(self, parent=parent, flags=flags)
+ def format_secondary_text(self, message_format):
+ self.set_property('secondary-use-markup', False)
+ self.set_property('secondary-text', message_format)
+
+ def format_secondary_markup(self, message_format):
+ self.set_property('secondary-use-markup', True)
+ self.set_property('secondary-text', message_format)
+
MessageDialog = override(MessageDialog)
__all__.append('MessageDialog')
@@ -409,9 +450,9 @@ class FileChooserDialog(Gtk.FileChooserDialog, Dialog):
Gtk.FileChooserDialog.__init__(self,
action=action,
**kwds)
- Dialog.__init__(self,
- title=title,
- parent=parent,
+ Dialog.__init__(self,
+ title=title,
+ parent=parent,
buttons=buttons)
FileChooserDialog = override(FileChooserDialog)
@@ -516,6 +557,12 @@ class TextBuffer(Gtk.TextBuffer):
self._get_or_create_tag_table().add(tag)
return tag
+ def create_mark(self, mark_name, where, left_gravity=False):
+ return Gtk.TextBuffer.create_mark(self, mark_name, where, left_gravity)
+
+ def set_text(self, text, length=-1):
+ Gtk.TextBuffer.set_text(self, text, length)
+
def insert(self, iter, text):
if not isinstance(text , _basestring):
raise TypeError('text must be a string, not %s' % type(text))
@@ -523,6 +570,32 @@ class TextBuffer(Gtk.TextBuffer):
length = len(text)
Gtk.TextBuffer.insert(self, iter, text, length)
+ def insert_with_tags(self, iter, text, *tags):
+ start_offset = iter.get_offset()
+ self.insert(iter, text)
+
+ if not tags:
+ return
+
+ start = self.get_iter_at_offset(start_offset)
+
+ for tag in tags:
+ self.apply_tag(tag, start, iter)
+
+ def insert_with_tags_by_name(self, iter, text, *tags):
+ if not tags:
+ return
+
+ tag_objs = []
+
+ for tag in tags:
+ tag_obj = self.get_tag_table().lookup(tag)
+ if not tag_obj:
+ raise ValueError('unknown text tag: %s' % tag)
+ tag_objs.append(tag_obj)
+
+ self.insert_with_tags(iter, text, *tag_objs)
+
def insert_at_cursor(self, text):
if not isinstance(text , _basestring):
raise TypeError('text must be a string, not %s' % type(text))
@@ -531,9 +604,11 @@ class TextBuffer(Gtk.TextBuffer):
Gtk.TextBuffer.insert_at_cursor(self, text, length)
def get_selection_bounds(self):
- success, start, end = super(TextBuffer, self).get_selection_bounds(string,
- flags, limit)
- return (start, end)
+ success, start, end = super(TextBuffer, self).get_selection_bounds()
+ if success:
+ return (start, end)
+ else:
+ return ()
TextBuffer = override(TextBuffer)
__all__.append('TextBuffer')
@@ -550,6 +625,15 @@ class TextIter(Gtk.TextIter):
flags, limit)
return (match_start, match_end,)
+ def begins_tag(self, tag=None):
+ return super(TextIter, self).begins_tag(tag)
+
+ def ends_tag(self, tag=None):
+ return super(TextIter, self).ends_tag(tag)
+
+ def toggles_tag(self, tag=None):
+ return super(TextIter, self).toggles_tag(tag)
+
TextIter = override(TextIter)
__all__.append('TextIter')
@@ -586,30 +670,14 @@ class TreeModel(Gtk.TreeModel):
return TreeModelRowIter(self, self.get_iter_first())
def get_iter(self, path):
- if isinstance(path, Gtk.TreePath):
- pass
- elif isinstance(path, (int, str,)):
- path = self._tree_path_from_string(str(path))
- elif isinstance(path, tuple):
- path_str = ":".join(str(val) for val in path)
- path = self._tree_path_from_string(path_str)
- else:
- raise TypeError("tree path must be one of Gtk.TreeIter, Gtk.TreePath, \
- int, str or tuple, not %s" % type(path).__name__)
+ if not isinstance(path, Gtk.TreePath):
+ path = TreePath(path)
success, aiter = super(TreeModel, self).get_iter(path)
if not success:
raise ValueError("invalid tree path '%s'" % path)
return aiter
- def _tree_path_from_string(self, path):
- if len(path) == 0:
- raise TypeError("could not parse subscript '%s' as a tree path" % path)
- try:
- return TreePath.new_from_string(path)
- except TypeError:
- raise TypeError("could not parse subscript '%s' as a tree path" % path)
-
def get_iter_first(self):
success, aiter = super(TreeModel, self).get_iter_first()
if success:
@@ -646,13 +714,64 @@ class TreeModel(Gtk.TreeModel):
# TODO: Accept a dictionary for row
# model.append(None,{COLUMN_ICON: icon, COLUMN_NAME: name})
- n_columns = self.get_n_columns();
+ n_columns = self.get_n_columns()
if len(row) != n_columns:
raise ValueError('row sequence has the incorrect number of elements')
for i in range(n_columns):
- if row[i] is not None:
- self.set_value(treeiter, i, row[i])
+ value = row[i]
+ self.set_value(treeiter, i, value)
+
+ def _convert_value(self, treeiter, column, value):
+ if value is None:
+ return
+
+ # we may need to convert to a basic type
+ type_ = self.get_column_type(column)
+ if type_ == gobject.TYPE_PYOBJECT:
+ pass # short-circut branching
+ elif type_ == gobject.TYPE_STRING:
+ if isinstance(value, str):
+ value = str(value)
+ elif sys.version_info < (3, 0):
+ if isinstance(value, unicode):
+ value = value.encode('UTF-8')
+ else:
+ raise ValueError('Expected string or unicode for column %i but got %s%s' % (column, value, type(value)))
+ else:
+ raise ValueError('Expected a string for column %i but got %s' % (column, type(value)))
+ elif type_ == gobject.TYPE_FLOAT or type_ == gobject.TYPE_DOUBLE:
+ if isinstance(value, float):
+ value = float(value)
+ else:
+ raise ValueError('Expected a float for column %i but got %s' % (column, type(value)))
+ elif type_ == gobject.TYPE_LONG or type_ == gobject.TYPE_INT:
+ if isinstance(value, int):
+ value = int(value)
+ elif sys.version_info < (3, 0):
+ if isinstance(value, long):
+ value = long(value)
+ else:
+ raise ValueError('Expected an long for column %i but got %s' % (column, type(value)))
+ else:
+ raise ValueError('Expected an integer for column %i but got %s' % (column, type(value)))
+
+ return value
+
+ def get(self, treeiter, *columns):
+ n_columns = self.get_n_columns()
+
+ values = []
+ for col in columns:
+ if not isinstance(col, int):
+ raise TypeError("column numbers must be ints")
+
+ if col < 0 or col >= n_columns:
+ raise ValueError("column number is out of range")
+
+ values.append(self.get_value(treeiter, col))
+
+ return tuple(values)
TreeModel = override(TreeModel)
__all__.append('TreeModel')
@@ -666,6 +785,12 @@ class TreeSortable(Gtk.TreeSortable, ):
else:
return (None, None,)
+ def set_sort_func(self, sort_column_id, sort_func, user_data=None):
+ super(TreeSortable, self).set_sort_func(sort_column_id, sort_func, user_data)
+
+ def set_default_sort_func(self, sort_func, user_data=None):
+ super(TreeSortable, self).set_default_sort_func(sort_func, user_data)
+
TreeSortable = override(TreeSortable)
__all__.append('TreeSortable')
@@ -698,7 +823,6 @@ class ListStore(Gtk.ListStore, TreeModel, TreeSortable):
return treeiter
-
def insert_after(self, sibling, row=None):
treeiter = Gtk.ListStore.insert_after(self, sibling)
@@ -707,6 +831,10 @@ class ListStore(Gtk.ListStore, TreeModel, TreeSortable):
return treeiter
+ def set_value(self, treeiter, column, value):
+ value = self._convert_value(treeiter, column, value)
+ Gtk.ListStore.set_value(self, treeiter, column, value)
+
ListStore = override(ListStore)
__all__.append('ListStore')
@@ -802,26 +930,39 @@ __all__.append('TreeModelRowIter')
class TreePath(Gtk.TreePath):
+ def __new__(cls, path=0):
+ if isinstance(path, int):
+ path = str(path)
+ elif isinstance(path, tuple):
+ path = ":".join(str(val) for val in path)
+
+ if len(path) == 0:
+ raise TypeError("could not parse subscript '%s' as a tree path" % path)
+ try:
+ return TreePath.new_from_string(path)
+ except TypeError:
+ raise TypeError("could not parse subscript '%s' as a tree path" % path)
+
def __str__(self):
return self.to_string()
def __lt__(self, other):
- return self.compare(other) < 0
+ return not other is None and self.compare(other) < 0
def __le__(self, other):
- return self.compare(other) <= 0
+ return not other is None and self.compare(other) <= 0
def __eq__(self, other):
- return self.compare(other) == 0
+ return not other is None and self.compare(other) == 0
def __ne__(self, other):
- return self.compare(other) != 0
+ return other is None or self.compare(other) != 0
def __gt__(self, other):
- return self.compare(other) > 0
+ return other is None or self.compare(other) > 0
def __ge__(self, other):
- return self.compare(other) >= 0
+ return other is None or self.compare(other) >= 0
TreePath = override(TreePath)
__all__.append('TreePath')
@@ -856,7 +997,6 @@ class TreeStore(Gtk.TreeStore, TreeModel, TreeSortable):
return treeiter
-
def insert_after(self, parent, sibling, row=None):
treeiter = Gtk.TreeStore.insert_after(self, parent, sibling)
@@ -865,6 +1005,10 @@ class TreeStore(Gtk.TreeStore, TreeModel, TreeSortable):
return treeiter
+ def set_value(self, treeiter, column, value):
+ value = self._convert_value(treeiter, column, value)
+ Gtk.TreeStore.set_value(self, treeiter, column, value)
+
TreeStore = override(TreeStore)
__all__.append('TreeStore')
@@ -881,6 +1025,32 @@ class TreeView(Gtk.TreeView, Container):
if success:
return (path, pos,)
+ def _construct_target_list(self, targets):
+ # FIXME: this should most likely be part of Widget or a global helper
+ # function
+ target_entries = []
+ for t in targets:
+ entry = Gtk.TargetEntry.new(*t)
+ target_entries.append(entry)
+ return target_entries
+
+ def enable_model_drag_source(self, start_button_mask, targets, actions):
+ target_entries = self._construct_target_list(targets)
+ super(TreeView, self).enable_model_drag_source(start_button_mask,
+ target_entries,
+ actions)
+
+ def enable_model_drag_dest(self, targets, actions):
+ target_entries = self._construct_target_list(targets)
+ super(TreeView, self).enable_model_drag_dest(target_entries,
+ actions)
+
+ def scroll_to_cell(self, path, column=None, use_align=False, row_align=0.0, col_align=0.0):
+ if not isinstance(path, Gtk.TreePath):
+ path = TreePath(path)
+ super(TreeView, self).scroll_to_cell(path, column, use_align, row_align, col_align)
+
+
TreeView = override(TreeView)
__all__.append('TreeView')
@@ -900,11 +1070,17 @@ class TreeViewColumn(Gtk.TreeViewColumn):
if success:
return (start_pos, width,)
+
TreeViewColumn = override(TreeViewColumn)
__all__.append('TreeViewColumn')
class TreeSelection(Gtk.TreeSelection):
+ def select_path(self, path):
+ if not isinstance(path, Gtk.TreePath):
+ path = TreePath(path)
+ super(TreeSelection, self).select_path(path)
+
def get_selected(self):
success, model, aiter = super(TreeSelection, self).get_selected()
if success:
@@ -912,11 +1088,17 @@ class TreeSelection(Gtk.TreeSelection):
else:
return (model, None)
+ # for compatibility with PyGtk
+ def get_selected_rows(self):
+ rows, model = super(TreeSelection, self).get_selected_rows()
+ return (model, rows)
+
+
TreeSelection = override(TreeSelection)
__all__.append('TreeSelection')
class Button(Gtk.Button, Container):
- def __init__(self, label=None, stock=None, use_underline=False):
+ def __init__(self, label=None, stock=None, use_underline=False, **kwds):
if stock:
label = stock
use_stock = True
@@ -924,11 +1106,72 @@ class Button(Gtk.Button, Container):
else:
use_stock = False
Gtk.Button.__init__(self, label=label, use_stock=use_stock,
- use_underline=use_underline)
+ use_underline=use_underline, **kwds)
Button = override(Button)
__all__.append('Button')
-import sys
+class LinkButton(Gtk.LinkButton):
+ def __init__(self, uri, label=None, **kwds):
+ Gtk.LinkButton.__init__(self, uri=uri, label=label, **kwds)
+
+LinkButton = override(LinkButton)
+__all__.append('LinkButton')
+
+class Label(Gtk.Label):
+ def __init__(self, label=None, **kwds):
+ Gtk.Label.__init__(self, label=label, **kwds)
+
+Label = override(Label)
+__all__.append('Label')
+
+class Adjustment(Gtk.Adjustment):
+ def __init__(self, *args, **kwds):
+ arg_names = ('value', 'lower', 'upper',
+ 'step_increment', 'page_increment', 'page_size')
+ new_args = dict(zip(arg_names, args))
+ new_args.update(kwds)
+ Gtk.Adjustment.__init__(self, **new_args)
+
+ # The value property is set between lower and (upper - page_size).
+ # Just in case lower, upper or page_size was still 0 when value
+ # was set, we set it again here.
+ if 'value' in new_args:
+ self.set_value(new_args['value'])
+
+Adjustment = override(Adjustment)
+__all__.append('Adjustment')
+
+class Table(Gtk.Table, Container):
+ def __init__(self, rows=1, columns=1, homogeneous=False, **kwds):
+ Gtk.Table.__init__(self, n_rows=rows, n_columns=columns, homogeneous=homogeneous, **kwds)
+
+ def attach(self, child, left_attach, right_attach, top_attach, bottom_attach, xoptions=Gtk.AttachOptions.EXPAND|Gtk.AttachOptions.FILL, yoptions=Gtk.AttachOptions.EXPAND|Gtk.AttachOptions.FILL, xpadding=0, ypadding=0):
+ Gtk.Table.attach(self, child, left_attach, right_attach, top_attach, bottom_attach, xoptions, yoptions, xpadding, ypadding)
+
+Table = override(Table)
+__all__.append('Table')
+
+class ScrolledWindow(Gtk.ScrolledWindow):
+ def __init__(self, hadjustment=None, vadjustment=None, **kwds):
+ Gtk.ScrolledWindow.__init__(self, hadjustment=hadjustment, vadjustment=vadjustment, **kwds)
+
+ScrolledWindow = override(ScrolledWindow)
+__all__.append('ScrolledWindow')
+
+class Paned(Gtk.Paned):
+ def pack1(self, child, resize=False, shrink=True):
+ super(Paned, self).pack1(child, resize, shrink)
+
+ def pack2(self, child, resize=True, shrink=True):
+ super(Paned, self).pack2(child, resize, shrink)
+
+Paned = override(Paned)
+__all__.append('Paned')
+
+_Gtk_main_quit = Gtk.main_quit
+@override(Gtk.main_quit)
+def main_quit(*args):
+ _Gtk_main_quit()
initialized, argv = Gtk.init_check(sys.argv)
sys.argv = list(argv)
diff --git a/gi/overrides/Makefile.am b/gi/overrides/Makefile.am
index b36c7a5..7a15b46 100644
--- a/gi/overrides/Makefile.am
+++ b/gi/overrides/Makefile.am
@@ -1,13 +1,17 @@
PLATFORM_VERSION = 2.0
-pkgpyexecdir = $(pyexecdir)/gtk-2.0/gi
+pkgpyexecdir = $(pyexecdir)/gi
pygioverridesdir = $(pkgpyexecdir)/overrides
pygioverrides_PYTHON = \
GLib.py \
Gtk.py \
Gdk.py \
+ Gio.py \
GIMarshallingTests.py \
+ Pango.py \
keysyms.py \
__init__.py
+
+-include $(top_srcdir)/git.mk
diff --git a/gi/overrides/Makefile.in b/gi/overrides/Makefile.in
index d0a78be..7ba6f5e 100644
--- a/gi/overrides/Makefile.in
+++ b/gi/overrides/Makefile.in
@@ -141,6 +141,7 @@ LN_S = @LN_S@
LTLIBOBJS = @LTLIBOBJS@
MAINT = @MAINT@
MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
MKDIR_P = @MKDIR_P@
NM = @NM@
NMEDIT = @NMEDIT@
@@ -169,6 +170,7 @@ PYTHON = @PYTHON@
PYTHON_BASENAME = @PYTHON_BASENAME@
PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
PYTHON_INCLUDES = @PYTHON_INCLUDES@
+PYTHON_LIBS = @PYTHON_LIBS@
PYTHON_PLATFORM = @PYTHON_PLATFORM@
PYTHON_PREFIX = @PYTHON_PREFIX@
PYTHON_VERSION = @PYTHON_VERSION@
@@ -184,6 +186,7 @@ abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
abs_top_builddir = @abs_top_builddir@
abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
ac_ct_CC = @ac_ct_CC@
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
am__include = @am__include@
@@ -220,7 +223,7 @@ mandir = @mandir@
mkdir_p = @mkdir_p@
oldincludedir = @oldincludedir@
pdfdir = @pdfdir@
-pkgpyexecdir = $(pyexecdir)/gtk-2.0/gi
+pkgpyexecdir = $(pyexecdir)/gi
pkgpythondir = @pkgpythondir@
prefix = @prefix@
program_transform_name = @program_transform_name@
@@ -242,7 +245,9 @@ pygioverrides_PYTHON = \
GLib.py \
Gtk.py \
Gdk.py \
+ Gio.py \
GIMarshallingTests.py \
+ Pango.py \
keysyms.py \
__init__.py
@@ -474,6 +479,8 @@ uninstall-am: uninstall-pygioverridesPYTHON
uninstall-pygioverridesPYTHON
+-include $(top_srcdir)/git.mk
+
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:
diff --git a/gi/overrides/Pango.py b/gi/overrides/Pango.py
new file mode 100644
index 0000000..3269806
--- /dev/null
+++ b/gi/overrides/Pango.py
@@ -0,0 +1,51 @@
+# -*- Mode: Python; py-indent-offset: 4 -*-
+# vim: tabstop=4 shiftwidth=4 expandtab
+#
+# Copyright (C) 2010 Paolo Borelli <pborelli@gnome.org>
+#
+# This library is free software; you can redistribute it and/or
+# modify it under the terms of the GNU Lesser General Public
+# License as published by the Free Software Foundation; either
+# version 2.1 of the License, or (at your option) any later version.
+#
+# This library is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+# Lesser General Public License for more details.
+#
+# You should have received a copy of the GNU Lesser General Public
+# License along with this library; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
+# USA
+
+from ..overrides import override
+from ..importer import modules
+
+Pango = modules['Pango']._introspection_module
+
+__all__ = []
+
+class FontDescription(Pango.FontDescription):
+
+ def __new__(cls, string=None):
+ if string is not None:
+ return Pango.font_description_from_string (string)
+ else:
+ return Pango.FontDescription.__new__(cls)
+
+FontDescription = override(FontDescription)
+__all__.append('FontDescription')
+
+class Layout(Pango.Layout):
+
+ def __new__(cls, context):
+ return Pango.Layout.new(context)
+
+ def __init__(self, context, **kwds):
+ # simply discard 'context', since it was set by
+ # __new__ and it is not a PangoLayout property
+ super(Layout, self).__init__(**kwds)
+
+Layout = override(Layout)
+__all__.append('Layout')
+
diff --git a/gi/overrides/__init__.py b/gi/overrides/__init__.py
index d4cd80b..a98974f 100644
--- a/gi/overrides/__init__.py
+++ b/gi/overrides/__init__.py
@@ -1,3 +1,6 @@
+import sys
+import types
+
import gobject
registry = None
@@ -34,10 +37,30 @@ class _Registry(dict):
def register(self, override_class):
self[override_class] = override_class
+
+class overridefunc(object):
+ '''decorator for overriding a function'''
+ def __init__(self, func):
+ if not hasattr(func, '__info__'):
+ raise TypeError("func must be an gi function")
+ from ..importer import modules
+ self.module = modules[func.__module__]._introspection_module
+
+ def __call__(self, func):
+ def wrapper(*args, **kwargs):
+ return func(*args, **kwargs)
+ wrapper.__name__ = func.__name__
+ setattr(self.module, func.__name__, wrapper)
+ return wrapper
+
registry = _Registry()
def override(type_):
'''Decorator for registering an override'''
- registry.register(type_)
- return type_
+ if type(type_) == types.FunctionType:
+ return overridefunc(type_)
+ else:
+ registry.register(type_)
+ return type_
+
diff --git a/gi/pygi-argument.c b/gi/pygi-argument.c
index b768e9e..8dd728d 100644
--- a/gi/pygi-argument.c
+++ b/gi/pygi-argument.c
@@ -188,6 +188,7 @@ _pygi_g_type_interface_check_object (GIBaseInfo *info,
for (i = 0; i < g_enum_info_get_n_values (info); i++) {
GIValueInfo *value_info = g_enum_info_get_value (info, i);
glong enum_value = g_value_info_get_value (value_info);
+ g_base_info_unref (value_info);
if (value == enum_value) {
retval = 1;
break;
@@ -271,8 +272,18 @@ _pygi_g_type_info_check_object (GITypeInfo *type_info,
case GI_TYPE_TAG_BOOLEAN:
/* No check; every Python object has a truth value. */
break;
- case GI_TYPE_TAG_INT8:
case GI_TYPE_TAG_UINT8:
+ /* UINT8 types can be characters */
+ if (PYGLIB_PyBytes_Check(object)) {
+ if (PYGLIB_PyBytes_Size(object) != 1) {
+ PyErr_Format (PyExc_TypeError, "Must be a single character");
+ retval = 0;
+ break;
+ }
+
+ break;
+ }
+ case GI_TYPE_TAG_INT8:
case GI_TYPE_TAG_INT16:
case GI_TYPE_TAG_UINT16:
case GI_TYPE_TAG_INT32:
@@ -368,9 +379,36 @@ check_number_release:
}
break;
}
+ case GI_TYPE_TAG_UNICHAR:
+ {
+ Py_ssize_t size;
+ if (PyUnicode_Check (object)) {
+ size = PyUnicode_GET_SIZE (object);
+#if PY_VERSION_HEX < 0x03000000
+ } else if (PyString_Check (object)) {
+ PyObject *pyuni = PyUnicode_FromEncodedObject (object, "UTF-8", "strict");
+ size = PyUnicode_GET_SIZE (pyuni);
+ Py_DECREF(pyuni);
+#endif
+ } else {
+ PyErr_Format (PyExc_TypeError, "Must be string, not %s",
+ object->ob_type->tp_name);
+ retval = 0;
+ break;
+ }
+
+ if (size != 1) {
+ PyErr_Format (PyExc_TypeError, "Must be a one character string, not %ld characters",
+ size);
+ retval = 0;
+ break;
+ }
+
+ break;
+ }
case GI_TYPE_TAG_UTF8:
case GI_TYPE_TAG_FILENAME:
- if (!PYGLIB_PyUnicode_Check (object)) {
+ if (!PYGLIB_PyBaseString_Check (object) ) {
PyErr_Format (PyExc_TypeError, "Must be string, not %s",
object->ob_type->tp_name);
retval = 0;
@@ -407,6 +445,10 @@ check_number_release:
item_type_info = g_type_info_get_param_type (type_info, 0);
g_assert (item_type_info != NULL);
+ /* FIXME: This is insain. We really should only check the first
+ * object and perhaps have a debugging mode. Large arrays
+ * will cause apps to slow to a crawl.
+ */
for (i = 0; i < length; i++) {
PyObject *item;
@@ -640,8 +682,13 @@ _pygi_argument_from_object (PyObject *object,
arg.v_boolean = PyObject_IsTrue (object);
break;
}
- case GI_TYPE_TAG_INT8:
case GI_TYPE_TAG_UINT8:
+ if (PYGLIB_PyBytes_Check(object)) {
+ arg.v_long = (long)(PYGLIB_PyBytes_AsString(object)[0]);
+ break;
+ }
+
+ case GI_TYPE_TAG_INT8:
case GI_TYPE_TAG_INT16:
case GI_TYPE_TAG_UINT16:
case GI_TYPE_TAG_INT32:
@@ -675,8 +722,7 @@ _pygi_argument_from_object (PyObject *object,
value = PyInt_AS_LONG (number);
} else
#endif
- if (PyLong_Check (number))
- value = PyLong_AsUnsignedLongLong (number);
+ value = PyLong_AsUnsignedLongLong (number);
arg.v_uint64 = value;
@@ -697,10 +743,9 @@ _pygi_argument_from_object (PyObject *object,
#if PY_VERSION_HEX < 0x03000000
if (PyInt_Check (number)) {
value = PyInt_AS_LONG (number);
- } else
-#endif
- if (PyLong_Check (number))
- value = PyLong_AsLongLong (number);
+ } else
+#endif
+ value = PyLong_AsLongLong (number);
arg.v_int64 = value;
@@ -742,6 +787,42 @@ _pygi_argument_from_object (PyObject *object,
break;
}
+ case GI_TYPE_TAG_UNICHAR:
+ {
+ gchar *string;
+
+ if (object == Py_None) {
+ arg.v_uint32 = 0;
+ break;
+ }
+
+#if PY_VERSION_HEX < 0x03000000
+ if (PyUnicode_Check(object)) {
+ PyObject *pystr_obj = PyUnicode_AsUTF8String (object);
+
+ if (!pystr_obj)
+ break;
+
+ string = g_strdup(PyString_AsString (pystr_obj));
+ Py_DECREF(pystr_obj);
+ } else {
+ string = g_strdup(PyString_AsString (object));
+ }
+#else
+ {
+ PyObject *pybytes_obj = PyUnicode_AsUTF8String (object);
+ if (!pybytes_obj)
+ break;
+
+ string = g_strdup(PyBytes_AsString (pybytes_obj));
+ Py_DECREF (pybytes_obj);
+ }
+#endif
+
+ arg.v_uint32 = g_utf8_get_char (string);
+
+ break;
+ }
case GI_TYPE_TAG_UTF8:
{
gchar *string;
@@ -751,7 +832,17 @@ _pygi_argument_from_object (PyObject *object,
break;
}
#if PY_VERSION_HEX < 0x03000000
- string = g_strdup(PyString_AsString (object));
+ if (PyUnicode_Check(object)) {
+ PyObject *pystr_obj = PyUnicode_AsUTF8String (object);
+
+ if (!pystr_obj)
+ break;
+
+ string = g_strdup(PyString_AsString (pystr_obj));
+ Py_DECREF(pystr_obj);
+ } else {
+ string = g_strdup(PyString_AsString (object));
+ }
#else
{
PyObject *pybytes_obj = PyUnicode_AsUTF8String (object);
@@ -830,6 +921,15 @@ _pygi_argument_from_object (PyObject *object,
break;
}
+ if (g_type_info_get_tag (item_type_info) == GI_TYPE_TAG_UINT8 &&
+ PYGLIB_PyBytes_Check(object)) {
+
+ memcpy(array->data, PYGLIB_PyBytes_AsString(object), length);
+ array->len = length;
+ goto array_success;
+ }
+
+
item_transfer = transfer == GI_TRANSFER_CONTAINER ? GI_TRANSFER_NOTHING : transfer;
for (i = 0; i < length; i++) {
@@ -862,6 +962,7 @@ array_item_error:
break;
}
+array_success:
arg.v_pointer = array;
g_base_info_unref ( (GIBaseInfo *) item_type_info);
@@ -1241,6 +1342,27 @@ _pygi_argument_to_object (GIArgument *arg,
object = pyg_type_wrapper_new ( (GType) arg->v_long);
break;
}
+ case GI_TYPE_TAG_UNICHAR:
+ {
+ /* Preserve the bidirectional mapping between 0 and "" */
+ if (arg->v_uint32 == 0) {
+ object = PYGLIB_PyUnicode_FromString ("");
+ } else if (g_unichar_validate (arg->v_uint32)) {
+ gchar utf8[6];
+ gint bytes;
+
+ bytes = g_unichar_to_utf8 (arg->v_uint32, utf8);
+ object = PYGLIB_PyUnicode_FromStringAndSize ((char*)utf8, bytes);
+ } else {
+ /* TODO: Convert the error to an exception. */
+ PyErr_Format (PyExc_TypeError,
+ "Invalid unicode codepoint %" G_GUINT32_FORMAT,
+ arg->v_uint32);
+ object = Py_None;
+ Py_INCREF (object);
+ }
+ break;
+ }
case GI_TYPE_TAG_UTF8:
if (arg->v_string == NULL) {
object = Py_None;
@@ -1282,23 +1404,36 @@ _pygi_argument_to_object (GIArgument *arg,
GITransfer item_transfer;
gsize i, item_size;
- if (arg->v_pointer == NULL) {
- object = PyList_New (0);
- break;
- }
-
array = arg->v_pointer;
- object = PyList_New (array->len);
- if (object == NULL) {
- break;
- }
-
item_type_info = g_type_info_get_param_type (type_info, 0);
g_assert (item_type_info != NULL);
item_type_tag = g_type_info_get_tag (item_type_info);
item_transfer = transfer == GI_TRANSFER_CONTAINER ? GI_TRANSFER_NOTHING : transfer;
+
+ if (item_type_tag == GI_TYPE_TAG_UINT8) {
+ /* Return as a byte array */
+ if (arg->v_pointer == NULL) {
+ object = PYGLIB_PyBytes_FromString ("");
+ break;
+ }
+
+ object = PYGLIB_PyBytes_FromStringAndSize(array->data, array->len);
+ break;
+
+ } else {
+ if (arg->v_pointer == NULL) {
+ object = PyList_New (0);
+ break;
+ }
+
+ object = PyList_New (array->len);
+ if (object == NULL) {
+ break;
+ }
+
+ }
item_size = g_array_get_element_size (array);
for (i = 0; i < array->len; i++) {
@@ -1375,6 +1510,8 @@ _pygi_argument_to_object (GIArgument *arg,
type = g_registered_type_info_get_g_type ( (GIRegisteredTypeInfo *) info);
if (g_type_is_a (type, G_TYPE_VALUE)) {
object = pyg_value_as_pyobject (arg->v_pointer, FALSE);
+ } else if (g_struct_info_is_foreign (info)) {
+ object = pygi_struct_foreign_convert_from_g_argument (type_info, arg->v_pointer);
} else if (g_type_is_a (type, G_TYPE_BOXED)) {
PyObject *py_type;
@@ -1398,8 +1535,6 @@ _pygi_argument_to_object (GIArgument *arg,
}
Py_XDECREF (py_type);
- } else if ( (type == G_TYPE_NONE) && (g_struct_info_is_foreign (info))) {
- object = pygi_struct_foreign_convert_from_g_argument (type_info, arg->v_pointer);
} else if (type == G_TYPE_NONE) {
PyObject *py_type;
@@ -1611,6 +1746,7 @@ _pygi_argument_release (GIArgument *arg,
case GI_TYPE_TAG_FLOAT:
case GI_TYPE_TAG_DOUBLE:
case GI_TYPE_TAG_GTYPE:
+ case GI_TYPE_TAG_UNICHAR:
break;
case GI_TYPE_TAG_FILENAME:
case GI_TYPE_TAG_UTF8:
diff --git a/gi/pygi-closure.c b/gi/pygi-closure.c
index 1e2ce05..33a8d81 100644
--- a/gi/pygi-closure.c
+++ b/gi/pygi-closure.c
@@ -27,6 +27,53 @@
*/
static GSList* async_free_list;
+static void
+_pygi_closure_assign_pyobj_to_out_argument (gpointer out_arg, PyObject *object,
+ GITypeInfo *type_info,
+ GITransfer transfer)
+{
+ GIArgument arg = _pygi_argument_from_object (object, type_info, transfer);
+ GITypeTag type_tag = g_type_info_get_tag (type_info);
+
+ switch (type_tag) {
+ case GI_TYPE_TAG_BOOLEAN:
+ *((gboolean *) out_arg) = arg.v_boolean;
+ break;
+ case GI_TYPE_TAG_INT8:
+ *((gint8 *) out_arg) = arg.v_int8;
+ break;
+ case GI_TYPE_TAG_UINT8:
+ *((guint8 *) out_arg) = arg.v_uint8;
+ break;
+ case GI_TYPE_TAG_INT16:
+ *((gint16 *) out_arg) = arg.v_int16;
+ break;
+ case GI_TYPE_TAG_UINT16:
+ *((guint16 *) out_arg) = arg.v_uint16;
+ break;
+ case GI_TYPE_TAG_INT32:
+ *((gint32 *) out_arg) = arg.v_int32;
+ break;
+ case GI_TYPE_TAG_UINT32:
+ *((guint32 *) out_arg) = arg.v_uint32;
+ break;
+ case GI_TYPE_TAG_INT64:
+ *((gint64 *) out_arg) = arg.v_int64;
+ break;
+ case GI_TYPE_TAG_UINT64:
+ *((glong *) out_arg) = arg.v_uint64;
+ break;
+ case GI_TYPE_TAG_FLOAT:
+ *((gfloat *) out_arg) = arg.v_float;
+ break;
+ case GI_TYPE_TAG_DOUBLE:
+ *((gdouble *) out_arg) = arg.v_double;
+ break;
+ default:
+ *((GIArgument *) out_arg) = arg;
+ break;
+ }
+}
static GIArgument *
_pygi_closure_convert_ffi_arguments (GICallableInfo *callable_info, void **args)
@@ -198,6 +245,7 @@ _pygi_closure_convert_arguments (GICallableInfo *callable_info, void **args,
if (_PyTuple_Resize (py_args, n_in_args) == -1)
goto error;
+ g_free (g_args);
return TRUE;
error:
@@ -225,15 +273,14 @@ _pygi_closure_set_out_arguments (GICallableInfo *callable_info,
return_type_info = g_callable_info_get_return_type (callable_info);
return_type_tag = g_type_info_get_tag (return_type_info);
if (return_type_tag != GI_TYPE_TAG_VOID) {
- GIArgument arg;
GITransfer transfer = g_callable_info_get_caller_owns (callable_info);
if (PyTuple_Check (py_retval)) {
PyObject *item = PyTuple_GET_ITEM (py_retval, 0);
- arg = _pygi_argument_from_object (item, return_type_info, transfer);
- * ( (GIArgument*) resp) = arg;
+ _pygi_closure_assign_pyobj_to_out_argument (resp, item,
+ return_type_info, transfer);
} else {
- arg = _pygi_argument_from_object (py_retval, return_type_info, transfer);
- * ( (GIArgument*) resp) = arg;
+ _pygi_closure_assign_pyobj_to_out_argument (resp, py_retval,
+ return_type_info, transfer);
}
i_py_retval++;
}
@@ -248,14 +295,14 @@ _pygi_closure_set_out_arguments (GICallableInfo *callable_info,
if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT) {
GITransfer transfer = g_arg_info_get_ownership_transfer (arg_info);
- GIArgument arg;
if (PyTuple_Check (py_retval)) {
PyObject *item = PyTuple_GET_ITEM (py_retval, i_py_retval);
- arg = _pygi_argument_from_object (item, type_info, transfer);
- * ( (GIArgument*) out_args[i_out_args].v_pointer) = arg;
+ _pygi_closure_assign_pyobj_to_out_argument (
+ out_args[i_out_args].v_pointer, item, type_info, transfer);
} else if (i_py_retval == 0) {
- arg = _pygi_argument_from_object (py_retval, type_info, transfer);
- * ( (GIArgument*) out_args[i_out_args].v_pointer) = arg;
+ _pygi_closure_assign_pyobj_to_out_argument (
+ out_args[i_out_args].v_pointer, py_retval, type_info,
+ transfer);
} else
g_assert_not_reached();
@@ -309,6 +356,8 @@ _pygi_closure_handle (ffi_cif *cif,
_pygi_closure_set_out_arguments (closure->info, retval, out_args, result);
end:
+ if (out_args != NULL)
+ g_free (out_args);
g_base_info_unref ( (GIBaseInfo*) return_type);
PyGILState_Release (state);
diff --git a/gi/pygi-foreign-cairo.c b/gi/pygi-foreign-cairo.c
index 6326397..0264b71 100644
--- a/gi/pygi-foreign-cairo.c
+++ b/gi/pygi-foreign-cairo.c
@@ -56,9 +56,9 @@ cairo_context_to_arg (PyObject *value,
}
PyObject *
-cairo_context_from_arg (GITypeInfo *type_info, GIArgument *arg)
+cairo_context_from_arg (GITypeInfo *type_info, gpointer data)
{
- cairo_t *context = (cairo_t*) arg;
+ cairo_t *context = (cairo_t*) data;
cairo_reference (context);
@@ -95,9 +95,9 @@ cairo_surface_to_arg (PyObject *value,
}
PyObject *
-cairo_surface_from_arg (GITypeInfo *type_info, GIArgument *arg)
+cairo_surface_from_arg (GITypeInfo *type_info, gpointer data)
{
- cairo_surface_t *surface = (cairo_surface_t*) arg;
+ cairo_surface_t *surface = (cairo_surface_t*) data;
cairo_surface_reference (surface);
@@ -112,65 +112,12 @@ cairo_surface_release (GIBaseInfo *base_info,
Py_RETURN_NONE;
}
-#ifdef PycairoRectangleInt_FromRectangleInt
-PyObject *
-cairo_rectangle_int_to_arg (PyObject *value,
- GITypeInfo *type_info,
- GITransfer transfer,
- GIArgument *arg)
-{
- cairo_rectangle_int_t *rect;
-
- rect = ( (PycairoRectangleInt *) value)->rectangle_int;
- if (!rect) {
- PyErr_SetString (PyExc_ValueError, "RectangleInt instance wrapping a NULL pointer");
- return NULL;
- }
-
- if (transfer == GI_TRANSFER_EVERYTHING) {
- unsigned int size = sizeof(cairo_rectangle_int_t);
- cairo_rectangle_int_t *transfer = malloc(size);
- if (!transfer) {
- PyErr_NoMemory();
- return NULL;
- }
-
- memcpy(transfer, rect, size);
- rect = transfer;
- }
-
- arg->v_pointer = rect;
- Py_RETURN_NONE;
-}
-
-PyObject *
-cairo_rectangle_int_from_arg (GITypeInfo *type_info, GIArgument *arg)
-{
- cairo_rectangle_int_t *rect = (cairo_rectangle_int_t*) arg;
-
- if (rect)
- return PycairoRectangleInt_FromRectangleInt (rect);
- else {
- cairo_rectangle_int_t temp = {};
- return PycairoRectangleInt_FromRectangleInt (&temp);
- }
-}
-
-PyObject *
-cairo_rectangle_int_release (GIBaseInfo *base_info,
- gpointer struct_)
-{
- g_free (struct_);
- Py_RETURN_NONE;
-}
-#endif
-
static PyMethodDef _gi_cairo_functions[] = {};
PYGLIB_MODULE_START(_gi_cairo, "_gi_cairo")
{
Pycairo_IMPORT;
if (Pycairo_CAPI == NULL)
- return 0;
+ return PYGLIB_MODULE_ERROR_RETURN;
pygi_register_foreign_struct ("cairo",
"Context",
@@ -183,14 +130,5 @@ PYGLIB_MODULE_START(_gi_cairo, "_gi_cairo")
cairo_surface_to_arg,
cairo_surface_from_arg,
cairo_surface_release);
-
-#ifdef PycairoRectangleInt_FromRectangleInt
- pygi_register_foreign_struct ("cairo",
- "RectangleInt",
- cairo_rectangle_int_to_arg,
- cairo_rectangle_int_from_arg,
- cairo_rectangle_int_release);
-#endif
-
}
PYGLIB_MODULE_END;
diff --git a/gi/pygi-foreign-gvariant.c b/gi/pygi-foreign-gvariant.c
index ac16395..3c8ae8d 100644
--- a/gi/pygi-foreign-gvariant.c
+++ b/gi/pygi-foreign-gvariant.c
@@ -42,9 +42,9 @@ g_variant_to_arg (PyObject *value,
PyObject *
g_variant_from_arg (GITypeInfo *type_info,
- GIArgument *arg)
+ gpointer data)
{
- GVariant *variant = (GVariant *) arg;
+ GVariant *variant = (GVariant *) data;
GITypeInfo *interface_info = g_type_info_get_interface (type_info);
PyObject *type = _pygi_type_import_by_gi_info (interface_info);
diff --git a/gi/pygi-foreign-gvariant.h b/gi/pygi-foreign-gvariant.h
index 6de8c57..b0c9781 100644
--- a/gi/pygi-foreign-gvariant.h
+++ b/gi/pygi-foreign-gvariant.h
@@ -32,7 +32,7 @@ PyObject *g_variant_to_arg(PyObject *value,
GIArgument *arg);
PyObject *g_variant_from_arg(GITypeInfo *type_info,
- GIArgument *arg);
+ gpointer data);
PyObject *g_variant_release_foreign (GIBaseInfo *base_info,
gpointer struct_);
diff --git a/gi/pygi-foreign.c b/gi/pygi-foreign.c
index 75d5bb9..5c9a88a 100644
--- a/gi/pygi-foreign.c
+++ b/gi/pygi-foreign.c
@@ -165,7 +165,7 @@ pygi_register_foreign_struct_real (const char* namespace_,
PyGIArgOverrideFromGIArgumentFunc from_func,
PyGIArgOverrideReleaseFunc release_func)
{
- PyGIForeignStruct *new_struct = g_slice_new0 (PyGIForeignStruct);
+ PyGIForeignStruct *new_struct = g_slice_new (PyGIForeignStruct);
new_struct->namespace = namespace_;
new_struct->name = name;
new_struct->to_func = to_func;
diff --git a/gi/pygi-info.c b/gi/pygi-info.c
index 33f71c1..f5dd69f 100644
--- a/gi/pygi-info.c
+++ b/gi/pygi-info.c
@@ -234,7 +234,45 @@ out:
/* CallableInfo */
PYGLIB_DEFINE_TYPE ("gi.CallableInfo", PyGICallableInfo_Type, PyGIBaseInfo);
+static PyObject *
+_wrap_g_callable_info_get_arguments (PyGIBaseInfo *self)
+{
+ gssize n_infos;
+ PyObject *infos;
+ gssize i;
+
+ n_infos = g_callable_info_get_n_args ( (GICallableInfo *) self->info);
+
+ infos = PyTuple_New (n_infos);
+ if (infos == NULL) {
+ return NULL;
+ }
+
+ for (i = 0; i < n_infos; i++) {
+ GIBaseInfo *info;
+ PyObject *py_info;
+
+ info = (GIBaseInfo *) g_callable_info_get_arg ( (GICallableInfo *) self->info, i);
+ g_assert (info != NULL);
+
+ py_info = _pygi_info_new (info);
+
+ g_base_info_unref (info);
+
+ if (py_info == NULL) {
+ Py_CLEAR (infos);
+ break;
+ }
+
+ PyTuple_SET_ITEM (infos, i, py_info);
+ }
+
+ return infos;
+}
+
static PyMethodDef _PyGICallableInfo_methods[] = {
+ { "invoke", (PyCFunction) _wrap_g_callable_info_invoke, METH_VARARGS | METH_KEYWORDS },
+ { "get_arguments", (PyCFunction) _wrap_g_callable_info_get_arguments, METH_NOARGS },
{ NULL, NULL, 0 }
};
@@ -349,6 +387,9 @@ _pygi_g_type_tag_size (GITypeTag type_tag)
case GI_TYPE_TAG_GTYPE:
size = sizeof (GType);
break;
+ case GI_TYPE_TAG_UNICHAR:
+ size = sizeof (gunichar);
+ break;
case GI_TYPE_TAG_VOID:
case GI_TYPE_TAG_UTF8:
case GI_TYPE_TAG_FILENAME:
@@ -388,6 +429,7 @@ _pygi_g_type_info_size (GITypeInfo *type_info)
case GI_TYPE_TAG_FLOAT:
case GI_TYPE_TAG_DOUBLE:
case GI_TYPE_TAG_GTYPE:
+ case GI_TYPE_TAG_UNICHAR:
if (g_type_info_is_pointer (type_info)) {
size = sizeof (gpointer);
} else {
@@ -472,7 +514,6 @@ _pygi_g_type_info_size (GITypeInfo *type_info)
static PyMethodDef _PyGIFunctionInfo_methods[] = {
{ "is_constructor", (PyCFunction) _wrap_g_function_info_is_constructor, METH_NOARGS },
{ "is_method", (PyCFunction) _wrap_g_function_info_is_method, METH_NOARGS },
- { "invoke", (PyCFunction) _wrap_g_function_info_invoke, METH_VARARGS },
{ NULL, NULL, 0 }
};
@@ -767,6 +808,7 @@ pygi_g_struct_info_is_simple (GIStructInfo *struct_info)
case GI_TYPE_TAG_UINT64:
case GI_TYPE_TAG_FLOAT:
case GI_TYPE_TAG_DOUBLE:
+ case GI_TYPE_TAG_UNICHAR:
if (g_type_info_is_pointer (field_type_info)) {
is_simple = FALSE;
}
@@ -1539,7 +1581,7 @@ _pygi_info_register_types (PyObject *m)
_PyGI_REGISTER_TYPE (m, PyGIFieldInfo_Type, FieldInfo,
PyGIBaseInfo_Type);
_PyGI_REGISTER_TYPE (m, PyGIVFuncInfo_Type, VFuncInfo,
- PyGIBaseInfo_Type);
+ PyGICallableInfo_Type);
_PyGI_REGISTER_TYPE (m, PyGIUnionInfo_Type, UnionInfo,
PyGIRegisteredTypeInfo_Type);
_PyGI_REGISTER_TYPE (m, PyGIBoxedInfo_Type, BoxedInfo,
diff --git a/gi/pygi-invoke.c b/gi/pygi-invoke.c
index 71d5859..c93442a 100644
--- a/gi/pygi-invoke.c
+++ b/gi/pygi-invoke.c
@@ -21,6 +21,7 @@
* USA
*/
+#include <pyglib.h>
#include "pygi-invoke.h"
struct invocation_state
@@ -58,19 +59,40 @@ struct invocation_state
GIArgument *backup_args;
GIArgument return_arg;
- PyObject *return_value;
+ PyObject *return_value;
+
+ GType implementor_gtype;
};
-static void
+static gboolean
_initialize_invocation_state (struct invocation_state *state,
GIFunctionInfo *info,
- PyObject *py_args)
+ PyObject *py_args,
+ PyObject *kwargs)
{
- GIFunctionInfoFlags flags;
+ if (g_base_info_get_type (info) == GI_INFO_TYPE_FUNCTION) {
+ GIFunctionInfoFlags flags = g_function_info_get_flags (info);
- flags = g_function_info_get_flags (info);
- state->is_method = (flags & GI_FUNCTION_IS_METHOD) != 0;
- state->is_constructor = (flags & GI_FUNCTION_IS_CONSTRUCTOR) != 0;
+ state->is_method = (flags & GI_FUNCTION_IS_METHOD) != 0;
+ state->is_constructor = (flags & GI_FUNCTION_IS_CONSTRUCTOR) != 0;
+ state->implementor_gtype = 0;
+ } else {
+ PyObject *obj;
+
+ state->is_method = TRUE;
+ state->is_constructor = FALSE;
+
+ obj = PyDict_GetItemString (kwargs, "gtype");
+ if (obj == NULL) {
+ PyErr_SetString (PyExc_TypeError,
+ "need the GType of the implementor class");
+ return FALSE;
+ }
+
+ state->implementor_gtype = pyg_type_from_object (obj);
+ if (state->implementor_gtype == 0)
+ return FALSE;
+ }
/* Count arguments. */
state->n_args = g_callable_info_get_n_args ( (GICallableInfo *) info);
@@ -98,6 +120,8 @@ _initialize_invocation_state (struct invocation_state *state,
state->out_args = NULL;
state->out_values = NULL;
state->backup_args = NULL;
+
+ return TRUE;
}
static gboolean
@@ -552,7 +576,7 @@ _prepare_invocation_state (struct invocation_state *state,
static gboolean
_invoke_function (struct invocation_state *state,
- GIFunctionInfo *function_info, PyObject *py_args)
+ GICallableInfo *callable_info, PyObject *py_args)
{
GError *error;
gint retval;
@@ -560,20 +584,28 @@ _invoke_function (struct invocation_state *state,
error = NULL;
pyg_begin_allow_threads;
- retval = g_function_info_invoke ( (GIFunctionInfo *) function_info,
- state->in_args,
- state->n_in_args,
- state->out_args,
- state->n_out_args,
- &state->return_arg,
- &error);
+ if (g_base_info_get_type (callable_info) == GI_INFO_TYPE_FUNCTION) {
+ retval = g_function_info_invoke ( (GIFunctionInfo *) callable_info,
+ state->in_args,
+ state->n_in_args,
+ state->out_args,
+ state->n_out_args,
+ &state->return_arg,
+ &error);
+ } else {
+ retval = g_vfunc_info_invoke ( (GIVFuncInfo *) callable_info,
+ state->implementor_gtype,
+ state->in_args,
+ state->n_in_args,
+ state->out_args,
+ state->n_out_args,
+ &state->return_arg,
+ &error);
+ }
pyg_end_allow_threads;
if (!retval) {
- g_assert (error != NULL);
- /* TODO: raise the right error, out of the error domain. */
- PyErr_SetString (PyExc_RuntimeError, error->message);
- g_error_free (error);
+ pyglib_error_check(&error);
/* TODO: release input arguments. */
@@ -585,11 +617,7 @@ _invoke_function (struct invocation_state *state,
error = state->args[state->error_arg_pos]->v_pointer;
- if (*error != NULL) {
- /* TODO: raise the right error, out of the error domain, if applicable. */
- PyErr_SetString (PyExc_Exception, (*error)->message);
- g_error_free (*error);
-
+ if (pyglib_error_check(error)) {
/* TODO: release input arguments. */
return FALSE;
@@ -672,6 +700,10 @@ _process_invocation_state (struct invocation_state *state,
/* The new wrapper increased the reference count, so decrease it. */
g_object_unref (state->return_arg.v_pointer);
}
+ if (state->is_constructor && G_IS_INITIALLY_UNOWNED (state->return_arg.v_pointer)) {
+ /* GInitiallyUnowned constructors always end up with one extra reference, so decrease it. */
+ g_object_unref (state->return_arg.v_pointer);
+ }
break;
default:
/* Other types don't have neither methods nor constructors. */
@@ -772,13 +804,16 @@ _process_invocation_state (struct invocation_state *state,
if (type_tag == GI_TYPE_TAG_INTERFACE) {
GIBaseInfo *info;
GIInfoType info_type;
+ GType type;
info = g_type_info_get_interface (state->arg_type_infos[i]);
g_assert (info != NULL);
info_type = g_base_info_get_type (info);
+ type = g_registered_type_info_get_g_type ( (GIRegisteredTypeInfo *) info);
if ( (info_type == GI_INFO_TYPE_STRUCT) &&
- !g_struct_info_is_foreign((GIStructInfo *) info) ) {
+ !g_struct_info_is_foreign((GIStructInfo *) info) &&
+ !g_type_is_a (type, G_TYPE_BOXED)) {
if (g_arg_info_is_caller_allocates (state->arg_infos[i])) {
transfer = GI_TRANSFER_EVERYTHING;
} else if (transfer == GI_TRANSFER_EVERYTHING) {
@@ -846,9 +881,7 @@ _free_invocation_state (struct invocation_state *state)
continue;
}
- if (state->args != NULL
- && state->args[i] != NULL
- && state->arg_infos[i] != NULL
+ if (state->arg_infos[i] != NULL
&& state->arg_type_infos[i] != NULL) {
GIDirection direction;
GITypeTag type_tag;
@@ -857,20 +890,25 @@ _free_invocation_state (struct invocation_state *state)
direction = g_arg_info_get_direction (state->arg_infos[i]);
transfer = g_arg_info_get_ownership_transfer (state->arg_infos[i]);
- type_tag = g_type_info_get_tag (state->arg_type_infos[i]);
-
/* Release the argument. */
if (direction == GI_DIRECTION_INOUT) {
- _pygi_argument_release (&state->backup_args[backup_args_pos], state->arg_type_infos[i],
- transfer, GI_DIRECTION_IN);
+ if (state->args != NULL) {
+ _pygi_argument_release (&state->backup_args[backup_args_pos],
+ state->arg_type_infos[i],
+ transfer, GI_DIRECTION_IN);
+ }
backup_args_pos += 1;
}
- _pygi_argument_release (state->args[i], state->arg_type_infos[i], transfer, direction);
+ if (state->args != NULL && state->args[i] != NULL) {
+ _pygi_argument_release (state->args[i], state->arg_type_infos[i],
+ transfer, direction);
- if (type_tag == GI_TYPE_TAG_ARRAY
+ type_tag = g_type_info_get_tag (state->arg_type_infos[i]);
+ if (type_tag == GI_TYPE_TAG_ARRAY
&& (direction != GI_DIRECTION_IN && transfer == GI_TRANSFER_NOTHING)) {
- /* We created a #GArray and it has not been released above, so free it. */
- state->args[i]->v_pointer = g_array_free (state->args[i]->v_pointer, FALSE);
+ /* We created a #GArray and it has not been released above, so free it. */
+ state->args[i]->v_pointer = g_array_free (state->args[i]->v_pointer, FALSE);
+ }
}
}
@@ -913,11 +951,15 @@ _free_invocation_state (struct invocation_state *state)
PyObject *
-_wrap_g_function_info_invoke (PyGIBaseInfo *self, PyObject *py_args)
+_wrap_g_callable_info_invoke (PyGIBaseInfo *self, PyObject *py_args,
+ PyObject *kwargs)
{
struct invocation_state state = { 0, };
- _initialize_invocation_state (&state, self->info, py_args);
+ if (!_initialize_invocation_state (&state, self->info, py_args, kwargs)) {
+ _free_invocation_state (&state);
+ return NULL;
+ }
if (!_prepare_invocation_state (&state, self->info, py_args)) {
_free_invocation_state (&state);
diff --git a/gi/pygi-invoke.h b/gi/pygi-invoke.h
index 0d07b21..dc1ce18 100644
--- a/gi/pygi-invoke.h
+++ b/gi/pygi-invoke.h
@@ -30,7 +30,8 @@
G_BEGIN_DECLS
-PyObject *_wrap_g_function_info_invoke (PyGIBaseInfo *self, PyObject *py_args);
+PyObject *_wrap_g_callable_info_invoke (PyGIBaseInfo *self, PyObject *py_args,
+ PyObject *kwargs);
G_END_DECLS
diff --git a/gi/pygi-property.c b/gi/pygi-property.c
index 7b6a508..2f8970d 100644
--- a/gi/pygi-property.c
+++ b/gi/pygi-property.c
@@ -139,7 +139,7 @@ pygi_get_property_value_real (PyGObject *instance,
arg.v_double = g_value_get_double (&value);
break;
case GI_TYPE_TAG_GTYPE:
- arg.v_size = g_value_get_uint (&value);
+ arg.v_size = g_value_get_gtype (&value);
break;
case GI_TYPE_TAG_UTF8:
case GI_TYPE_TAG_FILENAME:
@@ -155,6 +155,8 @@ pygi_get_property_value_real (PyGObject *instance,
type = g_registered_type_info_get_g_type (info);
info_type = g_base_info_get_type (info);
+ g_base_info_unref (info);
+
switch (info_type) {
case GI_INFO_TYPE_ENUM:
arg.v_int32 = g_value_get_enum (&value);
@@ -261,6 +263,8 @@ pygi_set_property_value_real (PyGObject *instance,
type = g_registered_type_info_get_g_type (info);
info_type = g_base_info_get_type (info);
+ g_base_info_unref (info);
+
switch (info_type) {
case GI_INFO_TYPE_ENUM:
g_value_set_enum (&value, arg.v_int32);
@@ -310,7 +314,7 @@ pygi_set_property_value_real (PyGObject *instance,
g_value_set_double (&value, arg.v_double);
break;
case GI_TYPE_TAG_GTYPE:
- g_value_set_uint (&value, arg.v_size);
+ g_value_set_gtype (&value, arg.v_size);
break;
case GI_TYPE_TAG_UTF8:
case GI_TYPE_TAG_FILENAME:
diff --git a/gi/pygi.h b/gi/pygi.h
index 03f71a4..2765b40 100644
--- a/gi/pygi.h
+++ b/gi/pygi.h
@@ -60,7 +60,7 @@ typedef PyObject * (*PyGIArgOverrideToGIArgumentFunc) (PyObject *value,
GITransfer transfer,
GIArgument *arg);
typedef PyObject * (*PyGIArgOverrideFromGIArgumentFunc) (GITypeInfo *type_info,
- GIArgument *arg);
+ gpointer data);
typedef PyObject * (*PyGIArgOverrideReleaseFunc) (GITypeInfo *type_info,
gpointer struct_);
diff --git a/gi/repository/Makefile.am b/gi/repository/Makefile.am
index c9138ce..ece9c4f 100644
--- a/gi/repository/Makefile.am
+++ b/gi/repository/Makefile.am
@@ -1,8 +1,10 @@
PLATFORM_VERSION = 2.0
-pkgpyexecdir = $(pyexecdir)/gtk-2.0/gi
+pkgpyexecdir = $(pyexecdir)/gi
pygirepositorydir = $(pkgpyexecdir)/repository
pygirepository_PYTHON = \
__init__.py
+
+-include $(top_srcdir)/git.mk
diff --git a/gi/repository/Makefile.in b/gi/repository/Makefile.in
index 7f0ef44..cb6de2a 100644
--- a/gi/repository/Makefile.in
+++ b/gi/repository/Makefile.in
@@ -141,6 +141,7 @@ LN_S = @LN_S@
LTLIBOBJS = @LTLIBOBJS@
MAINT = @MAINT@
MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
MKDIR_P = @MKDIR_P@
NM = @NM@
NMEDIT = @NMEDIT@
@@ -169,6 +170,7 @@ PYTHON = @PYTHON@
PYTHON_BASENAME = @PYTHON_BASENAME@
PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@
PYTHON_INCLUDES = @PYTHON_INCLUDES@
+PYTHON_LIBS = @PYTHON_LIBS@
PYTHON_PLATFORM = @PYTHON_PLATFORM@
PYTHON_PREFIX = @PYTHON_PREFIX@
PYTHON_VERSION = @PYTHON_VERSION@
@@ -184,6 +186,7 @@ abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
abs_top_builddir = @abs_top_builddir@
abs_top_srcdir = @abs_top_srcdir@
+ac_ct_AR = @ac_ct_AR@
ac_ct_CC = @ac_ct_CC@
ac_ct_DUMPBIN = @ac_ct_DUMPBIN@
am__include = @am__include@
@@ -220,7 +223,7 @@ mandir = @mandir@
mkdir_p = @mkdir_p@
oldincludedir = @oldincludedir@
pdfdir = @pdfdir@
-pkgpyexecdir = $(pyexecdir)/gtk-2.0/gi
+pkgpyexecdir = $(pyexecdir)/gi
pkgpythondir = @pkgpythondir@
prefix = @prefix@
program_transform_name = @program_transform_name@
@@ -469,6 +472,8 @@ uninstall-am: uninstall-pygirepositoryPYTHON
uninstall-pygirepositoryPYTHON
+-include $(top_srcdir)/git.mk
+
# Tell versions [3.59,3.63) of GNU make to not export all variables.
# Otherwise a system limit (for SysV at least) may be exceeded.
.NOEXPORT:
diff --git a/gi/types.py b/gi/types.py
index 18b4013..37cf499 100644
--- a/gi/types.py
+++ b/gi/types.py
@@ -29,10 +29,14 @@ from ._gi import \
InterfaceInfo, \
ObjectInfo, \
StructInfo, \
+ VFuncInfo, \
set_object_has_new_constructor, \
register_interface_info, \
hook_up_vfunc_implementation
+if sys.version_info > (3, 0):
+ def callable(obj):
+ return hasattr(obj, '__call__')
def Function(info):
@@ -45,6 +49,16 @@ def Function(info):
return function
+def NativeVFunc(info, cls):
+
+ def native_vfunc(*args):
+ return info.invoke(*args, gtype=cls.__gtype__)
+ native_vfunc.__info__ = info
+ native_vfunc.__name__ = info.get_name()
+ native_vfunc.__module__ = info.get_namespace()
+
+ return native_vfunc
+
def Constructor(info):
def constructor(cls, *args):
@@ -93,40 +107,106 @@ class MetaClassHelper(object):
setattr(cls, name, value)
def _setup_vfuncs(cls):
- for base in cls.__bases__:
- if not hasattr(base, '__info__') or \
- not hasattr(base.__info__, 'get_vfuncs'):
+ for vfunc_name, py_vfunc in cls.__dict__.items():
+ if not vfunc_name.startswith("do_") or not callable(py_vfunc):
continue
- for vfunc_info in base.__info__.get_vfuncs():
- vfunc = getattr(cls, 'do_' + vfunc_info.get_name(), None)
- if vfunc is None and isinstance(base.__info__, InterfaceInfo) and \
- (not hasattr(cls, vfunc_info.get_name()) and not vfunc_info.get_invoker()):
- raise TypeError('Class implementing %s.%s should implement '
- 'the method do_%s()' % (base.__info__.get_namespace(),
- base.__info__.get_name(),
- vfunc_info.get_name()))
- elif vfunc is not None:
- function = vfunc
- if sys.version_info < (3, 0):
- function = vfunc.im_func
-
- if not is_function_in_classes(function, cls.__bases__):
- hook_up_vfunc_implementation(vfunc_info, cls.__gtype__,
- vfunc)
-
-def is_function_in_classes(function, classes):
- for klass in classes:
- if function in klass.__dict__.values():
- return True
- elif is_function_in_classes(function, klass.__bases__):
- return True
- return False
+
+ # If a method name starts with "do_" assume it is a vfunc, and search
+ # in the base classes for a method with the same name to override.
+ # Recursion is not necessary here because getattr() searches all
+ # super class attributes as well.
+ vfunc_info = None
+ for base in cls.__bases__:
+ method = getattr(base, vfunc_name, None)
+ if method is not None and hasattr(method, '__info__') and \
+ isinstance(method.__info__, VFuncInfo):
+ vfunc_info = method.__info__
+ break
+
+ # If we did not find a matching method name in the bases, we might
+ # be overriding an interface virtual method. Since interfaces do not
+ # provide implementations, there will be no method attribute installed
+ # on the object. Instead we have to search through
+ # InterfaceInfo.get_vfuncs(). Note that the infos returned by
+ # get_vfuncs() use the C vfunc name (ie. there is no "do_" prefix).
+ if vfunc_info is None:
+ vfunc_info = find_vfunc_info_in_interface(cls.__bases__, vfunc_name[len("do_"):])
+
+ if vfunc_info is not None:
+ assert vfunc_name == ('do_' + vfunc_info.get_name())
+ # Check to see if there are vfuncs with the same name in the bases.
+ # We have no way of specifying which one we are supposed to override.
+ ambiguous_base = find_vfunc_conflict_in_bases(vfunc_info, cls.__bases__)
+ if ambiguous_base is not None:
+ base_info = vfunc_info.get_container()
+ raise TypeError('Method %s() on class %s.%s is ambiguous '
+ 'with methods in base classes %s.%s and %s.%s' %
+ (vfunc_name,
+ cls.__info__.get_namespace(),
+ cls.__info__.get_name(),
+ base_info.get_namespace(),
+ base_info.get_name(),
+ ambiguous_base.__info__.get_namespace(),
+ ambiguous_base.__info__.get_name()))
+
+ hook_up_vfunc_implementation(vfunc_info, cls.__gtype__,
+ py_vfunc)
+
+ def _setup_native_vfuncs(cls):
+ # Only InterfaceInfo and ObjectInfo have the get_vfuncs() method.
+ # We skip InterfaceInfo because interfaces have no implementations for vfuncs.
+ # Also check if __info__ in __dict__, not hasattr('__info__', ...)
+ # because we do not want to accidentally retrieve __info__ from a base class.
+ class_info = cls.__dict__.get('__info__')
+ if class_info is None or not isinstance(class_info, ObjectInfo):
+ return
+
+ for vfunc_info in class_info.get_vfuncs():
+ name = 'do_%s' % vfunc_info.get_name()
+ value = NativeVFunc(vfunc_info, cls)
+ setattr(cls, name, value)
+
+def find_vfunc_info_in_interface(bases, vfunc_name):
+ for base in bases:
+ # All wrapped interfaces inherit from GInterface.
+ # This can be seen in IntrospectionModule.__getattr__() in module.py.
+ # We do not need to search regular classes here, only wrapped interfaces.
+ # We also skip GInterface, because it is not wrapped and has no __info__ attr.
+ if base is gobject.GInterface or\
+ not issubclass(base, gobject.GInterface) or\
+ not isinstance(base.__info__, InterfaceInfo):
+ continue
+
+ for vfunc in base.__info__.get_vfuncs():
+ if vfunc.get_name() == vfunc_name:
+ return vfunc
+
+ vfunc = find_vfunc_info_in_interface(base.__bases__, vfunc_name)
+ if vfunc is not None:
+ return vfunc
+
+ return None
+
+def find_vfunc_conflict_in_bases(vfunc, bases):
+ for klass in bases:
+ if not hasattr(klass, '__info__') or \
+ not hasattr(klass.__info__, 'get_vfuncs'):
+ continue
+ vfuncs = klass.__info__.get_vfuncs()
+ vfunc_name = vfunc.get_name()
+ for v in vfuncs:
+ if v.get_name() == vfunc_name and v != vfunc:
+ return klass
+
+ aklass = find_vfunc_conflict_in_bases(vfunc, klass.__bases__)
+ if aklass is not None:
+ return aklass
+ return None
class GObjectMeta(gobject.GObjectMeta, MetaClassHelper):
def __init__(cls, name, bases, dict_):
super(GObjectMeta, cls).__init__(name, bases, dict_)
-
is_gi_defined = False
if cls.__module__ == 'gi.repository.' + cls.__info__.get_namespace():
is_gi_defined = True
@@ -140,6 +220,7 @@ class GObjectMeta(gobject.GObjectMeta, MetaClassHelper):
elif is_gi_defined:
cls._setup_methods()
cls._setup_constants()
+ cls._setup_native_vfuncs()
if isinstance(cls.__info__, ObjectInfo):
cls._setup_fields()
@@ -148,6 +229,7 @@ class GObjectMeta(gobject.GObjectMeta, MetaClassHelper):
elif isinstance(cls.__info__, InterfaceInfo):
register_interface_info(cls.__info__.get_g_type())
+
class StructMeta(type, MetaClassHelper):
def __init__(cls, name, bases, dict_):
@@ -162,8 +244,17 @@ class StructMeta(type, MetaClassHelper):
cls._setup_methods()
cls._setup_constructors()
+ for method_info in cls.__info__.get_methods():
+ if method_info.is_constructor() and \
+ method_info.get_name() == 'new' and \
+ not method_info.get_arguments():
+ cls.__new__ = staticmethod(Constructor(method_info))
+ break
+
class Enum(int):
- __info__ = None
+ # Only subclasses of this type should be instantiated.
+ # Each subclass requires an __info__ attribute,
+ # which is not declared here because enums do not share the same gi type.
def __init__(self, value):
int.__init__(value)