summaryrefslogtreecommitdiff
path: root/gi/_gobject
diff options
context:
space:
mode:
authorDongHun Kwak <dh0128.kwak@samsung.com>2017-07-12 08:39:06 +0900
committerDongHun Kwak <dh0128.kwak@samsung.com>2017-07-12 08:39:09 +0900
commit23384e73cb73bc8875384183d5916e33af4196d4 (patch)
treebe92faf8967d24f2be88a92b4f7506e9d65fbf3d /gi/_gobject
parent705bf16f6a14a07ccdc0c1a5fe1b31d92c3bd96e (diff)
downloadpygobject2-23384e73cb73bc8875384183d5916e33af4196d4.tar.gz
pygobject2-23384e73cb73bc8875384183d5916e33af4196d4.tar.bz2
pygobject2-23384e73cb73bc8875384183d5916e33af4196d4.zip
Imported Upstream version 3.10.0
Change-Id: Ib97d541be276a6a70923c214755d8273c4437a2f Signed-off-by: DongHun Kwak <dh0128.kwak@samsung.com>
Diffstat (limited to 'gi/_gobject')
-rw-r--r--gi/_gobject/Makefile.am29
-rw-r--r--gi/_gobject/Makefile.in98
-rw-r--r--gi/_gobject/__init__.py84
-rw-r--r--gi/_gobject/constants.py41
-rw-r--r--gi/_gobject/gobjectmodule.c692
-rw-r--r--gi/_gobject/propertyhelper.py264
-rw-r--r--gi/_gobject/pygboxed.c3
-rw-r--r--gi/_gobject/pygenum.c37
-rw-r--r--gi/_gobject/pygflags.c74
-rw-r--r--gi/_gobject/pyginterface.c2
-rw-r--r--gi/_gobject/pygobject-private.h56
-rw-r--r--gi/_gobject/pygobject.c769
-rw-r--r--gi/_gobject/pygobject.h79
-rw-r--r--gi/_gobject/pygtype.c845
-rw-r--r--gi/_gobject/signalhelper.py258
15 files changed, 1751 insertions, 1580 deletions
diff --git a/gi/_gobject/Makefile.am b/gi/_gobject/Makefile.am
index 3263889..5059ea7 100644
--- a/gi/_gobject/Makefile.am
+++ b/gi/_gobject/Makefile.am
@@ -10,7 +10,8 @@ extension_cppflags = \
extension_ldflags = \
-module \
- -avoid-version
+ -avoid-version \
+ -shrext $(PYTHON_SO)
if OS_WIN32
# Windows requires Python modules to be explicitly linked to libpython.
@@ -20,8 +21,7 @@ extension_libadd = \
$(PYTHON_LIBS)
extension_ldflags += \
- -no-undefined \
- -shrext ".pyd"
+ -no-undefined
endif
pygobjectdir = $(pyexecdir)/gi/_gobject
@@ -29,7 +29,8 @@ pygobjectdir = $(pyexecdir)/gi/_gobject
pygobject_PYTHON = \
__init__.py \
constants.py \
- propertyhelper.py
+ propertyhelper.py \
+ signalhelper.py
pygobject_LTLIBRARIES = _gobject.la
@@ -69,12 +70,18 @@ _gobject_la_LDFLAGS = \
$(extension_ldflags) \
-export-symbols-regex "_gobject|PyInit__gobject"
+# if we build in a separate tree, we need to symlink the *.py files from the
+# source tree; Python does not accept the extensions and modules in different
+# paths
+build_pylinks:
+ for f in $(pygobject_PYTHON); do \
+ [ -e $(builddir)/$$f ] || $(LN_S) $(srcdir)/$$f $(builddir)/$$f; \
+ done
-all: $(pygobject_LTLIBRARIES:.la=.so)
-check-local: $(pygobject_LTLIBRARIES:.la=.so)
-clean-local:
- rm -f $(pygobject_LTLIBRARIES:.la=.so)
-.la.so:
- $(LN_S) .libs/$@ $@ || true
--include $(top_srcdir)/git.mk
+all: $(pygobject_LTLIBRARIES:.la=$(PYTHON_SO)) build_pylinks
+check-local: $(pygobject_LTLIBRARIES:.la=$(PYTHON_SO)) build_pylinks
+clean-local:
+ rm -f $(pygobject_LTLIBRARIES:.la=$(PYTHON_SO))
+%$(PYTHON_SO): %.la
+ $(LN_S) -f .libs/$@ $@
diff --git a/gi/_gobject/Makefile.in b/gi/_gobject/Makefile.in
index c9313e6..a422d9e 100644
--- a/gi/_gobject/Makefile.in
+++ b/gi/_gobject/Makefile.in
@@ -1,4 +1,4 @@
-# Makefile.in generated by automake 1.11.3 from Makefile.am.
+# Makefile.in generated by automake 1.11.6 from Makefile.am.
# @configure_input@
# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
@@ -17,6 +17,23 @@
VPATH = @srcdir@
+am__make_dryrun = \
+ { \
+ am__dry=no; \
+ case $$MAKEFLAGS in \
+ *\\[\ \ ]*) \
+ echo 'am--echo: ; @echo "AM" OK' | $(MAKE) -f - 2>/dev/null \
+ | grep '^AM OK$$' >/dev/null || am__dry=yes;; \
+ *) \
+ for am__flg in $$MAKEFLAGS; do \
+ case $$am__flg in \
+ *=*|--*) ;; \
+ *n*) am__dry=yes; break;; \
+ esac; \
+ done;; \
+ esac; \
+ test $$am__dry = yes; \
+ }
pkgdatadir = $(datadir)/@PACKAGE@
pkglibdir = $(libdir)/@PACKAGE@
pkglibexecdir = $(libexecdir)/@PACKAGE@
@@ -35,18 +52,15 @@ POST_UNINSTALL = :
build_triplet = @build@
host_triplet = @host@
@OS_WIN32_TRUE@am__append_1 = \
-@OS_WIN32_TRUE@ -no-undefined \
-@OS_WIN32_TRUE@ -shrext ".pyd"
+@OS_WIN32_TRUE@ -no-undefined
subdir = gi/_gobject
DIST_COMMON = $(pkginclude_HEADERS) $(pygobject_PYTHON) \
$(srcdir)/Makefile.am $(srcdir)/Makefile.in
ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
am__aclocal_m4_deps = $(top_srcdir)/m4/as-ac-expand.m4 \
- $(top_srcdir)/m4/jhflags.m4 $(top_srcdir)/m4/libtool.m4 \
- $(top_srcdir)/m4/ltoptions.m4 $(top_srcdir)/m4/ltsugar.m4 \
- $(top_srcdir)/m4/ltversion.m4 $(top_srcdir)/m4/lt~obsolete.m4 \
- $(top_srcdir)/m4/python.m4 $(top_srcdir)/configure.ac
+ $(top_srcdir)/m4/jhflags.m4 $(top_srcdir)/m4/python.m4 \
+ $(top_srcdir)/configure.ac
am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
$(ACLOCAL_M4)
mkinstalldirs = $(install_sh) -d
@@ -128,6 +142,11 @@ am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
am__v_GEN_0 = @echo " GEN " $@;
SOURCES = $(_gobject_la_SOURCES)
DIST_SOURCES = $(_gobject_la_SOURCES)
+am__can_run_installinfo = \
+ case $$AM_UPDATE_INFO_DIR in \
+ n|no|NO) false;; \
+ *) (install-info --version) >/dev/null 2>&1;; \
+ esac
am__py_compile = PYTHON=$(PYTHON) $(SHELL) $(py_compile)
py_compile = $(top_srcdir)/py-compile
HEADERS = $(pkginclude_HEADERS)
@@ -145,9 +164,14 @@ AUTOCONF = @AUTOCONF@
AUTOHEADER = @AUTOHEADER@
AUTOMAKE = @AUTOMAKE@
AWK = @AWK@
+CAIRO_CFLAGS = @CAIRO_CFLAGS@
+CAIRO_LIBS = @CAIRO_LIBS@
CC = @CC@
CCDEPMODE = @CCDEPMODE@
CFLAGS = @CFLAGS@
+CODE_COVERAGE_CFLAGS = @CODE_COVERAGE_CFLAGS@
+CODE_COVERAGE_ENABLED = @CODE_COVERAGE_ENABLED@
+CODE_COVERAGE_LDFLAGS = @CODE_COVERAGE_LDFLAGS@
CPP = @CPP@
CPPFLAGS = @CPPFLAGS@
CYGPATH_W = @CYGPATH_W@
@@ -165,6 +189,7 @@ EXEEXT = @EXEEXT@
FFI_CFLAGS = @FFI_CFLAGS@
FFI_LIBS = @FFI_LIBS@
FGREP = @FGREP@
+GENHTML = @GENHTML@
GIO_CFLAGS = @GIO_CFLAGS@
GIO_LIBS = @GIO_LIBS@
GI_CFLAGS = @GI_CFLAGS@
@@ -184,6 +209,7 @@ INSTALL_SCRIPT = @INSTALL_SCRIPT@
INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
INTROSPECTION_COMPILER = @INTROSPECTION_COMPILER@
INTROSPECTION_SCANNER = @INTROSPECTION_SCANNER@
+LCOV = @LCOV@
LD = @LD@
LDFLAGS = @LDFLAGS@
LIBFFI_PC = @LIBFFI_PC@
@@ -193,7 +219,6 @@ LIBTOOL = @LIBTOOL@
LIPO = @LIPO@
LN_S = @LN_S@
LTLIBOBJS = @LTLIBOBJS@
-MAINT = @MAINT@
MAKEINFO = @MAKEINFO@
MANIFEST_TOOL = @MANIFEST_TOOL@
MKDIR_P = @MKDIR_P@
@@ -228,6 +253,7 @@ PYTHON_LIBS = @PYTHON_LIBS@
PYTHON_LIB_LOC = @PYTHON_LIB_LOC@
PYTHON_PLATFORM = @PYTHON_PLATFORM@
PYTHON_PREFIX = @PYTHON_PREFIX@
+PYTHON_SO = @PYTHON_SO@
PYTHON_VERSION = @PYTHON_VERSION@
RANLIB = @RANLIB@
SED = @SED@
@@ -236,6 +262,7 @@ SHELL = @SHELL@
STRIP = @STRIP@
THREADING_CFLAGS = @THREADING_CFLAGS@
VERSION = @VERSION@
+WARN_CFLAGS = @WARN_CFLAGS@
abs_builddir = @abs_builddir@
abs_srcdir = @abs_srcdir@
abs_top_builddir = @abs_top_builddir@
@@ -299,7 +326,8 @@ extension_cppflags = \
$(PYTHON_INCLUDES) \
-DPY_SSIZE_T_CLEAN
-extension_ldflags = -module -avoid-version $(am__append_1)
+extension_ldflags = -module -avoid-version -shrext $(PYTHON_SO) \
+ $(am__append_1)
# Windows requires Python modules to be explicitly linked to libpython.
# Extension modules are shared libaries (.dll), but need to be
@@ -311,7 +339,8 @@ pygobjectdir = $(pyexecdir)/gi/_gobject
pygobject_PYTHON = \
__init__.py \
constants.py \
- propertyhelper.py
+ propertyhelper.py \
+ signalhelper.py
pygobject_LTLIBRARIES = _gobject.la
_gobject_la_SOURCES = \
@@ -357,8 +386,8 @@ _gobject_la_LDFLAGS = \
all: all-am
.SUFFIXES:
-.SUFFIXES: .c .la .lo .o .obj .so
-$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps)
+.SUFFIXES: .c .lo .o .obj
+$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps)
@for dep in $?; do \
case '$(am__configure_deps)' in \
*$$dep*) \
@@ -383,14 +412,13 @@ Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
-$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
+$(top_srcdir)/configure: $(am__configure_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
-$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps)
+$(ACLOCAL_M4): $(am__aclocal_m4_deps)
cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh
$(am__aclocal_m4_deps):
install-pygobjectLTLIBRARIES: $(pygobject_LTLIBRARIES)
@$(NORMAL_INSTALL)
- test -z "$(pygobjectdir)" || $(MKDIR_P) "$(DESTDIR)$(pygobjectdir)"
@list='$(pygobject_LTLIBRARIES)'; test -n "$(pygobjectdir)" || list=; \
list2=; for p in $$list; do \
if test -f $$p; then \
@@ -398,6 +426,8 @@ install-pygobjectLTLIBRARIES: $(pygobject_LTLIBRARIES)
else :; fi; \
done; \
test -z "$$list2" || { \
+ echo " $(MKDIR_P) '$(DESTDIR)$(pygobjectdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(pygobjectdir)" || exit 1; \
echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(pygobjectdir)'"; \
$(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(pygobjectdir)"; \
}
@@ -529,8 +559,11 @@ clean-libtool:
-rm -rf .libs _libs
install-pygobjectPYTHON: $(pygobject_PYTHON)
@$(NORMAL_INSTALL)
- test -z "$(pygobjectdir)" || $(MKDIR_P) "$(DESTDIR)$(pygobjectdir)"
@list='$(pygobject_PYTHON)'; dlist=; list2=; test -n "$(pygobjectdir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(pygobjectdir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(pygobjectdir)" || exit 1; \
+ fi; \
for p in $$list; do \
if test -f "$$p"; then b=; else b="$(srcdir)/"; fi; \
if test -f $$b$$p; then \
@@ -545,8 +578,12 @@ install-pygobjectPYTHON: $(pygobject_PYTHON)
$(INSTALL_DATA) $$files "$(DESTDIR)$(pygobjectdir)" || exit $$?; \
done || exit $$?; \
if test -n "$$dlist"; then \
- $(am__py_compile) --destdir "$(DESTDIR)" \
- --basedir "$(pygobjectdir)" $$dlist; \
+ if test -z "$(DESTDIR)"; then \
+ $(am__py_compile) --basedir "$(pygobjectdir)" $$dlist; \
+ else \
+ $(am__py_compile) --destdir "$(DESTDIR)" \
+ --basedir "$(pygobjectdir)" $$dlist; \
+ fi; \
else :; fi
uninstall-pygobjectPYTHON:
@@ -564,8 +601,11 @@ uninstall-pygobjectPYTHON:
exit $$st
install-pkgincludeHEADERS: $(pkginclude_HEADERS)
@$(NORMAL_INSTALL)
- test -z "$(pkgincludedir)" || $(MKDIR_P) "$(DESTDIR)$(pkgincludedir)"
@list='$(pkginclude_HEADERS)'; test -n "$(pkgincludedir)" || list=; \
+ if test -n "$$list"; then \
+ echo " $(MKDIR_P) '$(DESTDIR)$(pkgincludedir)'"; \
+ $(MKDIR_P) "$(DESTDIR)$(pkgincludedir)" || exit 1; \
+ fi; \
for p in $$list; do \
if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
echo "$$d$$p"; \
@@ -794,14 +834,20 @@ uninstall-am: uninstall-pkgincludeHEADERS \
uninstall-pygobjectLTLIBRARIES uninstall-pygobjectPYTHON
-all: $(pygobject_LTLIBRARIES:.la=.so)
-check-local: $(pygobject_LTLIBRARIES:.la=.so)
-clean-local:
- rm -f $(pygobject_LTLIBRARIES:.la=.so)
-.la.so:
- $(LN_S) .libs/$@ $@ || true
+# if we build in a separate tree, we need to symlink the *.py files from the
+# source tree; Python does not accept the extensions and modules in different
+# paths
+build_pylinks:
+ for f in $(pygobject_PYTHON); do \
+ [ -e $(builddir)/$$f ] || $(LN_S) $(srcdir)/$$f $(builddir)/$$f; \
+ done
--include $(top_srcdir)/git.mk
+all: $(pygobject_LTLIBRARIES:.la=$(PYTHON_SO)) build_pylinks
+check-local: $(pygobject_LTLIBRARIES:.la=$(PYTHON_SO)) build_pylinks
+clean-local:
+ rm -f $(pygobject_LTLIBRARIES:.la=$(PYTHON_SO))
+%$(PYTHON_SO): %.la
+ $(LN_S) -f .libs/$@ $@
# 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.
diff --git a/gi/_gobject/__init__.py b/gi/_gobject/__init__.py
index 4304b80..d3ea0e0 100644
--- a/gi/_gobject/__init__.py
+++ b/gi/_gobject/__init__.py
@@ -1,6 +1,6 @@
# -*- Mode: Python; py-indent-offset: 4 -*-
# pygobject - Python bindings for the GObject library
-# Copyright (C) 2006 Johan Dahlin
+# Copyright (C) 2006-2012 Johan Dahlin
#
# gobject/__init__.py: initialisation file for gobject module
#
@@ -27,85 +27,24 @@ import sys
if 'gobject' in sys.modules:
raise ImportError('When using gi.repository you must not import static modules like "gobject". Please change all occurrences of "import gobject" to "from gi.repository import GObject".')
-from .._glib import spawn_async, idle_add, timeout_add, timeout_add_seconds, \
- io_add_watch, source_remove, child_watch_add, markup_escape_text, \
- get_current_time, filename_display_name, filename_display_basename, \
- filename_from_utf8, get_application_name, set_application_name, \
- get_prgname, set_prgname, main_depth, Pid, GError, glib_version, \
- MainLoop, MainContext, main_context_default, IOChannel, Source, Idle, \
- Timeout, PollFD, OptionGroup, OptionContext, option, uri_list_extract_uris
-from .._glib import SPAWN_LEAVE_DESCRIPTORS_OPEN, SPAWN_DO_NOT_REAP_CHILD, \
- SPAWN_SEARCH_PATH, SPAWN_STDOUT_TO_DEV_NULL, SPAWN_STDERR_TO_DEV_NULL, \
- SPAWN_CHILD_INHERITS_STDIN, SPAWN_FILE_AND_ARGV_ZERO, PRIORITY_HIGH, \
- PRIORITY_DEFAULT, PRIORITY_HIGH_IDLE, PRIORITY_DEFAULT_IDLE, \
- PRIORITY_LOW, IO_IN, IO_OUT, IO_PRI, IO_ERR, IO_HUP, IO_NVAL, \
- IO_STATUS_ERROR, IO_STATUS_NORMAL, IO_STATUS_EOF, IO_STATUS_AGAIN, \
- IO_FLAG_APPEND, IO_FLAG_NONBLOCK, IO_FLAG_IS_READABLE, \
- IO_FLAG_IS_WRITEABLE, IO_FLAG_IS_SEEKABLE, IO_FLAG_MASK, \
- IO_FLAG_GET_MASK, IO_FLAG_SET_MASK, OPTION_FLAG_HIDDEN, \
- OPTION_FLAG_IN_MAIN, OPTION_FLAG_REVERSE, OPTION_FLAG_NO_ARG, \
- OPTION_FLAG_FILENAME, OPTION_FLAG_OPTIONAL_ARG, OPTION_FLAG_NOALIAS, \
- OPTION_ERROR_UNKNOWN_OPTION, OPTION_ERROR_BAD_VALUE, \
- OPTION_ERROR_FAILED, OPTION_REMAINING, OPTION_ERROR
-
-from .constants import *
-from ._gobject import *
+from . import _gobject
+from . import propertyhelper
+from . import signalhelper
+GObject = _gobject.GObject
+GType = _gobject.GType
_PyGObject_API = _gobject._PyGObject_API
+pygobject_version = _gobject.pygobject_version
-from .propertyhelper import Property
-
-sys.modules['gi._gobject.option'] = option
class GObjectMeta(type):
"Metaclass for automatically registering GObject classes"
def __init__(cls, name, bases, dict_):
type.__init__(cls, name, bases, dict_)
- cls._install_properties()
+ propertyhelper.install_properties(cls)
+ signalhelper.install_signals(cls)
cls._type_register(cls.__dict__)
- def _install_properties(cls):
- gproperties = getattr(cls, '__gproperties__', {})
-
- props = []
- for name, prop in cls.__dict__.items():
- if isinstance(prop, Property): # not same as the built-in
- if name in gproperties:
- raise ValueError
- prop.name = name
- gproperties[name] = prop.get_pspec_args()
- props.append(prop)
-
- if not props:
- return
-
- cls.__gproperties__ = gproperties
-
- if ('do_get_property' in cls.__dict__ or
- 'do_set_property' in cls.__dict__):
- for prop in props:
- if (prop.fget != prop._default_getter or
- prop.fset != prop._default_setter):
- raise TypeError(
- "GObject subclass %r defines do_get/set_property"
- " and it also uses a property with a custom setter"
- " or getter. This is not allowed" % (
- cls.__name__,))
-
- def obj_get_property(self, pspec):
- name = pspec.name.replace('-', '_')
- prop = getattr(cls, name, None)
- if prop:
- return prop.fget(self)
- cls.do_get_property = obj_get_property
-
- def obj_set_property(self, pspec, value):
- name = pspec.name.replace('-', '_')
- prop = getattr(cls, name, None)
- if prop:
- prop.fset(self, value)
- cls.do_set_property = obj_set_property
-
def _type_register(cls, namespace):
## don't register the class if already registered
if '__gtype__' in namespace:
@@ -116,9 +55,6 @@ class GObjectMeta(type):
if cls.__module__.startswith('gi.overrides.'):
return
- type_register(cls, namespace.get('__gtype_name__'))
+ _gobject.type_register(cls, namespace.get('__gtype_name__'))
_gobject._install_metaclass(GObjectMeta)
-
-# Deprecated naming still available for backwards compatibility.
-property = Property
diff --git a/gi/_gobject/constants.py b/gi/_gobject/constants.py
index ff970ae..9565a66 100644
--- a/gi/_gobject/constants.py
+++ b/gi/_gobject/constants.py
@@ -19,11 +19,9 @@
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
# USA
-import sys
-
from . import _gobject
-# TYPE_INVALID defined in gobjectmodule.c
+TYPE_INVALID = _gobject.TYPE_INVALID
TYPE_NONE = _gobject.type_from_name('void')
TYPE_INTERFACE = _gobject.type_from_name('GInterface')
TYPE_CHAR = _gobject.type_from_name('gchar')
@@ -45,38 +43,7 @@ TYPE_BOXED = _gobject.type_from_name('GBoxed')
TYPE_PARAM = _gobject.type_from_name('GParam')
TYPE_OBJECT = _gobject.type_from_name('GObject')
TYPE_PYOBJECT = _gobject.type_from_name('PyObject')
+TYPE_GTYPE = _gobject.type_from_name('GType')
+TYPE_STRV = _gobject.type_from_name('GStrv')
+TYPE_VARIANT = _gobject.type_from_name('GVariant')
TYPE_UNICHAR = TYPE_UINT
-
-# do a little dance to maintain API compatibility
-# as these were origianally defined here, and are
-# now defined in gobjectmodule.c
-G_MINFLOAT = _gobject.G_MINFLOAT
-G_MAXFLOAT = _gobject.G_MAXFLOAT
-G_MINDOUBLE = _gobject.G_MINDOUBLE
-G_MAXDOUBLE = _gobject.G_MAXDOUBLE
-G_MINSHORT = _gobject.G_MINSHORT
-G_MAXSHORT = _gobject.G_MAXSHORT
-G_MAXUSHORT = _gobject.G_MAXUSHORT
-G_MININT = _gobject.G_MININT
-G_MAXINT = _gobject.G_MAXINT
-G_MAXUINT = _gobject.G_MAXUINT
-G_MINLONG = _gobject.G_MINLONG
-G_MAXLONG = _gobject.G_MAXLONG
-G_MAXULONG = _gobject.G_MAXULONG
-G_MININT8 = _gobject.G_MININT8
-G_MAXINT8 = _gobject.G_MAXINT8
-G_MAXUINT8 = _gobject.G_MAXUINT8
-G_MININT16 = _gobject.G_MININT16
-G_MAXINT16 = _gobject.G_MAXINT16
-G_MAXUINT16 = _gobject.G_MAXUINT16
-G_MININT32 = _gobject.G_MININT32
-G_MAXINT32 = _gobject.G_MAXINT32
-G_MAXUINT32 = _gobject.G_MAXUINT32
-G_MININT64 = _gobject.G_MININT64
-G_MAXINT64 = _gobject.G_MAXINT64
-G_MAXUINT64 = _gobject.G_MAXUINT64
-G_MAXSIZE = _gobject.G_MAXSIZE
-G_MAXSSIZE = _gobject.G_MAXSSIZE
-G_MINOFFSET = _gobject.G_MINOFFSET
-G_MAXOFFSET = _gobject.G_MAXOFFSET
-
diff --git a/gi/_gobject/gobjectmodule.c b/gi/_gobject/gobjectmodule.c
index cacd46b..ac37904 100644
--- a/gi/_gobject/gobjectmodule.c
+++ b/gi/_gobject/gobjectmodule.c
@@ -37,7 +37,6 @@
#include "pygpointer.h"
#include "pygtype.h"
-static PyObject *_pyg_signal_accumulator_true_handled_func;
static GHashTable *log_handlers = NULL;
static gboolean log_handlers_disabled = FALSE;
@@ -49,24 +48,17 @@ static void pyg_flags_add_constants(PyObject *module, GType flags_type,
/**
* pyg_set_thread_block_funcs:
- * @block_threads_func: a function to block Python threads.
- * @unblock_threads_func: a function to unblock Python threads.
- *
- * an interface to allow pygtk to add hooks to handle threading
- * similar to the old PyGTK 0.6.x releases. May not work quite right
- * anymore.
+ * Deprecated, only available for ABI compatibility.
*/
static void
-pyg_set_thread_block_funcs (PyGThreadBlockFunc block_threads_func,
- PyGThreadBlockFunc unblock_threads_func)
+_pyg_set_thread_block_funcs (PyGThreadBlockFunc block_threads_func,
+ PyGThreadBlockFunc unblock_threads_func)
{
- g_return_if_fail(pygobject_api_functions.block_threads == NULL &&
- pygobject_api_functions.unblock_threads == NULL);
-
- pygobject_api_functions.block_threads = block_threads_func;
- pygobject_api_functions.unblock_threads = unblock_threads_func;
- pyglib_set_thread_block_funcs(block_threads_func,
- unblock_threads_func);
+ PyGILState_STATE state = pyglib_gil_state_ensure ();
+ PyErr_Warn (PyExc_DeprecationWarning,
+ "Using pyg_set_thread_block_funcs is not longer needed. "
+ "PyGObject always uses Py_BLOCK/UNBLOCK_THREADS.");
+ pyglib_gil_state_release (state);
}
/**
@@ -120,6 +112,7 @@ pyg_type_from_name (PyObject *self, PyObject *args)
{
const gchar *name;
GType type;
+ PyObject *repr = NULL;
#if 0
if (PyErr_Warn(PyExc_DeprecationWarning,
"gobject.type_from_name is deprecated; "
@@ -128,34 +121,14 @@ pyg_type_from_name (PyObject *self, PyObject *args)
#endif
if (!PyArg_ParseTuple(args, "s:gobject.type_from_name", &name))
return NULL;
- type = _pyg_type_from_name(name);
+ type = g_type_from_name(name);
if (type != 0)
return pyg_type_wrapper_new(type);
+ repr = PyObject_Repr((PyObject*)self);
PyErr_Format(PyExc_RuntimeError, "%s: unknown type name: %s",
- PYGLIB_PyUnicode_AsString(PyObject_Repr((PyObject*)self)),
+ PYGLIB_PyUnicode_AsString(repr),
name);
- return NULL;
-}
-
-static PyObject *
-pyg_type_parent (PyObject *self, PyObject *args)
-{
- PyObject *gtype;
- GType type, parent;
-#if 0
- if (PyErr_Warn(PyExc_DeprecationWarning,
- "gobject.type_parent is deprecated; "
- "use GType.parent instead"))
- return NULL;
-#endif
- if (!PyArg_ParseTuple(args, "O:gobject.type_parent", &gtype))
- return NULL;
- if ((type = pyg_type_from_object(gtype)) == 0)
- return NULL;
- parent = g_type_parent(type);
- if (parent != 0)
- return pyg_type_wrapper_new(parent);
- PyErr_SetString(PyExc_RuntimeError, "no parent for type");
+ Py_DECREF(repr);
return NULL;
}
@@ -179,68 +152,6 @@ pyg_type_is_a (PyObject *self, PyObject *args)
return PyBool_FromLong(g_type_is_a(type, parent));
}
-static PyObject *
-pyg_type_children (PyObject *self, PyObject *args)
-{
- PyObject *gtype, *list;
- GType type, *children;
- guint n_children, i;
-#if 0
- if (PyErr_Warn(PyExc_DeprecationWarning,
- "gobject.type_children is deprecated; "
- "use GType.children instead"))
- return NULL;
-#endif
- if (!PyArg_ParseTuple(args, "O:gobject.type_children", &gtype))
- return NULL;
- if ((type = pyg_type_from_object(gtype)) == 0)
- return NULL;
- children = g_type_children(type, &n_children);
- if (children) {
- list = PyList_New(0);
- for (i = 0; i < n_children; i++) {
- PyObject *o;
- PyList_Append(list, o=pyg_type_wrapper_new(children[i]));
- Py_DECREF(o);
- }
- g_free(children);
- return list;
- }
- PyErr_SetString(PyExc_RuntimeError, "invalid type, or no children");
- return NULL;
-}
-
-static PyObject *
-pyg_type_interfaces (PyObject *self, PyObject *args)
-{
- PyObject *gtype, *list;
- GType type, *interfaces;
- guint n_interfaces, i;
-#if 0
- if (PyErr_Warn(PyExc_DeprecationWarning,
- "gobject.type_interfaces is deprecated; "
- "use GType.interfaces instead"))
- return NULL;
-#endif
- if (!PyArg_ParseTuple(args, "O:gobject.type_interfaces", &gtype))
- return NULL;
- if ((type = pyg_type_from_object(gtype)) == 0)
- return NULL;
- interfaces = g_type_interfaces(type, &n_interfaces);
- if (interfaces) {
- list = PyList_New(0);
- for (i = 0; i < n_interfaces; i++) {
- PyObject *o;
- PyList_Append(list, o=pyg_type_wrapper_new(interfaces[i]));
- Py_DECREF(o);
- }
- g_free(interfaces);
- return list;
- }
- PyErr_SetString(PyExc_RuntimeError, "invalid type, or no interfaces");
- return NULL;
-}
-
static void
pyg_object_set_property (GObject *object, guint property_id,
const GValue *value, GParamSpec *pspec)
@@ -306,13 +217,6 @@ pyg_object_get_property (GObject *object, guint property_id,
pyglib_gil_state_release(state);
}
-static void
-pyg_object_class_init(GObjectClass *class, PyObject *py_class)
-{
- class->set_property = pyg_object_set_property;
- class->get_property = pyg_object_get_property;
-}
-
typedef struct _PyGSignalAccumulatorData {
PyObject *callable;
PyObject *user_data;
@@ -428,17 +332,13 @@ create_signal (GType instance_type, const gchar *signal_name, PyObject *tuple)
Py_DECREF(item);
}
- if (py_accum == _pyg_signal_accumulator_true_handled_func)
- accumulator = g_signal_accumulator_true_handled;
- else {
- if (py_accum != NULL && py_accum != Py_None) {
- accum_data = g_new(PyGSignalAccumulatorData, 1);
- accum_data->callable = py_accum;
- Py_INCREF(py_accum);
- accum_data->user_data = py_accum_data;
- Py_XINCREF(py_accum_data);
- accumulator = _pyg_signal_accumulator;
- }
+ if (py_accum != NULL && py_accum != Py_None) {
+ accum_data = g_new(PyGSignalAccumulatorData, 1);
+ accum_data->callable = py_accum;
+ Py_INCREF(py_accum);
+ accum_data->user_data = py_accum_data;
+ Py_XINCREF(py_accum_data);
+ accumulator = _pyg_signal_accumulator;
}
signal_id = g_signal_newv(signal_name, instance_type, signal_flags,
@@ -478,15 +378,14 @@ override_signal(GType instance_type, const gchar *signal_name)
}
static PyObject *
-add_signals (GType instance_type, PyObject *signals)
+add_signals (GObjectClass *klass, PyObject *signals)
{
gboolean ret = TRUE;
- GObjectClass *oclass;
Py_ssize_t pos = 0;
PyObject *key, *value, *overridden_signals = NULL;
+ GType instance_type = G_OBJECT_CLASS_TYPE (klass);
overridden_signals = PyDict_New();
- oclass = g_type_class_ref(instance_type);
while (PyDict_Next(signals, &pos, &key, &value)) {
const gchar *signal_name;
gchar *signal_name_canon, *c;
@@ -524,7 +423,6 @@ add_signals (GType instance_type, PyObject *signals)
if (!ret)
break;
}
- g_type_class_unref(oclass);
if (ret)
return overridden_signals;
else {
@@ -667,7 +565,7 @@ create_property (const gchar *prop_name,
return NULL;
if (pyg_flags_get_value(prop_type, pydefault,
- (gint *)&default_value))
+ &default_value))
return NULL;
pspec = g_param_spec_flags (prop_name, nick, blurb,
@@ -719,13 +617,29 @@ create_property (const gchar *prop_name,
case G_TYPE_POINTER:
if (!PyArg_ParseTuple(args, ""))
return NULL;
- pspec = g_param_spec_pointer (prop_name, nick, blurb, flags);
+ if (prop_type == G_TYPE_GTYPE)
+ pspec = g_param_spec_gtype (prop_name, nick, blurb, G_TYPE_NONE, flags);
+ else
+ pspec = g_param_spec_pointer (prop_name, nick, blurb, flags);
break;
case G_TYPE_OBJECT:
+ case G_TYPE_INTERFACE:
if (!PyArg_ParseTuple(args, ""))
return NULL;
pspec = g_param_spec_object (prop_name, nick, blurb, prop_type, flags);
break;
+ case G_TYPE_VARIANT:
+ {
+ PyObject *pydefault;
+ GVariant *default_value = NULL;
+
+ if (!PyArg_ParseTuple(args, "O", &pydefault))
+ return NULL;
+ if (pydefault != Py_None)
+ default_value = pyg_boxed_get (pydefault, GVariant);
+ pspec = g_param_spec_variant (prop_name, nick, blurb, G_VARIANT_TYPE_ANY, default_value, flags);
+ }
+ break;
default:
/* unhandled pspec type ... */
break;
@@ -743,7 +657,7 @@ create_property (const gchar *prop_name,
return pspec;
}
-GParamSpec *
+static GParamSpec *
pyg_param_spec_from_object (PyObject *tuple)
{
gint val_length;
@@ -794,14 +708,12 @@ pyg_param_spec_from_object (PyObject *tuple)
}
static gboolean
-add_properties (GType instance_type, PyObject *properties)
+add_properties (GObjectClass *klass, PyObject *properties)
{
gboolean ret = TRUE;
- GObjectClass *oclass;
Py_ssize_t pos = 0;
PyObject *key, *value;
- oclass = g_type_class_ref(instance_type);
while (PyDict_Next(properties, &pos, &key, &value)) {
const gchar *prop_name;
GType prop_type;
@@ -867,7 +779,7 @@ add_properties (GType instance_type, PyObject *properties)
Py_DECREF(slice);
if (pspec) {
- g_object_class_install_property(oclass, 1, pspec);
+ g_object_class_install_property(klass, 1, pspec);
} else {
PyObject *type, *value, *traceback;
ret = FALSE;
@@ -877,7 +789,7 @@ add_properties (GType instance_type, PyObject *properties)
g_snprintf(msg, 256,
"%s (while registering property '%s' for GType '%s')",
PYGLIB_PyUnicode_AsString(value),
- prop_name, g_type_name(instance_type));
+ prop_name, G_OBJECT_CLASS_NAME(klass));
Py_DECREF(value);
value = PYGLIB_PyUnicode_FromString(msg);
}
@@ -886,11 +798,63 @@ add_properties (GType instance_type, PyObject *properties)
}
}
- g_type_class_unref(oclass);
return ret;
}
static void
+pyg_object_class_init(GObjectClass *class, PyObject *py_class)
+{
+ PyObject *gproperties, *gsignals, *overridden_signals;
+ PyObject *class_dict = ((PyTypeObject*) py_class)->tp_dict;
+
+ class->set_property = pyg_object_set_property;
+ class->get_property = pyg_object_get_property;
+
+ /* install signals */
+ /* we look this up in the instance dictionary, so we don't
+ * accidentally get a parent type's __gsignals__ attribute. */
+ gsignals = PyDict_GetItemString(class_dict, "__gsignals__");
+ if (gsignals) {
+ if (!PyDict_Check(gsignals)) {
+ PyErr_SetString(PyExc_TypeError,
+ "__gsignals__ attribute not a dict!");
+ return;
+ }
+ if (!(overridden_signals = add_signals(class, gsignals))) {
+ return;
+ }
+ if (PyDict_SetItemString(class_dict, "__gsignals__",
+ overridden_signals)) {
+ return;
+ }
+ Py_DECREF(overridden_signals);
+
+ PyDict_DelItemString(class_dict, "__gsignals__");
+ } else {
+ PyErr_Clear();
+ }
+
+ /* install properties */
+ /* we look this up in the instance dictionary, so we don't
+ * accidentally get a parent type's __gproperties__ attribute. */
+ gproperties = PyDict_GetItemString(class_dict, "__gproperties__");
+ if (gproperties) {
+ if (!PyDict_Check(gproperties)) {
+ PyErr_SetString(PyExc_TypeError,
+ "__gproperties__ attribute not a dict!");
+ return;
+ }
+ if (!add_properties(class, gproperties)) {
+ return;
+ }
+ PyDict_DelItemString(class_dict, "__gproperties__");
+ /* Borrowed reference. Py_DECREF(gproperties); */
+ } else {
+ PyErr_Clear();
+ }
+}
+
+static void
pyg_register_class_init(GType gtype, PyGClassInitFunc class_init)
{
GSList *list;
@@ -988,7 +952,7 @@ get_type_name_for_class(PyTypeObject *class)
for (i = 0; type_name[i] != '\0'; i++)
if (type_name[i] == '.')
type_name[i] = '+';
- if (_pyg_type_from_name(type_name) == 0)
+ if (g_type_from_name(type_name) == 0)
break; /* we now have a unique name */
++name_serial;
}
@@ -997,18 +961,18 @@ get_type_name_for_class(PyTypeObject *class)
}
-static GStaticPrivate pygobject_construction_wrapper = G_STATIC_PRIVATE_INIT;
+static GPrivate pygobject_construction_wrapper;
static inline void
pygobject_init_wrapper_set(PyObject *wrapper)
{
- g_static_private_set(&pygobject_construction_wrapper, wrapper, NULL);
+ g_private_set(&pygobject_construction_wrapper, wrapper);
}
static inline PyObject *
pygobject_init_wrapper_get(void)
{
- return (PyObject *) g_static_private_get(&pygobject_construction_wrapper);
+ return (PyObject *) g_private_get(&pygobject_construction_wrapper);
}
int
@@ -1021,7 +985,11 @@ pygobject_constructv(PyGObject *self,
pygobject_init_wrapper_set((PyObject *) self);
obj = g_object_newv(pyg_type_from_object((PyObject *) self),
n_parameters, parameters);
+
+ if (g_object_is_floating (obj))
+ self->private_flags.flags |= PYGOBJECT_GOBJECT_WAS_FLOATING;
pygobject_sink (obj);
+
pygobject_init_wrapper_set(NULL);
if (self->obj == NULL) {
self->obj = obj;
@@ -1059,7 +1027,9 @@ pygobject__g_instance_init(GTypeInstance *instance,
* now */
PyGILState_STATE state;
state = pyglib_gil_state_ensure();
- wrapper = pygobject_new_full(object, FALSE, g_class);
+ wrapper = pygobject_new_full(object,
+ /*steal=*/ FALSE,
+ g_class);
/* float the wrapper ref here because we are going to orphan it
* so we don't destroy the wrapper. The next call to pygobject_new_full
@@ -1089,7 +1059,7 @@ pygobject__g_instance_init(GTypeInstance *instance,
*/
static void
pyg_type_add_interfaces(PyTypeObject *class, GType instance_type,
- PyObject *bases, gboolean new_interfaces,
+ PyObject *bases,
GType *parent_interfaces, guint n_parent_interfaces)
{
int i;
@@ -1100,10 +1070,8 @@ pyg_type_add_interfaces(PyTypeObject *class, GType instance_type,
}
for (i = 0; i < PyTuple_GET_SIZE(bases); ++i) {
- guint k;
PyObject *base = PyTuple_GET_ITEM(bases, i);
GType itype;
- gboolean is_new = TRUE;
const GInterfaceInfo *iinfo;
GInterfaceInfo iinfo_copy;
@@ -1120,16 +1088,6 @@ pyg_type_add_interfaces(PyTypeObject *class, GType instance_type,
if (!G_TYPE_IS_INTERFACE(itype))
continue;
- for (k = 0; k < n_parent_interfaces; ++k) {
- if (parent_interfaces[k] == itype) {
- is_new = FALSE;
- break;
- }
- }
-
- if ((new_interfaces && !is_new) || (!new_interfaces && is_new))
- continue;
-
iinfo = pyg_lookup_interface_info(itype);
if (!iinfo) {
gchar *error;
@@ -1150,7 +1108,7 @@ pyg_type_add_interfaces(PyTypeObject *class, GType instance_type,
int
pyg_type_register(PyTypeObject *class, const char *type_name)
{
- PyObject *gtype, *gsignals, *gproperties, *overridden_signals;
+ PyObject *gtype;
GType parent_type, instance_type;
GType *parent_interfaces;
guint n_parent_interfaces;
@@ -1216,6 +1174,10 @@ pyg_type_register(PyTypeObject *class, const char *type_name)
g_type_set_qdata(instance_type, g_quark_from_string("PyGObject::class"),
class);
+ /* Mark this GType as a custom python type */
+ g_type_set_qdata(instance_type, pygobject_custom_key,
+ GINT_TO_POINTER (1));
+
/* set new value of __gtype__ on class */
gtype = pyg_type_wrapper_new(instance_type);
PyObject_SetAttrString((PyObject *)class, "__gtype__", gtype);
@@ -1228,88 +1190,22 @@ pyg_type_register(PyTypeObject *class, const char *type_name)
}
/*
- * Note: Interfaces to be implemented are searched twice. First
- * we register interfaces that are already implemented by a parent
- * type. The second time, the remaining interfaces are
- * registered, i.e. the ones that are not implemented by a parent
- * type. In between these two loops, properties and signals are
- * registered. It has to be done this way, in two steps,
- * otherwise glib will complain. If registering all interfaces
- * always before properties, you get an error like:
- *
- * ../gobject:121: Warning: Object class
- * test_interface+MyObject doesn't implement property
- * 'some-property' from interface 'TestInterface'
- *
- * If, on the other hand, you register interfaces after
- * registering the properties, you get something like:
- *
- * ../gobject:121: Warning: cannot add interface type
- * `TestInterface' to type `test_interface+MyUnknown', since
- * type `test_interface+MyUnknown' already conforms to
- * interface
- *
- * This looks like a GLib quirk, but no bug has been filed
- * upstream. However we have a unit test for this particular
- * problem, which can be found in test_interfaces.py, class
- * TestInterfaceImpl.
+ * Note, all interfaces need to be registered before the first
+ * g_type_class_ref(), see bug #686149.
*
* See also comment above pyg_type_add_interfaces().
*/
- pyg_type_add_interfaces(class, instance_type, class->tp_bases, FALSE,
+ pyg_type_add_interfaces(class, instance_type, class->tp_bases,
parent_interfaces, n_parent_interfaces);
- /* we look this up in the instance dictionary, so we don't
- * accidentally get a parent type's __gsignals__ attribute. */
- gsignals = PyDict_GetItemString(class->tp_dict, "__gsignals__");
- if (gsignals) {
- if (!PyDict_Check(gsignals)) {
- PyErr_SetString(PyExc_TypeError,
- "__gsignals__ attribute not a dict!");
- g_free(parent_interfaces);
- return -1;
- }
- if (!(overridden_signals = add_signals(instance_type, gsignals))) {
- g_free(parent_interfaces);
- return -1;
- }
- if (PyDict_SetItemString(class->tp_dict, "__gsignals__",
- overridden_signals)) {
- g_free(parent_interfaces);
- return -1;
- }
- Py_DECREF(overridden_signals);
- } else {
- PyErr_Clear();
- }
- /* we look this up in the instance dictionary, so we don't
- * accidentally get a parent type's __gsignals__ attribute. */
- gproperties = PyDict_GetItemString(class->tp_dict, "__gproperties__");
- if (gproperties) {
- if (!PyDict_Check(gproperties)) {
- PyErr_SetString(PyExc_TypeError,
- "__gproperties__ attribute not a dict!");
- g_free(parent_interfaces);
- return -1;
- }
- if (!add_properties(instance_type, gproperties)) {
- g_free(parent_interfaces);
- return -1;
- }
- PyDict_DelItemString(class->tp_dict, "__gproperties__");
- /* Borrowed reference. Py_DECREF(gproperties); */
- } else {
- PyErr_Clear();
+ gclass = g_type_class_ref(instance_type);
+ if (PyErr_Occurred() != NULL) {
+ g_type_class_unref(gclass);
+ g_free(parent_interfaces);
+ return -1;
}
- /* Register new interfaces, that are _not_ already defined by
- * the parent type. FIXME: See above.
- */
- pyg_type_add_interfaces(class, instance_type, class->tp_bases, TRUE,
- parent_interfaces, n_parent_interfaces);
-
- gclass = g_type_class_ref(instance_type);
if (pyg_run_class_init(instance_type, gclass, class)) {
g_type_class_unref(gclass);
g_free(parent_interfaces);
@@ -1318,9 +1214,8 @@ pyg_type_register(PyTypeObject *class, const char *type_name)
g_type_class_unref(gclass);
g_free(parent_interfaces);
- if (gsignals)
- PyDict_DelItemString(class->tp_dict, "__gsignals__");
-
+ if (PyErr_Occurred() != NULL)
+ return -1;
return 0;
}
@@ -1392,171 +1287,6 @@ pyg_signal_new(PyObject *self, PyObject *args)
}
static PyObject *
-pyg_signal_list_names (PyObject *self, PyObject *args, PyObject *kwargs)
-{
- static char *kwlist[] = { "type", NULL };
- PyObject *py_itype, *list;
- GObjectClass *class = NULL;
- GType itype;
- guint n;
- guint *ids;
- guint i;
- gpointer iface = NULL;
-
- if (!PyArg_ParseTupleAndKeywords(args, kwargs,
- "O:gobject.signal_list_names",
- kwlist, &py_itype))
- return NULL;
- if ((itype = pyg_type_from_object(py_itype)) == 0)
- return NULL;
-
- if (G_TYPE_IS_INSTANTIATABLE(itype)) {
- class = g_type_class_ref(itype);
- if (!class) {
- PyErr_SetString(PyExc_RuntimeError,
- "could not get a reference to type class");
- return NULL;
- }
- } else if (!G_TYPE_IS_INTERFACE(itype)) {
- PyErr_SetString(PyExc_TypeError,
- "type must be instantiable or an interface");
- return NULL;
- } else {
- iface = g_type_default_interface_ref(itype);
- }
-
- ids = g_signal_list_ids(itype, &n);
-
- list = PyTuple_New((gint)n);
- if (list != NULL) {
- for (i = 0; i < n; i++)
- PyTuple_SetItem(list, i,
- PYGLIB_PyUnicode_FromString(g_signal_name(ids[i])));
- }
-
- g_free(ids);
- if (class)
- g_type_class_unref(class);
- else
- g_type_default_interface_unref(iface);
-
- return list;
-}
-
-static PyObject *
-pyg_signal_list_ids (PyObject *self, PyObject *args, PyObject *kwargs)
-{
- static char *kwlist[] = { "type", NULL };
- PyObject *py_itype, *list;
- GObjectClass *class = NULL;
- GType itype;
- guint n;
- guint *ids;
- guint i;
- gpointer iface = NULL;
-
- if (!PyArg_ParseTupleAndKeywords(args, kwargs,
- "O:gobject.signal_list_ids",
- kwlist, &py_itype))
- return NULL;
- if ((itype = pyg_type_from_object(py_itype)) == 0)
- return NULL;
-
- if (G_TYPE_IS_INSTANTIATABLE(itype)) {
- class = g_type_class_ref(itype);
- if (!class) {
- PyErr_SetString(PyExc_RuntimeError,
- "could not get a reference to type class");
- return NULL;
- }
- } else if (!G_TYPE_IS_INTERFACE(itype)) {
- PyErr_SetString(PyExc_TypeError,
- "type must be instantiable or an interface");
- return NULL;
- } else {
- iface = g_type_default_interface_ref(itype);
- }
-
- ids = g_signal_list_ids(itype, &n);
-
- list = PyTuple_New((gint)n);
- if (list == NULL) {
- g_free(ids);
- g_type_class_unref(class);
- return NULL;
- }
-
- for (i = 0; i < n; i++)
- PyTuple_SetItem(list, i, PYGLIB_PyLong_FromLong(ids[i]));
- g_free(ids);
- if (class)
- g_type_class_unref(class);
- else
- g_type_default_interface_unref(iface);
-
- return list;
-}
-
-static PyObject *
-pyg_signal_lookup (PyObject *self, PyObject *args, PyObject *kwargs)
-{
- static char *kwlist[] = { "name", "type", NULL };
- PyObject *py_itype;
- GObjectClass *class = NULL;
- GType itype;
- gchar *signal_name;
- guint id;
- gpointer iface = NULL;
-
- if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sO:gobject.signal_lookup",
- kwlist, &signal_name, &py_itype))
- return NULL;
- if ((itype = pyg_type_from_object(py_itype)) == 0)
- return NULL;
-
- if (G_TYPE_IS_INSTANTIATABLE(itype)) {
- class = g_type_class_ref(itype);
- if (!class) {
- PyErr_SetString(PyExc_RuntimeError,
- "could not get a reference to type class");
- return NULL;
- }
- } else if (!G_TYPE_IS_INTERFACE(itype)) {
- PyErr_SetString(PyExc_TypeError,
- "type must be instantiable or an interface");
- return NULL;
- } else {
- iface = g_type_default_interface_ref(itype);
- }
-
- id = g_signal_lookup(signal_name, itype);
-
- if (class)
- g_type_class_unref(class);
- else
- g_type_default_interface_unref(iface);
- return PYGLIB_PyLong_FromLong(id);
-}
-
-static PyObject *
-pyg_signal_name (PyObject *self, PyObject *args, PyObject *kwargs)
-{
- static char *kwlist[] = { "signal_id", NULL };
- const gchar *signal_name;
- guint id;
-
- if (!PyArg_ParseTupleAndKeywords(args, kwargs, "i:gobject.signal_name",
- kwlist, &id))
- return NULL;
- signal_name = g_signal_name(id);
- if (signal_name)
- return PYGLIB_PyUnicode_FromString(signal_name);
-
- Py_INCREF(Py_None);
- return Py_None;
-}
-
-static PyObject *
pyg_signal_query (PyObject *self, PyObject *args, PyObject *kwargs)
{
static char *kwlist1[] = { "name", "type", NULL };
@@ -1746,7 +1476,7 @@ pyg_object_new (PyGObject *self, PyObject *args, PyObject *kwargs)
if (obj) {
pygobject_sink (obj);
- self = (PyGObject *) pygobject_new_full((GObject *)obj, FALSE, NULL);
+ self = (PyGObject *) pygobject_new((GObject *)obj);
g_object_unref(obj);
} else
self = NULL;
@@ -1793,31 +1523,13 @@ pygobject_gil_state_release (int flag)
pyglib_gil_state_release(flag);
}
-static PyObject *
-pyg_threads_init (PyObject *unused, PyObject *args, PyObject *kwargs)
-{
- if (!pyglib_enable_threads())
- return NULL;
-
- Py_INCREF(Py_None);
- return Py_None;
-}
-
/* Only for backwards compatibility */
-int
+static int
pygobject_enable_threads(void)
{
- if (!pyglib_enable_threads())
- return -1;
return 0;
}
-static void
-pyg_note_threads_enabled(void)
-{
- pygobject_api_functions.threads_enabled = TRUE;
-}
-
static PyObject *
pyg_signal_accumulator_true_handled(PyObject *unused, PyObject *args)
{
@@ -1878,7 +1590,7 @@ out:
static PyObject *
pyg_add_emission_hook(PyGObject *self, PyObject *args)
{
- PyObject *first, *callback, *extra_args, *data;
+ PyObject *first, *callback, *extra_args, *data, *repr;
gchar *name;
gulong hook_id;
guint sigid;
@@ -1910,9 +1622,11 @@ pyg_add_emission_hook(PyGObject *self, PyObject *args)
}
if (!g_signal_parse_name(name, gtype, &sigid, &detail, TRUE)) {
+ repr = PyObject_Repr((PyObject*)self);
PyErr_Format(PyExc_TypeError, "%s: unknown signal name: %s",
- PYGLIB_PyUnicode_AsString(PyObject_Repr((PyObject*)self)),
+ PYGLIB_PyUnicode_AsString(repr),
name);
+ Py_DECREF(repr);
return NULL;
}
extra_args = PySequence_GetSlice(args, 3, len);
@@ -1932,81 +1646,74 @@ pyg_add_emission_hook(PyGObject *self, PyObject *args)
}
static PyObject *
-pyg_remove_emission_hook(PyGObject *self, PyObject *args)
+pyg__install_metaclass(PyObject *dummy, PyTypeObject *metaclass)
{
- PyObject *pygtype;
- char *name;
- guint signal_id;
- gulong hook_id;
- GType gtype;
+ Py_INCREF(metaclass);
+ PyGObject_MetaType = metaclass;
+ Py_INCREF(metaclass);
- if (!PyArg_ParseTuple(args, "Osk:gobject.remove_emission_hook",
- &pygtype, &name, &hook_id))
- return NULL;
+ Py_TYPE(&PyGObject_Type) = metaclass;
- if ((gtype = pyg_type_from_object(pygtype)) == 0) {
- return NULL;
- }
+ Py_INCREF(Py_None);
+ return Py_None;
+}
- if (!g_signal_parse_name(name, gtype, &signal_id, NULL, TRUE)) {
- PyErr_Format(PyExc_TypeError, "%s: unknown signal name: %s",
- PYGLIB_PyUnicode_AsString(PyObject_Repr((PyObject*)self)),
- name);
- return NULL;
+static PyObject *
+pyg__gvalue_get(PyObject *module, PyObject *pygvalue)
+{
+ if (!pyg_boxed_check (pygvalue, G_TYPE_VALUE)) {
+ PyErr_SetString (PyExc_TypeError, "Expected GValue argument.");
+ return NULL;
}
- g_signal_remove_emission_hook(signal_id, hook_id);
-
- Py_INCREF(Py_None);
- return Py_None;
+ return pyg_value_as_pyobject (pyg_boxed_get(pygvalue, GValue),
+ /*copy_boxed=*/ TRUE);
}
static PyObject *
-pyg__install_metaclass(PyObject *dummy, PyTypeObject *metaclass)
+pyg__gvalue_set(PyObject *module, PyObject *args)
{
- Py_INCREF(metaclass);
- PyGObject_MetaType = metaclass;
- Py_INCREF(metaclass);
+ PyObject *pygvalue;
+ PyObject *pyobject;
- Py_TYPE(&PyGObject_Type) = metaclass;
+ if (!PyArg_ParseTuple (args, "OO:_gobject._gvalue_set",
+ &pygvalue, &pyobject))
+ return NULL;
- Py_INCREF(Py_None);
- return Py_None;
+ if (!pyg_boxed_check (pygvalue, G_TYPE_VALUE)) {
+ PyErr_SetString (PyExc_TypeError, "Expected GValue argument.");
+ return NULL;
+ }
+
+ if (pyg_value_from_pyobject_with_error (pyg_boxed_get (pygvalue, GValue),
+ pyobject) == -1)
+ return NULL;
+
+ Py_RETURN_NONE;
}
static PyMethodDef _gobject_functions[] = {
{ "type_name", pyg_type_name, METH_VARARGS },
{ "type_from_name", pyg_type_from_name, METH_VARARGS },
- { "type_parent", pyg_type_parent, METH_VARARGS },
{ "type_is_a", pyg_type_is_a, METH_VARARGS },
- { "type_children", pyg_type_children, METH_VARARGS },
- { "type_interfaces", pyg_type_interfaces, METH_VARARGS },
{ "type_register", _wrap_pyg_type_register, METH_VARARGS },
{ "signal_new", pyg_signal_new, METH_VARARGS },
- { "signal_list_names",
- (PyCFunction)pyg_signal_list_names, METH_VARARGS|METH_KEYWORDS },
- { "signal_list_ids",
- (PyCFunction)pyg_signal_list_ids, METH_VARARGS|METH_KEYWORDS },
- { "signal_lookup",
- (PyCFunction)pyg_signal_lookup, METH_VARARGS|METH_KEYWORDS },
- { "signal_name",
- (PyCFunction)pyg_signal_name, METH_VARARGS|METH_KEYWORDS },
{ "signal_query",
(PyCFunction)pyg_signal_query, METH_VARARGS|METH_KEYWORDS },
{ "list_properties",
pyg_object_class_list_properties, METH_VARARGS },
{ "new",
(PyCFunction)pyg_object_new, METH_VARARGS|METH_KEYWORDS },
- { "threads_init",
- (PyCFunction)pyg_threads_init, METH_VARARGS|METH_KEYWORDS },
{ "signal_accumulator_true_handled",
(PyCFunction)pyg_signal_accumulator_true_handled, METH_VARARGS },
{ "add_emission_hook",
(PyCFunction)pyg_add_emission_hook, METH_VARARGS },
- { "remove_emission_hook",
- (PyCFunction)pyg_remove_emission_hook, METH_VARARGS },
{ "_install_metaclass",
(PyCFunction)pyg__install_metaclass, METH_O },
+ { "_gvalue_get",
+ (PyCFunction)pyg__gvalue_get, METH_O },
+ { "_gvalue_set",
+ (PyCFunction)pyg__gvalue_set, METH_VARARGS },
{ NULL, NULL, 0 }
};
@@ -2356,7 +2063,7 @@ struct _PyGObject_Functions pygobject_api_functions = {
pyg_error_check,
- pyg_set_thread_block_funcs,
+ _pyg_set_thread_block_funcs,
(PyGThreadBlockFunc)0, /* block_threads */
(PyGThreadBlockFunc)0, /* unblock_threads */
@@ -2377,7 +2084,13 @@ struct _PyGObject_Functions pygobject_api_functions = {
pyg_flags_add,
pyg_flags_from_gtype,
- FALSE, /* threads_enabled */
+ /* threads_enabled */
+#ifdef DISABLE_THREADING
+ FALSE,
+#else
+ TRUE,
+#endif
+
pygobject_enable_threads,
pygobject_gil_state_ensure,
pygobject_gil_state_release,
@@ -2389,11 +2102,17 @@ struct _PyGObject_Functions pygobject_api_functions = {
add_warning_redirection,
disable_warning_redirections,
- pyg_type_register_custom_callback,
+ NULL, /* previously type_register_custom */
+
pyg_gerror_exception_check,
pyglib_option_group_new,
- pyg_type_from_object_strict
+ pyg_type_from_object_strict,
+
+ pygobject_new_full,
+ &PyGObject_Type,
+
+ pyg_value_from_pyobject_with_error
};
/* for addon libraries ... */
@@ -2421,52 +2140,17 @@ pygobject_register_constants(PyObject *m)
PyModule_AddIntConstant(m, "G_MAXUSHORT", G_MAXUSHORT);
PyModule_AddIntConstant(m, "G_MININT", G_MININT);
PyModule_AddIntConstant(m, "G_MAXINT", G_MAXINT);
+ PyModule_AddObject(m, "G_MAXUINT", PyLong_FromUnsignedLong(G_MAXUINT));
PyModule_AddObject(m, "G_MINLONG", PyLong_FromLong(G_MINLONG));
PyModule_AddObject(m, "G_MAXLONG", PyLong_FromLong(G_MAXLONG));
PyModule_AddObject(m, "G_MAXULONG", PyLong_FromUnsignedLong(G_MAXULONG));
- PyModule_AddIntConstant(m, "G_MININT8", G_MININT8);
- PyModule_AddIntConstant(m, "G_MAXINT8", G_MAXINT8);
- PyModule_AddIntConstant(m, "G_MAXUINT8", G_MAXUINT8);
- PyModule_AddIntConstant(m, "G_MININT16", G_MININT16);
- PyModule_AddIntConstant(m, "G_MAXINT16", G_MAXINT16);
- PyModule_AddIntConstant(m, "G_MAXUINT16", G_MAXUINT16);
- PyModule_AddIntConstant(m, "G_MININT32", G_MININT32);
- PyModule_AddIntConstant(m, "G_MAXINT32", G_MAXINT32);
- PyModule_AddObject(m, "G_MININT64", PyLong_FromLongLong(G_MININT64));
- PyModule_AddObject(m, "G_MAXINT64", PyLong_FromLongLong(G_MAXINT64));
- PyModule_AddObject(m, "G_MAXUINT64", PyLong_FromUnsignedLongLong(G_MAXUINT64));
-#if PY_VERSION_HEX < 0x02050000 /* 2.3, 2.4 */
- PyModule_AddObject(m, "G_MAXSIZE", PyLong_FromUnsignedLongLong(G_MAXSIZE));
- PyModule_AddObject(m, "G_MAXSSIZE", PyLong_FromUnsignedLongLong(G_MAXSSIZE));
-#elif PY_VERSION_HEX < 0x02060000 /* 2.5 */
- PyModule_AddObject(m, "G_MAXSIZE", PYGLIB_PyLong_FromSize_t(G_MAXSIZE));
- PyModule_AddObject(m, "G_MAXSSIZE", PYGLIB_PyLong_FromSsize_t(G_MAXSSIZE));
-#else /* 2.6+ */
PyModule_AddObject(m, "G_MAXSIZE", PyLong_FromSize_t(G_MAXSIZE));
PyModule_AddObject(m, "G_MAXSSIZE", PyLong_FromSsize_t(G_MAXSSIZE));
-#endif
+ PyModule_AddObject(m, "G_MINSSIZE", PyLong_FromSsize_t(G_MINSSIZE));
PyModule_AddObject(m, "G_MINOFFSET", PyLong_FromLongLong(G_MINOFFSET));
PyModule_AddObject(m, "G_MAXOFFSET", PyLong_FromLongLong(G_MAXOFFSET));
- /* in order for test_properties to pass, G_MAXUINT must be initialized using
- PyLong_FromUnsignedLong, despite AFAICT it is unecessary for 32bit int types.
- In the interests of consistancy I did the same for MAXUINT32 */
- PyModule_AddObject(m, "G_MAXUINT32", PyLong_FromUnsignedLong(G_MAXUINT32));
- PyModule_AddObject(m, "G_MAXUINT", PyLong_FromUnsignedLong(G_MAXUINT));
-
PyModule_AddIntConstant(m, "SIGNAL_RUN_FIRST", G_SIGNAL_RUN_FIRST);
- PyModule_AddIntConstant(m, "SIGNAL_RUN_LAST", G_SIGNAL_RUN_LAST);
- PyModule_AddIntConstant(m, "SIGNAL_RUN_CLEANUP", G_SIGNAL_RUN_CLEANUP);
- PyModule_AddIntConstant(m, "SIGNAL_NO_RECURSE", G_SIGNAL_NO_RECURSE);
- PyModule_AddIntConstant(m, "SIGNAL_DETAILED", G_SIGNAL_DETAILED);
- PyModule_AddIntConstant(m, "SIGNAL_ACTION", G_SIGNAL_ACTION);
- PyModule_AddIntConstant(m, "SIGNAL_NO_HOOKS", G_SIGNAL_NO_HOOKS);
-
- PyModule_AddIntConstant(m, "PARAM_READABLE", G_PARAM_READABLE);
- PyModule_AddIntConstant(m, "PARAM_WRITABLE", G_PARAM_WRITABLE);
- PyModule_AddIntConstant(m, "PARAM_CONSTRUCT", G_PARAM_CONSTRUCT);
- PyModule_AddIntConstant(m, "PARAM_CONSTRUCT_ONLY", G_PARAM_CONSTRUCT_ONLY);
- PyModule_AddIntConstant(m, "PARAM_LAX_VALIDATION", G_PARAM_LAX_VALIDATION);
PyModule_AddIntConstant(m, "PARAM_READWRITE", G_PARAM_READWRITE);
/* The rest of the types are set in __init__.py */
@@ -2516,7 +2200,6 @@ PYGLIB_MODULE_START(_gobject, "_gobject")
{
PyObject *d;
- g_type_init();
pyglib_init();
d = PyModule_GetDict(module);
@@ -2533,12 +2216,5 @@ PYGLIB_MODULE_START(_gobject, "_gobject")
pygobject_pointer_register_types(d);
pygobject_enum_register_types(d);
pygobject_flags_register_types(d);
-
- /* signal registration recognizes this special accumulator 'constant' */
- _pyg_signal_accumulator_true_handled_func = \
- PyDict_GetItemString(d, "signal_accumulator_true_handled");
-
- pygobject_api_functions.threads_enabled = pyglib_threads_enabled();
- _pyglib_notify_on_enabling_threads(pyg_note_threads_enabled);
}
PYGLIB_MODULE_END
diff --git a/gi/_gobject/propertyhelper.py b/gi/_gobject/propertyhelper.py
index 8042d26..c9400df 100644
--- a/gi/_gobject/propertyhelper.py
+++ b/gi/_gobject/propertyhelper.py
@@ -24,16 +24,16 @@ import sys
from . import _gobject
from .constants import \
- TYPE_NONE, TYPE_INTERFACE, TYPE_CHAR, TYPE_UCHAR, \
- TYPE_BOOLEAN, TYPE_INT, TYPE_UINT, TYPE_LONG, \
- TYPE_ULONG, TYPE_INT64, TYPE_UINT64, TYPE_ENUM, \
- TYPE_FLAGS, TYPE_FLOAT, TYPE_DOUBLE, TYPE_STRING, \
- TYPE_POINTER, TYPE_BOXED, TYPE_PARAM, TYPE_OBJECT, \
- TYPE_PYOBJECT
-from .constants import \
- G_MINFLOAT, G_MAXFLOAT, G_MINDOUBLE, G_MAXDOUBLE, \
- G_MININT, G_MAXINT, G_MAXUINT, G_MINLONG, G_MAXLONG, \
- G_MAXULONG
+ TYPE_NONE, TYPE_INTERFACE, TYPE_CHAR, TYPE_UCHAR, \
+ TYPE_BOOLEAN, TYPE_INT, TYPE_UINT, TYPE_LONG, \
+ TYPE_ULONG, TYPE_INT64, TYPE_UINT64, TYPE_ENUM, TYPE_FLAGS, \
+ TYPE_FLOAT, TYPE_DOUBLE, TYPE_STRING, \
+ TYPE_POINTER, TYPE_BOXED, TYPE_PARAM, TYPE_OBJECT, \
+ TYPE_PYOBJECT, TYPE_GTYPE, TYPE_STRV, TYPE_VARIANT
+from ._gobject import \
+ G_MAXFLOAT, G_MAXDOUBLE, \
+ G_MININT, G_MAXINT, G_MAXUINT, G_MINLONG, G_MAXLONG, \
+ G_MAXULONG
if sys.version_info >= (3, 0):
_basestring = str
@@ -42,19 +42,19 @@ else:
_basestring = basestring
_long = long
+
class Property(object):
"""
Creates a new property which in conjunction with GObject subclass will
create a property proxy:
- >>> class MyObject(GObject.GObject):
- >>> ... prop = GObject.Property(type=str)
+ class MyObject(GObject.GObject):
+ ... prop = GObject.Property(type=str)
- >>> obj = MyObject()
- >>> obj.prop = 'value'
+ obj = MyObject()
+ obj.prop = 'value'
- >>> obj.prop
- 'value'
+ obj.prop # now is 'value'
The API is similar to the builtin property:
@@ -73,6 +73,50 @@ class Property(object):
def propInt(self, value):
...
"""
+ _type_from_pytype_lookup = {
+ # Put long_ first in case long_ and int are the same so int clobbers long_
+ _long: TYPE_LONG,
+ int: TYPE_INT,
+ bool: TYPE_BOOLEAN,
+ float: TYPE_DOUBLE,
+ str: TYPE_STRING,
+ object: TYPE_PYOBJECT,
+ }
+
+ _min_value_lookup = {
+ TYPE_UINT: 0,
+ TYPE_ULONG: 0,
+ TYPE_UINT64: 0,
+ # Remember that G_MINFLOAT and G_MINDOUBLE are something different.
+ TYPE_FLOAT: -G_MAXFLOAT,
+ TYPE_DOUBLE: -G_MAXDOUBLE,
+ TYPE_INT: G_MININT,
+ TYPE_LONG: G_MINLONG,
+ TYPE_INT64: -2 ** 63,
+ }
+
+ _max_value_lookup = {
+ TYPE_UINT: G_MAXUINT,
+ TYPE_ULONG: G_MAXULONG,
+ TYPE_INT64: 2 ** 63 - 1,
+ TYPE_UINT64: 2 ** 64 - 1,
+ TYPE_FLOAT: G_MAXFLOAT,
+ TYPE_DOUBLE: G_MAXDOUBLE,
+ TYPE_INT: G_MAXINT,
+ TYPE_LONG: G_MAXLONG,
+ }
+
+ _default_lookup = {
+ TYPE_INT: 0,
+ TYPE_UINT: 0,
+ TYPE_LONG: 0,
+ TYPE_ULONG: 0,
+ TYPE_INT64: 0,
+ TYPE_UINT64: 0,
+ TYPE_STRING: '',
+ TYPE_FLOAT: 0.0,
+ TYPE_DOUBLE: 0.0,
+ }
class __metaclass__(type):
def __repr__(self):
@@ -104,6 +148,8 @@ class Property(object):
@keyword maximum: maximum allowed value (int, float, long only)
"""
+ self.name = None
+
if type is None:
type = object
self.type = self._type_from_python(type)
@@ -117,9 +163,10 @@ class Property(object):
if not isinstance(blurb, _basestring):
raise TypeError("blurb must be a string")
self.blurb = blurb
-
- if flags < 0 or flags > 32:
- raise TypeError("invalid flag value: %r" % (flags,))
+ # Always clobber __doc__ with blurb even if blurb is empty because
+ # we don't want the lengthy Property class documentation showing up
+ # on instances.
+ self.__doc__ = blurb
self.flags = flags
# Call after setting blurb for potential __doc__ usage.
@@ -131,27 +178,27 @@ class Property(object):
getter = self._default_getter
setter = self._default_setter
self.getter(getter)
- self.setter(setter)
+ # do not call self.setter() here, as this defines the property name
+ # already
+ self.fset = setter
if minimum is not None:
if minimum < self._get_minimum():
raise TypeError(
- "Minimum for type %s cannot be lower than %d" % (
- self.type, self._get_minimum()))
+ "Minimum for type %s cannot be lower than %d" %
+ (self.type, self._get_minimum()))
else:
minimum = self._get_minimum()
self.minimum = minimum
if maximum is not None:
if maximum > self._get_maximum():
raise TypeError(
- "Maximum for type %s cannot be higher than %d" % (
- self.type, self._get_maximum()))
+ "Maximum for type %s cannot be higher than %d" %
+ (self.type, self._get_maximum()))
else:
maximum = self._get_maximum()
self.maximum = maximum
- self.name = None
-
self._exc = None
def __repr__(self):
@@ -189,60 +236,47 @@ class Property(object):
def getter(self, fget):
"""Set the getter function to fget. For use as a decorator."""
- if self.__doc__ is None:
- self.__doc__ = fget.__doc__
- if not self.blurb and fget.__doc__:
+ if fget.__doc__:
+ # Always clobber docstring and blurb with the getter docstring.
self.blurb = fget.__doc__
+ self.__doc__ = fget.__doc__
self.fget = fget
return self
def setter(self, fset):
"""Set the setter function to fset. For use as a decorator."""
self.fset = fset
+ # with a setter decorator, we must ignore the name of the method in
+ # install_properties, as this does not need to be a valid property name
+ # and does not define the property name. So set the name here.
+ if not self.name:
+ self.name = self.fget.__name__
return self
def _type_from_python(self, type_):
- if type_ == _long:
- return TYPE_LONG
- elif type_ == int:
- return TYPE_INT
- elif type_ == bool:
- return TYPE_BOOLEAN
- elif type_ == float:
- return TYPE_DOUBLE
- elif type_ == str:
- return TYPE_STRING
- elif type_ == object:
- return TYPE_PYOBJECT
+ if type_ in self._type_from_pytype_lookup:
+ return self._type_from_pytype_lookup[type_]
elif (isinstance(type_, type) and
issubclass(type_, (_gobject.GObject,
_gobject.GEnum,
- _gobject.GBoxed))):
+ _gobject.GFlags,
+ _gobject.GBoxed,
+ _gobject.GInterface))):
return type_.__gtype__
- elif type_ in [TYPE_NONE, TYPE_INTERFACE, TYPE_CHAR, TYPE_UCHAR,
+ elif type_ in (TYPE_NONE, TYPE_INTERFACE, TYPE_CHAR, TYPE_UCHAR,
TYPE_INT, TYPE_UINT, TYPE_BOOLEAN, TYPE_LONG,
TYPE_ULONG, TYPE_INT64, TYPE_UINT64,
TYPE_FLOAT, TYPE_DOUBLE, TYPE_POINTER,
TYPE_BOXED, TYPE_PARAM, TYPE_OBJECT, TYPE_STRING,
- TYPE_PYOBJECT]:
+ TYPE_PYOBJECT, TYPE_GTYPE, TYPE_STRV, TYPE_VARIANT):
return type_
else:
raise TypeError("Unsupported type: %r" % (type_,))
def _get_default(self, default):
- ptype = self.type
if default is not None:
return default
-
- if ptype in [TYPE_INT, TYPE_UINT, TYPE_LONG, TYPE_ULONG,
- TYPE_INT64, TYPE_UINT64]:
- return 0
- elif ptype == TYPE_STRING:
- return ''
- elif ptype == TYPE_FLOAT or ptype == TYPE_DOUBLE:
- return 0.0
- else:
- return None
+ return self._default_lookup.get(self.type, None)
def _check_default(self):
ptype = self.type
@@ -253,61 +287,45 @@ class Property(object):
elif ptype == TYPE_PYOBJECT:
if default is not None:
raise TypeError("object types does not have default values")
+ elif ptype == TYPE_GTYPE:
+ if default is not None:
+ raise TypeError("GType types does not have default values")
elif _gobject.type_is_a(ptype, TYPE_ENUM):
if default is None:
raise TypeError("enum properties needs a default value")
elif not _gobject.type_is_a(default, ptype):
raise TypeError("enum value %s must be an instance of %r" %
(default, ptype))
+ elif _gobject.type_is_a(ptype, TYPE_FLAGS):
+ if not _gobject.type_is_a(default, ptype):
+ raise TypeError("flags value %s must be an instance of %r" %
+ (default, ptype))
+ elif _gobject.type_is_a(ptype, TYPE_STRV) and default is not None:
+ if not isinstance(default, list):
+ raise TypeError("Strv value %s must be a list" % repr(default))
+ for val in default:
+ if type(val) not in (str, bytes):
+ raise TypeError("Strv value %s must contain only strings" % str(default))
+ elif _gobject.type_is_a(ptype, TYPE_VARIANT) and default is not None:
+ if not hasattr(default, '__gtype__') or not _gobject.type_is_a(default, TYPE_VARIANT):
+ raise TypeError("variant value %s must be an instance of %r" %
+ (default, ptype))
def _get_minimum(self):
- ptype = self.type
- if ptype in [TYPE_UINT, TYPE_ULONG, TYPE_UINT64]:
- return 0
- # Remember that G_MINFLOAT and G_MINDOUBLE are something different.
- elif ptype == TYPE_FLOAT:
- return -G_MAXFLOAT
- elif ptype == TYPE_DOUBLE:
- return -G_MAXDOUBLE
- elif ptype == TYPE_INT:
- return G_MININT
- elif ptype == TYPE_LONG:
- return G_MINLONG
- elif ptype == TYPE_INT64:
- return -2 ** 62 - 1
-
- return None
+ return self._min_value_lookup.get(self.type, None)
def _get_maximum(self):
- ptype = self.type
- if ptype == TYPE_UINT:
- return G_MAXUINT
- elif ptype == TYPE_ULONG:
- return G_MAXULONG
- elif ptype == TYPE_INT64:
- return 2 ** 62 - 1
- elif ptype == TYPE_UINT64:
- return 2 ** 63 - 1
- elif ptype == TYPE_FLOAT:
- return G_MAXFLOAT
- elif ptype == TYPE_DOUBLE:
- return G_MAXDOUBLE
- elif ptype == TYPE_INT:
- return G_MAXINT
- elif ptype == TYPE_LONG:
- return G_MAXLONG
-
- return None
+ return self._max_value_lookup.get(self.type, None)
#
# Getter and Setter
#
def _default_setter(self, instance, value):
- setattr(instance, '_property_helper_'+self.name, value)
+ setattr(instance, '_property_helper_' + self.name, value)
def _default_getter(self, instance):
- return getattr(instance, '_property_helper_'+self.name, self.default)
+ return getattr(instance, '_property_helper_' + self.name, self.default)
def _readonly_setter(self, instance, value):
self._exc = TypeError("%s property of %s is read-only" % (
@@ -323,13 +341,14 @@ class Property(object):
def get_pspec_args(self):
ptype = self.type
- if ptype in [TYPE_INT, TYPE_UINT, TYPE_LONG, TYPE_ULONG,
- TYPE_INT64, TYPE_UINT64, TYPE_FLOAT, TYPE_DOUBLE]:
+ if ptype in (TYPE_INT, TYPE_UINT, TYPE_LONG, TYPE_ULONG,
+ TYPE_INT64, TYPE_UINT64, TYPE_FLOAT, TYPE_DOUBLE):
args = self.minimum, self.maximum, self.default
elif (ptype == TYPE_STRING or ptype == TYPE_BOOLEAN or
- ptype.is_a(TYPE_ENUM)):
+ ptype.is_a(TYPE_ENUM) or ptype.is_a(TYPE_FLAGS) or
+ ptype.is_a(TYPE_VARIANT)):
args = (self.default,)
- elif ptype == TYPE_PYOBJECT:
+ elif ptype in (TYPE_PYOBJECT, TYPE_GTYPE):
args = ()
elif ptype.is_a(TYPE_OBJECT) or ptype.is_a(TYPE_BOXED):
args = ()
@@ -337,3 +356,56 @@ class Property(object):
raise NotImplementedError(ptype)
return (self.type, self.nick, self.blurb) + args + (self.flags,)
+
+
+def install_properties(cls):
+ """
+ Scans the given class for instances of Property and merges them
+ into the classes __gproperties__ dict if it exists or adds it if not.
+ """
+ gproperties = cls.__dict__.get('__gproperties__', {})
+
+ props = []
+ for name, prop in cls.__dict__.items():
+ if isinstance(prop, Property): # not same as the built-in
+ # if a property was defined with a decorator, it may already have
+ # a name; if it was defined with an assignment (prop = Property(...))
+ # we set the property's name to the member name
+ if not prop.name:
+ prop.name = name
+ # we will encounter the same property multiple times in case of
+ # custom setter methods
+ if prop.name in gproperties:
+ if gproperties[prop.name] == prop.get_pspec_args():
+ continue
+ raise ValueError('Property %s was already found in __gproperties__' % prop.name)
+ gproperties[prop.name] = prop.get_pspec_args()
+ props.append(prop)
+
+ if not props:
+ return
+
+ cls.__gproperties__ = gproperties
+
+ if 'do_get_property' in cls.__dict__ or 'do_set_property' in cls.__dict__:
+ for prop in props:
+ if prop.fget != prop._default_getter or prop.fset != prop._default_setter:
+ raise TypeError(
+ "GObject subclass %r defines do_get/set_property"
+ " and it also uses a property with a custom setter"
+ " or getter. This is not allowed" %
+ (cls.__name__,))
+
+ def obj_get_property(self, pspec):
+ name = pspec.name.replace('-', '_')
+ prop = getattr(cls, name, None)
+ if prop:
+ return prop.fget(self)
+ cls.do_get_property = obj_get_property
+
+ def obj_set_property(self, pspec, value):
+ name = pspec.name.replace('-', '_')
+ prop = getattr(cls, name, None)
+ if prop:
+ prop.fset(self, value)
+ cls.do_set_property = obj_set_property
diff --git a/gi/_gobject/pygboxed.c b/gi/_gobject/pygboxed.c
index a00386b..541e77b 100644
--- a/gi/_gobject/pygboxed.c
+++ b/gi/_gobject/pygboxed.c
@@ -50,7 +50,8 @@ pyg_boxed_dealloc(PyGBoxed *self)
static PyObject*
pyg_boxed_richcompare(PyObject *self, PyObject *other, int op)
{
- if (Py_TYPE(self) == Py_TYPE(other) && Py_TYPE(self) == &PyGBoxed_Type)
+ if (Py_TYPE(self) == Py_TYPE(other) &&
+ PyObject_IsInstance(self, (PyObject*)&PyGBoxed_Type))
return _pyglib_generic_ptr_richcompare(((PyGBoxed*)self)->boxed,
((PyGBoxed*)other)->boxed,
op);
diff --git a/gi/_gobject/pygenum.c b/gi/_gobject/pygenum.c
index c0a51a9..89e3a06 100644
--- a/gi/_gobject/pygenum.c
+++ b/gi/_gobject/pygenum.c
@@ -27,27 +27,25 @@
#include <pyglib.h>
#include "pygobject-private.h"
-
#include "pygi.h"
+#include "pygenum.h"
+
GQuark pygenum_class_key;
PYGLIB_DEFINE_TYPE("gobject.GEnum", PyGEnum_Type, PyGEnum);
static PyObject *
pyg_enum_val_new(PyObject* subclass, GType gtype, PyObject *intval)
-{
- PyObject *item;
-
-#if PY_VERSION_HEX >= 0x03000000
- item = PyObject_CallMethod((PyObject*)&PyLong_Type, "__new__", "OO",
- subclass, intval);
-#else
- item = ((PyTypeObject *)subclass)->tp_alloc((PyTypeObject *)subclass, 0);
- ((PyIntObject*)item)->ob_ival = PyInt_AS_LONG(intval);
-#endif
+{
+ PyObject *args, *item;
+ args = Py_BuildValue("(O)", intval);
+ item = (&PYGLIB_PyLong_Type)->tp_new((PyTypeObject*)subclass, args, NULL);
+ Py_DECREF(args);
+ if (!item)
+ return NULL;
((PyGEnum*)item)->gtype = gtype;
-
+
return item;
}
@@ -202,6 +200,10 @@ pyg_enum_from_gtype (GType gtype, int value)
return retval;
}
+/*
+ * pyg_enum_add
+ * Dynamically create a class derived from PyGEnum based on the given GType.
+ */
PyObject *
pyg_enum_add (PyObject * module,
const char * typename,
@@ -214,14 +216,17 @@ pyg_enum_add (PyObject * module,
int i;
g_return_val_if_fail(typename != NULL, NULL);
- if (!g_type_is_a(gtype, G_TYPE_ENUM)) {
- g_warning("Trying to register gtype '%s' as enum when in fact it is of type '%s'",
- g_type_name(gtype), g_type_name(G_TYPE_FUNDAMENTAL(gtype)));
+ if (!g_type_is_a (gtype, G_TYPE_ENUM)) {
+ PyErr_Format (PyExc_TypeError, "Trying to register gtype '%s' as enum when in fact it is of type '%s'",
+ g_type_name (gtype), g_type_name (G_TYPE_FUNDAMENTAL (gtype)));
return NULL;
}
state = pyglib_gil_state_ensure();
+ /* Create a new type derived from GEnum. This is the same as:
+ * >>> stub = type(typename, (GEnum,), {})
+ */
instance_dict = PyDict_New();
stub = PyObject_CallFunction((PyObject *)&PyType_Type, "s(O)O",
typename, (PyObject *)&PyGEnum_Type,
@@ -354,7 +359,7 @@ pygobject_enum_register_types(PyObject *d)
PyGEnum_Type.tp_new = pyg_enum_new;
#else
PyGEnum_Type.tp_new = PyLong_Type.tp_new;
- PyGEnum_Type.tp_hash = PyLong_Type.tp_hash;
+ PyGEnum_Type.tp_hash = PyLong_Type.tp_hash;
#endif
PyGEnum_Type.tp_repr = (reprfunc)pyg_enum_repr;
PyGEnum_Type.tp_str = (reprfunc)pyg_enum_repr;
diff --git a/gi/_gobject/pygflags.c b/gi/_gobject/pygflags.c
index 8c00f15..bdeaae7 100644
--- a/gi/_gobject/pygflags.c
+++ b/gi/_gobject/pygflags.c
@@ -3,7 +3,7 @@
* Copyright (C) 1998-2003 James Henstridge
* Copyright (C) 2004 Johan Dahlin
*
- * pygenum.c: GFlags wrapper
+ * pygflags.c: GFlags wrapper
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
@@ -37,18 +37,16 @@ PYGLIB_DEFINE_TYPE("gobject.GFlags", PyGFlags_Type, PyGFlags);
static PyObject *
pyg_flags_val_new(PyObject* subclass, GType gtype, PyObject *intval)
-{
- PyObject *item;
-
-#if PY_VERSION_HEX >= 0x03000000
- item = PyObject_CallMethod((PyObject*)&PyLong_Type, "__new__", "OO",
- subclass, intval);
-#else
- item = ((PyTypeObject *)subclass)->tp_alloc((PyTypeObject *)subclass, 0);
- ((PyIntObject*)item)->ob_ival = PyInt_AS_LONG(intval);
-#endif
+{
+ PyObject *args, *item;
+ args = Py_BuildValue("(O)", intval);
+ g_assert(PyObject_IsSubclass(subclass, (PyObject*) &PyGFlags_Type));
+ item = PYGLIB_PyLong_Type.tp_new((PyTypeObject*)subclass, args, NULL);
+ Py_DECREF(args);
+ if (!item)
+ return NULL;
((PyGFlags*)item)->gtype = gtype;
-
+
return item;
}
@@ -73,7 +71,7 @@ pyg_flags_richcompare(PyGFlags *self, PyObject *other, int op)
}
static char *
-generate_repr(GType gtype, int value)
+generate_repr(GType gtype, guint value)
{
GFlagsClass *flags_class;
char *retval = NULL, *tmp;
@@ -111,13 +109,13 @@ pyg_flags_repr(PyGFlags *self)
char *tmp, *retval;
PyObject *pyretval;
- tmp = generate_repr(self->gtype, PYGLIB_PyLong_AS_LONG(self));
+ tmp = generate_repr(self->gtype, PYGLIB_PyLong_AsUnsignedLong(self));
if (tmp)
retval = g_strdup_printf("<flags %s of type %s>", tmp,
g_type_name(self->gtype));
else
- retval = g_strdup_printf("<flags %ld of type %s>", PYGLIB_PyLong_AS_LONG(self),
+ retval = g_strdup_printf("<flags %ld of type %s>", PYGLIB_PyLong_AsUnsignedLong(self),
g_type_name(self->gtype));
g_free(tmp);
@@ -131,12 +129,12 @@ static PyObject *
pyg_flags_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
{
static char *kwlist[] = { "value", NULL };
- long value;
+ gulong value;
PyObject *pytc, *values, *ret, *pyint;
GType gtype;
GFlagsClass *eclass;
- if (!PyArg_ParseTupleAndKeywords(args, kwargs, "l", kwlist, &value))
+ if (!PyArg_ParseTupleAndKeywords(args, kwargs, "k", kwlist, &value))
return NULL;
pytc = PyObject_GetAttrString((PyObject *)type, "__gtype__");
@@ -170,7 +168,7 @@ pyg_flags_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
g_type_class_unref(eclass);
- pyint = PYGLIB_PyLong_FromLong(value);
+ pyint = PYGLIB_PyLong_FromUnsignedLong(value);
ret = PyDict_GetItem(values, pyint);
if (!ret) {
PyErr_Clear();
@@ -188,10 +186,13 @@ pyg_flags_new(PyTypeObject *type, PyObject *args, PyObject *kwargs)
}
PyObject*
-pyg_flags_from_gtype (GType gtype, int value)
+pyg_flags_from_gtype (GType gtype, guint value)
{
PyObject *pyclass, *values, *retval, *pyint;
+ if (PyErr_Occurred())
+ return PYGLIB_PyLong_FromUnsignedLong(0);
+
g_return_val_if_fail(gtype != G_TYPE_INVALID, NULL);
/* Get a wrapper class by:
@@ -205,11 +206,11 @@ pyg_flags_from_gtype (GType gtype, int value)
if (!pyclass)
pyclass = pyg_flags_add(NULL, g_type_name(gtype), NULL, gtype);
if (!pyclass)
- return PYGLIB_PyLong_FromLong(value);
+ return PYGLIB_PyLong_FromUnsignedLong(value);
values = PyDict_GetItemString(((PyTypeObject *)pyclass)->tp_dict,
"__flags_values__");
- pyint = PYGLIB_PyLong_FromLong(value);
+ pyint = PYGLIB_PyLong_FromUnsignedLong(value);
retval = PyDict_GetItem(values, pyint);
if (!retval) {
PyErr_Clear();
@@ -224,6 +225,10 @@ pyg_flags_from_gtype (GType gtype, int value)
return retval;
}
+/*
+ * pyg_flags_add
+ * Dynamically create a class derived from PyGFlags based on the given GType.
+ */
PyObject *
pyg_flags_add (PyObject * module,
const char * typename,
@@ -244,13 +249,16 @@ pyg_flags_add (PyObject * module,
state = pyglib_gil_state_ensure();
+ /* Create a new type derived from GFlags. This is the same as:
+ * >>> stub = type(typename, (GFlags,), {})
+ */
instance_dict = PyDict_New();
stub = PyObject_CallFunction((PyObject *)&PyType_Type, "s(O)O",
typename, (PyObject *)&PyGFlags_Type,
instance_dict);
Py_DECREF(instance_dict);
if (!stub) {
- PyErr_SetString(PyExc_RuntimeError, "can't create const");
+ PyErr_SetString(PyExc_RuntimeError, "can't create GFlags subtype");
pyglib_gil_state_release(state);
return NULL;
}
@@ -280,7 +288,8 @@ pyg_flags_add (PyObject * module,
for (i = 0; i < eclass->n_values; i++) {
PyObject *item, *intval;
- intval = PYGLIB_PyLong_FromLong(eclass->values[i].value);
+ intval = PYGLIB_PyLong_FromUnsignedLong(eclass->values[i].value);
+ g_assert(PyErr_Occurred() == NULL);
item = pyg_flags_val_new(stub, gtype, intval);
PyDict_SetItem(values, intval, item);
Py_DECREF(intval);
@@ -315,7 +324,7 @@ pyg_flags_and(PyGFlags *a, PyGFlags *b)
(PyObject*)b);
return pyg_flags_from_gtype(a->gtype,
- PYGLIB_PyLong_AS_LONG(a) & PYGLIB_PyLong_AS_LONG(b));
+ PYGLIB_PyLong_AsUnsignedLong(a) & PYGLIB_PyLong_AsUnsignedLong(b));
}
static PyObject *
@@ -325,7 +334,7 @@ pyg_flags_or(PyGFlags *a, PyGFlags *b)
return PYGLIB_PyLong_Type.tp_as_number->nb_or((PyObject*)a,
(PyObject*)b);
- return pyg_flags_from_gtype(a->gtype, PYGLIB_PyLong_AS_LONG(a) | PYGLIB_PyLong_AS_LONG(b));
+ return pyg_flags_from_gtype(a->gtype, PYGLIB_PyLong_AsUnsignedLong(a) | PYGLIB_PyLong_AsUnsignedLong(b));
}
static PyObject *
@@ -336,7 +345,7 @@ pyg_flags_xor(PyGFlags *a, PyGFlags *b)
(PyObject*)b);
return pyg_flags_from_gtype(a->gtype,
- PYGLIB_PyLong_AS_LONG(a) ^ PYGLIB_PyLong_AS_LONG(b));
+ PYGLIB_PyLong_AsUnsignedLong(a) ^ PYGLIB_PyLong_AsUnsignedLong(b));
}
@@ -359,7 +368,7 @@ pyg_flags_get_first_value_name(PyGFlags *self, void *closure)
flags_class = g_type_class_ref(self->gtype);
g_assert(G_IS_FLAGS_CLASS(flags_class));
- flags_value = g_flags_get_first_value(flags_class, PYGLIB_PyLong_AS_LONG(self));
+ flags_value = g_flags_get_first_value(flags_class, PYGLIB_PyLong_AsUnsignedLong(self));
if (flags_value)
retval = PYGLIB_PyUnicode_FromString(flags_value->value_name);
else {
@@ -381,7 +390,7 @@ pyg_flags_get_first_value_nick(PyGFlags *self, void *closure)
flags_class = g_type_class_ref(self->gtype);
g_assert(G_IS_FLAGS_CLASS(flags_class));
- flags_value = g_flags_get_first_value(flags_class, PYGLIB_PyLong_AS_LONG(self));
+ flags_value = g_flags_get_first_value(flags_class, PYGLIB_PyLong_AsUnsignedLong(self));
if (flags_value)
retval = PYGLIB_PyUnicode_FromString(flags_value->value_nick);
else {
@@ -405,7 +414,7 @@ pyg_flags_get_value_names(PyGFlags *self, void *closure)
retval = PyList_New(0);
for (i = 0; i < flags_class->n_values; i++)
- if ((PYGLIB_PyLong_AS_LONG(self) & flags_class->values[i].value) == flags_class->values[i].value)
+ if ((PYGLIB_PyLong_AsUnsignedLong(self) & flags_class->values[i].value) == flags_class->values[i].value)
PyList_Append(retval, PYGLIB_PyUnicode_FromString(flags_class->values[i].value_name));
g_type_class_unref(flags_class);
@@ -425,8 +434,11 @@ pyg_flags_get_value_nicks(PyGFlags *self, void *closure)
retval = PyList_New(0);
for (i = 0; i < flags_class->n_values; i++)
- if ((PYGLIB_PyLong_AS_LONG(self) & flags_class->values[i].value) == flags_class->values[i].value)
- PyList_Append(retval, PYGLIB_PyUnicode_FromString(flags_class->values[i].value_nick));
+ if ((PYGLIB_PyLong_AsUnsignedLong(self) & flags_class->values[i].value) == flags_class->values[i].value) {
+ PyObject *py_nick = PYGLIB_PyUnicode_FromString(flags_class->values[i].value_nick);
+ PyList_Append(retval, py_nick);
+ Py_DECREF (py_nick);
+ }
g_type_class_unref(flags_class);
diff --git a/gi/_gobject/pyginterface.c b/gi/_gobject/pyginterface.c
index 29af546..eb76ba0 100644
--- a/gi/_gobject/pyginterface.c
+++ b/gi/_gobject/pyginterface.c
@@ -28,6 +28,8 @@
#include "pyglib.h"
#include "pygobject-private.h"
+#include "pyginterface.h"
+
GQuark pyginterface_type_key;
GQuark pyginterface_info_key;
diff --git a/gi/_gobject/pygobject-private.h b/gi/_gobject/pygobject-private.h
index 1b1d6db..294b0f6 100644
--- a/gi/_gobject/pygobject-private.h
+++ b/gi/_gobject/pygobject-private.h
@@ -21,39 +21,6 @@
/* from gobjectmodule.c */
extern struct _PyGObject_Functions pygobject_api_functions;
-#define pyg_block_threads() G_STMT_START { \
- if (pygobject_api_functions.block_threads != NULL) \
- (* pygobject_api_functions.block_threads)(); \
- } G_STMT_END
-#define pyg_unblock_threads() G_STMT_START { \
- if (pygobject_api_functions.unblock_threads != NULL) \
- (* pygobject_api_functions.unblock_threads)(); \
- } G_STMT_END
-
-#define pyg_threads_enabled (pygobject_api_functions.threads_enabled)
-
-#ifdef DISABLE_THREADING
-#define pyg_gil_state_ensure() 0
-#define pyg_gil_state_release(state) G_STMT_START { \
- } G_STMT_END
-
-#else
-#define pyg_gil_state_ensure() (pygobject_api_functions.threads_enabled? (PyGILState_Ensure()) : 0)
-#define pyg_gil_state_release(state) G_STMT_START { \
- if (pygobject_api_functions.threads_enabled) \
- PyGILState_Release(state); \
- } G_STMT_END
-#endif
-
-#define pyg_begin_allow_threads \
- G_STMT_START { \
- PyThreadState *_save = NULL; \
- if (pygobject_api_functions.threads_enabled) \
- _save = PyEval_SaveThread();
-#define pyg_end_allow_threads \
- if (pygobject_api_functions.threads_enabled) \
- PyEval_RestoreThread(_save); \
- } G_STMT_END
#ifndef Py_CLEAR /* since Python 2.4 */
@@ -81,6 +48,7 @@ extern GQuark pygobject_wrapper_key;
extern GQuark pygpointer_class_key;
extern GQuark pygobject_has_updated_constructor_key;
extern GQuark pygobject_instance_data_key;
+extern GQuark pygobject_custom_key;
void pygobject_data_free (PyGObjectData *data);
void pyg_destroy_notify (gpointer user_data);
@@ -107,7 +75,7 @@ GType pyg_type_from_object_strict (PyObject *obj, gboolean strict);
GType pyg_type_from_object (PyObject *obj);
gint pyg_enum_get_value (GType enum_type, PyObject *obj, gint *val);
-gint pyg_flags_get_value (GType flag_type, PyObject *obj, gint *val);
+gint pyg_flags_get_value (GType flag_type, PyObject *obj, guint *val);
int pyg_pyobj_to_unichar_conv (PyObject* py_obj, void* ptr);
typedef PyObject *(* fromvaluefunc)(const GValue *value);
@@ -117,6 +85,7 @@ void pyg_register_gtype_custom(GType gtype,
fromvaluefunc from_func,
tovaluefunc to_func);
int pyg_value_from_pyobject(GValue *value, PyObject *obj);
+int pyg_value_from_pyobject_with_error(GValue *value, PyObject *obj);
PyObject *pyg_value_as_pyobject(const GValue *value, gboolean copy_boxed);
int pyg_param_gvalue_from_pyobject(GValue* value,
PyObject* py_obj,
@@ -154,12 +123,10 @@ void pygobject_register_class (PyObject *dict,
PyObject *bases);
void pygobject_register_wrapper (PyObject *self);
PyObject * pygobject_new (GObject *obj);
-PyObject * pygobject_new_full (GObject *obj, gboolean sink, gpointer g_class);
+PyObject * pygobject_new_full (GObject *obj, gboolean steal, gpointer g_class);
void pygobject_sink (GObject *obj);
PyTypeObject *pygobject_lookup_class (GType gtype);
void pygobject_watch_closure (PyObject *self, GClosure *closure);
-void pygobject_register_sinkfunc(GType type,
- void (* sinkfunc)(GObject *object));
int pyg_type_register (PyTypeObject *class,
const gchar *type_name);
@@ -181,7 +148,8 @@ const gchar * pyg_constant_strip_prefix(const gchar *name, const gchar *strip_pr
/* pygflags */
typedef struct {
- PYGLIB_PyLongObject parent;
+ PYGLIB_PyLongObject parent;
+ int zero_pad; /* must always be 0 */
GType gtype;
} PyGFlags;
@@ -194,13 +162,14 @@ extern PyObject * pyg_flags_add (PyObject * module,
const char * strip_prefix,
GType gtype);
extern PyObject * pyg_flags_from_gtype (GType gtype,
- int value);
+ guint value);
/* pygenum */
#define PyGEnum_Check(x) (PyObject_IsInstance((PyObject *)x, (PyObject *)&PyGEnum_Type) && g_type_is_a(((PyGFlags*)x)->gtype, G_TYPE_ENUM))
typedef struct {
- PYGLIB_PyLongObject parent;
+ PYGLIB_PyLongObject parent;
+ int zero_pad; /* must always be 0 */
GType gtype;
} PyGEnum;
@@ -214,12 +183,7 @@ extern PyObject * pyg_enum_from_gtype (GType gtype,
int value);
/* pygtype.c */
-extern GHashTable *custom_type_registration;
-void pyg_type_register_custom_callback(const gchar *type_name,
- PyGTypeRegistrationFunction callback,
- gpointer data);
-PyTypeObject * pyg_type_get_custom(const gchar *name);
-GType _pyg_type_from_name(const gchar *name);
+extern gboolean pyg_gtype_is_custom (GType gtype);
/* pygobject.c */
extern PyTypeObject PyGObjectWeakRef_Type;
diff --git a/gi/_gobject/pygobject.c b/gi/_gobject/pygobject.c
index 8020b40..126c80e 100644
--- a/gi/_gobject/pygobject.c
+++ b/gi/_gobject/pygobject.c
@@ -38,34 +38,66 @@ static int pygobject_clear(PyGObject *self);
static PyObject * pyg_type_get_bases(GType gtype);
static inline int pygobject_clear(PyGObject *self);
static PyObject * pygobject_weak_ref_new(GObject *obj, PyObject *callback, PyObject *user_data);
+static PyObject * pygbinding_weak_ref_new(GObject *obj);
static inline PyGObjectData * pyg_object_peek_inst_data(GObject *obj);
-static PyObject * pygobject_weak_ref_new(GObject *obj, PyObject *callback, PyObject *user_data);
static void pygobject_inherit_slots(PyTypeObject *type, PyObject *bases,
gboolean check_for_present);
static void pygobject_find_slot_for(PyTypeObject *type, PyObject *bases, int slot_offset,
gboolean check_for_present);
GType PY_TYPE_OBJECT = 0;
+GQuark pygobject_custom_key;
GQuark pygobject_class_key;
GQuark pygobject_class_init_key;
GQuark pygobject_wrapper_key;
GQuark pygobject_has_updated_constructor_key;
GQuark pygobject_instance_data_key;
+/* Copied from glib. gobject uses hyphens in property names, but in Python
+ * we can only represent hyphens as underscores. Convert underscores to
+ * hyphens for glib compatibility. */
+static void
+canonicalize_key (gchar *key)
+{
+ gchar *p;
+
+ for (p = key; *p != 0; p++)
+ {
+ gchar c = *p;
+
+ if (c != '-' &&
+ (c < '0' || c > '9') &&
+ (c < 'A' || c > 'Z') &&
+ (c < 'a' || c > 'z'))
+ *p = '-';
+ }
+}
/* -------------- class <-> wrapper manipulation --------------- */
void
pygobject_data_free(PyGObjectData *data)
{
- PyGILState_STATE state = pyglib_gil_state_ensure();
+ /* This function may be called after the python interpreter has already
+ * been shut down. If this happens, we cannot do any python calls, so just
+ * free the memory. */
+ PyGILState_STATE state;
+ PyThreadState *_save = NULL;
+
GSList *closures, *tmp;
- Py_DECREF(data->type);
+
+ if (Py_IsInitialized()) {
+ state = pyglib_gil_state_ensure();
+ Py_DECREF(data->type);
+ /* We cannot use Py_BEGIN_ALLOW_THREADS here because this is inside
+ * a branch. */
+ Py_UNBLOCK_THREADS; /* Modifies _save */
+ }
+
tmp = closures = data->closures;
#ifndef NDEBUG
data->closures = NULL;
data->type = NULL;
#endif
- pyg_begin_allow_threads;
while (tmp) {
GClosure *closure = tmp->data;
@@ -74,13 +106,16 @@ pygobject_data_free(PyGObjectData *data)
tmp = tmp->next;
g_closure_invalidate(closure);
}
- pyg_end_allow_threads;
if (data->closures != NULL)
g_warning("invalidated all closures, but data->closures != NULL !");
g_free(data);
- pyglib_gil_state_release(state);
+
+ if (Py_IsInitialized()) {
+ Py_BLOCK_THREADS; /* Restores _save */
+ pyglib_gil_state_release(state);
+ }
}
static inline PyGObjectData *
@@ -113,8 +148,6 @@ pygobject_get_inst_data(PyGObject *self)
}
-GHashTable *custom_type_registration = NULL;
-
PyTypeObject *PyGObject_MetaType = NULL;
/**
@@ -209,6 +242,8 @@ build_parameter_list(GObjectClass *class)
g_free(name);
}
+ g_type_class_unref(class);
+
if (props)
g_free(props);
@@ -218,7 +253,7 @@ build_parameter_list(GObjectClass *class)
static PyObject*
PyGProps_getattro(PyGProps *self, PyObject *attr)
{
- char *attr_name;
+ char *attr_name, *property_name;
GObjectClass *class;
GParamSpec *pspec;
GValue value = { 0, };
@@ -233,16 +268,18 @@ PyGProps_getattro(PyGProps *self, PyObject *attr)
class = g_type_class_ref(self->gtype);
if (!strcmp(attr_name, "__members__")) {
- return build_parameter_list(class);
- }
-
- if (self->pygobject != NULL) {
- ret = pygi_get_property_value (self->pygobject, attr_name);
- if (ret != NULL)
- return ret;
- }
-
- pspec = g_object_class_find_property(class, attr_name);
+ ret = build_parameter_list(class);
+ g_type_class_unref(class);
+ return ret;
+ }
+
+ /* g_object_class_find_property recurses through the class hierarchy,
+ * so the resulting pspec tells us the owner_type that owns the property
+ * we're dealing with. */
+ property_name = g_strdup(attr_name);
+ canonicalize_key(property_name);
+ pspec = g_object_class_find_property(class, property_name);
+ g_free(property_name);
g_type_class_unref(class);
if (!pspec) {
@@ -255,15 +292,26 @@ PyGProps_getattro(PyGProps *self, PyObject *attr)
return NULL;
}
- /* If we're doing it without an instance, return a GParamSpec */
if (!self->pygobject) {
+ /* If we're doing it without an instance, return a GParamSpec */
return pyg_param_spec_new(pspec);
}
-
+
+ if (!pyg_gtype_is_custom (pspec->owner_type)) {
+ /* The GType is not implemented at the Python level: see if we can
+ * read the property value via gi. */
+ ret = pygi_get_property_value (self->pygobject, pspec);
+ if (ret)
+ return ret;
+ }
+
+ /* The GType is implemented in Python, or we failed to read it via gi:
+ * do a straightforward read. */
+ Py_BEGIN_ALLOW_THREADS;
g_value_init(&value, G_PARAM_SPEC_VALUE_TYPE(pspec));
- pyg_begin_allow_threads;
- g_object_get_property(self->pygobject->obj, attr_name, &value);
- pyg_end_allow_threads;
+ g_object_get_property(self->pygobject->obj, pspec->name, &value);
+ Py_END_ALLOW_THREADS;
+
ret = pyg_param_gvalue_as_pyobject(&value, TRUE, pspec);
g_value_unset(&value);
@@ -272,7 +320,6 @@ PyGProps_getattro(PyGProps *self, PyObject *attr)
static gboolean
set_property_from_pspec(GObject *obj,
- char *attr_name,
GParamSpec *pspec,
PyObject *pvalue)
{
@@ -281,29 +328,34 @@ set_property_from_pspec(GObject *obj,
if (pspec->flags & G_PARAM_CONSTRUCT_ONLY) {
PyErr_Format(PyExc_TypeError,
"property '%s' can only be set in constructor",
- attr_name);
+ pspec->name);
return FALSE;
}
if (!(pspec->flags & G_PARAM_WRITABLE)) {
PyErr_Format(PyExc_TypeError,
- "property '%s' is not writable", attr_name);
+ "property '%s' is not writable", pspec->name);
return FALSE;
}
g_value_init(&value, G_PARAM_SPEC_VALUE_TYPE(pspec));
if (pyg_param_gvalue_from_pyobject(&value, pvalue, pspec) < 0) {
- PyErr_SetString(PyExc_TypeError,
- "could not convert argument to correct param type");
+ PyObject *pvalue_str = PyObject_Str(pvalue);
+ PyErr_Format(PyExc_TypeError,
+ "could not convert '%s' to type '%s' when setting property '%s.%s'",
+ PYGLIB_PyUnicode_AsString(pvalue_str),
+ g_type_name(G_PARAM_SPEC_VALUE_TYPE(pspec)),
+ G_OBJECT_TYPE_NAME(obj),
+ pspec->name);
+ Py_DECREF(pvalue_str);
return FALSE;
}
- pyg_begin_allow_threads;
- g_object_set_property(obj, attr_name, &value);
- pyg_end_allow_threads;
-
+ Py_BEGIN_ALLOW_THREADS;
+ g_object_set_property(obj, pspec->name, &value);
g_value_unset(&value);
-
+ Py_END_ALLOW_THREADS;
+
return TRUE;
}
@@ -313,7 +365,7 @@ static int
PyGProps_setattro(PyGProps *self, PyObject *attr, PyObject *pvalue)
{
GParamSpec *pspec;
- char *attr_name;
+ char *attr_name, *property_name;
GObject *obj;
int ret = -1;
@@ -335,20 +387,33 @@ PyGProps_setattro(PyGProps *self, PyObject *attr, PyObject *pvalue)
return -1;
}
- ret = pygi_set_property_value (self->pygobject, attr_name, pvalue);
- if (ret == 0)
- return 0;
- else if (ret == -1)
- if (PyErr_Occurred())
- return -1;
-
obj = self->pygobject->obj;
- pspec = g_object_class_find_property(G_OBJECT_GET_CLASS(obj), attr_name);
+
+ property_name = g_strdup(attr_name);
+ canonicalize_key(property_name);
+
+ /* g_object_class_find_property recurses through the class hierarchy,
+ * so the resulting pspec tells us the owner_type that owns the property
+ * we're dealing with. */
+ pspec = g_object_class_find_property(G_OBJECT_GET_CLASS(obj),
+ property_name);
+ g_free(property_name);
if (!pspec) {
return PyObject_GenericSetAttr((PyObject *)self, attr, pvalue);
}
+ if (!pyg_gtype_is_custom (pspec->owner_type)) {
+ /* This GType is not implemented in Python: see if we can set the
+ * property via gi. */
+ ret = pygi_set_property_value (self->pygobject, pspec, pvalue);
+ if (ret == 0)
+ return 0;
+ else if (ret == -1 && PyErr_Occurred())
+ return -1;
+ }
- if (!set_property_from_pspec(obj, attr_name, pspec, pvalue))
+ /* This GType is implemented in Python, or we failed to set it via gi:
+ * do a straightforward set. */
+ if (!set_property_from_pspec(obj, pspec, pvalue))
return -1;
return 0;
@@ -654,7 +719,7 @@ pyg_type_get_bases(GType gtype)
*
* Returns: a PyTypeObject for the new type or NULL if it couldn't be created
*/
-PyTypeObject *
+static PyTypeObject *
pygobject_new_with_interfaces(GType gtype)
{
PyGILState_STATE state;
@@ -867,10 +932,6 @@ pygobject_lookup_class(GType gtype)
if (gtype == G_TYPE_INTERFACE)
return &PyGInterface_Type;
- py_type = pyg_type_get_custom(g_type_name(gtype));
- if (py_type)
- return py_type;
-
py_type = g_type_get_qdata(gtype, pygobject_class_key);
if (py_type == NULL) {
py_type = g_type_get_qdata(gtype, pyginterface_type_key);
@@ -890,7 +951,7 @@ pygobject_lookup_class(GType gtype)
/**
* pygobject_new_full:
* @obj: a GObject instance.
- * @sink: whether to sink any floating reference found on the GObject. DEPRECATED.
+ * @steal: whether to steal a ref from the GObject or add (sink) a new one.
* @g_class: the GObjectClass
*
* This function gets a reference to a wrapper for the given GObject
@@ -901,19 +962,30 @@ pygobject_lookup_class(GType gtype)
* Returns: a reference to the wrapper for the GObject.
*/
PyObject *
-pygobject_new_full(GObject *obj, gboolean sink, gpointer g_class)
+pygobject_new_full(GObject *obj, gboolean steal, gpointer g_class)
{
PyGObject *self;
if (obj == NULL) {
- Py_INCREF(Py_None);
- return Py_None;
+ Py_RETURN_NONE;
}
- /* we already have a wrapper for this object -- return it. */
+ /* If the GObject already has a PyObject wrapper stashed in its qdata, re-use it.
+ */
self = (PyGObject *)g_object_get_qdata(obj, pygobject_wrapper_key);
if (self != NULL) {
- pygobject_ref_sink(self);
+ /* Note the use of "pygobject_ref_sink" here only deals with PyObject
+ * wrapper ref counts and has nothing to do with GObject.
+ */
+ pygobject_ref_sink(self);
+
+ /* If steal is true, we also want to decref the incoming GObjects which
+ * already have a Python wrapper because the wrapper is already holding a
+ * strong reference.
+ */
+ if (steal)
+ g_object_unref (obj);
+
} else {
/* create wrapper */
PyGObjectData *inst_data = pyg_object_peek_inst_data(obj);
@@ -939,10 +1011,15 @@ pygobject_new_full(GObject *obj, gboolean sink, gpointer g_class)
self->weakreflist = NULL;
self->private_flags.flags = 0;
self->obj = obj;
- /* if we are creating a wrapper around a newly created object, it can have
- a floating ref (e.g. for methods like Gtk.Button.new()). Bug 640868 */
- g_object_ref_sink(obj);
- pygobject_register_wrapper((PyObject *)self);
+
+ /* If we are not stealing a ref or the object is floating,
+ * add a regular ref or sink the object. */
+ if (g_object_is_floating (obj))
+ self->private_flags.flags |= PYGOBJECT_GOBJECT_WAS_FLOATING;
+ if (!steal || self->private_flags.flags & PYGOBJECT_GOBJECT_WAS_FLOATING)
+ g_object_ref_sink (obj);
+
+ pygobject_register_wrapper((PyObject *)self);
PyObject_GC_Track((PyObject *)self);
}
@@ -953,7 +1030,9 @@ pygobject_new_full(GObject *obj, gboolean sink, gpointer g_class)
PyObject *
pygobject_new(GObject *obj)
{
- return pygobject_new_full(obj, TRUE, NULL);
+ return pygobject_new_full(obj,
+ /*steal=*/FALSE,
+ NULL);
}
static void
@@ -993,6 +1072,7 @@ pygobject_watch_closure(PyObject *self, GClosure *closure)
g_closure_add_invalidate_notifier(closure, data, pygobject_unwatch_closure);
}
+
/* -------------- PyGObject behaviour ----------------- */
PYGLIB_DEFINE_TYPE("gi._gobject.GObject", PyGObject_Type, PyGObject);
@@ -1101,9 +1181,9 @@ pygobject_clear(PyGObject *self)
g_object_remove_toggle_ref(self->obj, pyg_toggle_notify, self);
self->private_flags.flags &= ~PYGOBJECT_USING_TOGGLE_REF;
} else {
- pyg_begin_allow_threads;
+ Py_BEGIN_ALLOW_THREADS;
g_object_unref(self->obj);
- pyg_end_allow_threads;
+ Py_END_ALLOW_THREADS;
}
self->obj = NULL;
}
@@ -1238,9 +1318,10 @@ pygobject_get_property(PyGObject *self, PyObject *args)
return NULL;
}
g_value_init(&value, G_PARAM_SPEC_VALUE_TYPE(pspec));
- pyg_begin_allow_threads;
+ Py_BEGIN_ALLOW_THREADS;
g_object_get_property(self->obj, param_name, &value);
- pyg_end_allow_threads;
+ Py_END_ALLOW_THREADS;
+
ret = pyg_param_gvalue_as_pyobject(&value, TRUE, pspec);
g_value_unset(&value);
return ret;
@@ -1290,9 +1371,9 @@ pygobject_get_properties(PyGObject *self, PyObject *args)
}
g_value_init(&value, G_PARAM_SPEC_VALUE_TYPE(pspec));
- pyg_begin_allow_threads;
+ Py_BEGIN_ALLOW_THREADS;
g_object_get_property(self->obj, property_name, &value);
- pyg_end_allow_threads;
+ Py_END_ALLOW_THREADS;
item = pyg_value_as_pyobject(&value, TRUE);
PyTuple_SetItem(tuple, i, item);
@@ -1309,6 +1390,7 @@ pygobject_set_property(PyGObject *self, PyObject *args)
gchar *param_name;
GParamSpec *pspec;
PyObject *pvalue;
+ int ret = -1;
if (!PyArg_ParseTuple(args, "sO:GObject.set_property", &param_name,
&pvalue))
@@ -1325,9 +1407,17 @@ pygobject_set_property(PyGObject *self, PyObject *args)
return NULL;
}
- if (!set_property_from_pspec(self->obj, param_name, pspec, pvalue))
+ ret = pygi_set_property_value (self, pspec, pvalue);
+ if (ret == 0)
+ goto done;
+ else if (PyErr_Occurred())
+ return NULL;
+
+ if (!set_property_from_pspec(self->obj, pspec, pvalue))
return NULL;
-
+
+done:
+
Py_INCREF(Py_None);
return Py_None;
}
@@ -1351,6 +1441,7 @@ pygobject_set_properties(PyGObject *self, PyObject *args, PyObject *kwargs)
while (kwargs && PyDict_Next (kwargs, &pos, &key, &value)) {
gchar *key_str = PYGLIB_PyUnicode_AsString(key);
GParamSpec *pspec;
+ int ret = -1;
pspec = g_object_class_find_property(class, key_str);
if (!pspec) {
@@ -1363,8 +1454,17 @@ pygobject_set_properties(PyGObject *self, PyObject *args, PyObject *kwargs)
goto exit;
}
- if (!set_property_from_pspec(G_OBJECT(self->obj), key_str, pspec, value))
- goto exit;
+ ret = pygi_set_property_value (self, pspec, value);
+ if (ret != 0) {
+ /* Non-zero return code means that either an error occured ...*/
+ if (PyErr_Occurred())
+ goto exit;
+
+ /* ... or the property couldn't be found , so let's try the default
+ * call. */
+ if (!set_property_from_pspec(G_OBJECT(self->obj), pspec, value))
+ goto exit;
+ }
}
result = Py_None;
@@ -1375,94 +1475,210 @@ pygobject_set_properties(PyGObject *self, PyObject *args, PyObject *kwargs)
return result;
}
-static PyObject *
-pygobject_freeze_notify(PyGObject *self, PyObject *args)
+/* custom closure for gobject bindings */
+static void
+pygbinding_closure_invalidate(gpointer data, GClosure *closure)
{
- if (!PyArg_ParseTuple(args, ":GObject.freeze_notify"))
- return NULL;
-
- CHECK_GOBJECT(self);
-
- g_object_freeze_notify(self->obj);
- Py_INCREF(Py_None);
- return Py_None;
+ PyGClosure *pc = (PyGClosure *)closure;
+ PyGILState_STATE state;
+
+ state = pyglib_gil_state_ensure();
+ Py_XDECREF(pc->callback);
+ Py_XDECREF(pc->extra_args);
+ pyglib_gil_state_release(state);
+
+ pc->callback = NULL;
+ pc->extra_args = NULL;
}
-static PyObject *
-pygobject_notify(PyGObject *self, PyObject *args)
+static void
+pygbinding_marshal (GClosure *closure,
+ GValue *return_value,
+ guint n_param_values,
+ const GValue *param_values,
+ gpointer invocation_hint,
+ gpointer marshal_data)
{
- char *property_name;
+ PyGILState_STATE state;
+ PyGClosure *pc = (PyGClosure *)closure;
+ PyObject *params, *ret;
+ GValue *out_value;
- if (!PyArg_ParseTuple(args, "s:GObject.notify", &property_name))
- return NULL;
-
- CHECK_GOBJECT(self);
-
- g_object_notify(self->obj, property_name);
- Py_INCREF(Py_None);
- return Py_None;
+ state = pyglib_gil_state_ensure();
+
+ /* construct Python tuple for the parameter values */
+ params = PyTuple_New(2);
+ PyTuple_SetItem (params, 0, pyg_value_as_pyobject(&param_values[0], FALSE));
+ PyTuple_SetItem (params, 1, pyg_value_as_pyobject(&param_values[1], FALSE));
+
+ /* params passed to function may have extra arguments */
+ if (pc->extra_args) {
+ PyObject *tuple = params;
+ params = PySequence_Concat(tuple, pc->extra_args);
+ Py_DECREF(tuple);
+ }
+ ret = PyObject_CallObject(pc->callback, params);
+ if (!ret) {
+ PyErr_Print ();
+ goto out;
+ } else if (ret == Py_None) {
+ g_value_set_boolean (return_value, FALSE);
+ goto out;
+ }
+
+ out_value = g_value_get_boxed (&param_values[2]);
+ if (pyg_value_from_pyobject (out_value, ret) != 0) {
+ PyErr_SetString (PyExc_ValueError, "can't convert value");
+ PyErr_Print ();
+ g_value_set_boolean (return_value, FALSE);
+ } else {
+ g_value_set_boolean (return_value, TRUE);
+ }
+
+ Py_DECREF(ret);
+
+out:
+ Py_DECREF(params);
+ pyglib_gil_state_release(state);
}
-static PyObject *
-pygobject_thaw_notify(PyGObject *self, PyObject *args)
+static GClosure *
+pygbinding_closure_new (PyObject *callback, PyObject *extra_args)
{
- if (!PyArg_ParseTuple(args, ":GObject.thaw_notify"))
- return NULL;
-
- CHECK_GOBJECT(self);
-
- g_object_thaw_notify(self->obj);
- Py_INCREF(Py_None);
- return Py_None;
+ GClosure *closure;
+
+ g_return_val_if_fail(callback != NULL, NULL);
+ closure = g_closure_new_simple(sizeof(PyGClosure), NULL);
+ g_closure_add_invalidate_notifier(closure, NULL, pygbinding_closure_invalidate);
+ g_closure_set_marshal(closure, pygbinding_marshal);
+ Py_INCREF(callback);
+ ((PyGClosure *)closure)->callback = callback;
+ if (extra_args && extra_args != Py_None) {
+ Py_INCREF(extra_args);
+ if (!PyTuple_Check(extra_args)) {
+ PyObject *tmp = PyTuple_New(1);
+ PyTuple_SetItem(tmp, 0, extra_args);
+ extra_args = tmp;
+ }
+ ((PyGClosure *)closure)->extra_args = extra_args;
+ }
+ return closure;
}
static PyObject *
-pygobject_get_data(PyGObject *self, PyObject *args)
-{
- char *key;
- GQuark quark;
- PyObject *data;
+pygobject_bind_property(PyGObject *self, PyObject *args)
+{
+ gchar *source_name, *target_name;
+ gchar *source_canon, *target_canon;
+ PyObject *target, *source_repr, *target_repr;
+ PyObject *transform_to, *transform_from, *user_data = NULL;
+ GBinding *binding;
+ GBindingFlags flags = G_BINDING_DEFAULT;
+ GClosure *to_closure = NULL, *from_closure = NULL;
+
+ transform_from = NULL;
+ transform_to = NULL;
+
+ if (!PyArg_ParseTuple(args, "sOs|iOOO:GObject.bind_property",
+ &source_name, &target, &target_name, &flags,
+ &transform_to, &transform_from, &user_data))
+ return NULL;
+
+ CHECK_GOBJECT(self);
+ if (!PyObject_TypeCheck(target, &PyGObject_Type)) {
+ PyErr_SetString(PyExc_TypeError, "Second argument must be a GObject");
+ return NULL;
+ }
- if (!PyArg_ParseTuple(args, "s:GObject.get_data", &key))
- return NULL;
-
- CHECK_GOBJECT(self);
-
- quark = g_quark_from_string(key);
- data = g_object_get_qdata(self->obj, quark);
- if (!data) data = Py_None;
- Py_INCREF(data);
- return data;
+ if (transform_to && transform_to != Py_None) {
+ if (!PyCallable_Check (transform_to)) {
+ PyErr_SetString (PyExc_TypeError,
+ "transform_to must be callable or None");
+ return NULL;
+ }
+ to_closure = pygbinding_closure_new (transform_to, user_data);
+ }
+
+ if (transform_from && transform_from != Py_None) {
+ if (!PyCallable_Check (transform_from)) {
+ PyErr_SetString (PyExc_TypeError,
+ "transform_from must be callable or None");
+ return NULL;
+ }
+ from_closure = pygbinding_closure_new (transform_from, user_data);
+ }
+
+ /* Canonicalize underscores to hyphens. Note the results must be freed. */
+ source_canon = g_strdelimit(g_strdup(source_name), "_", '-');
+ target_canon = g_strdelimit(g_strdup(target_name), "_", '-');
+
+ binding = g_object_bind_property_with_closures (G_OBJECT(self->obj), source_canon,
+ pygobject_get(target), target_canon,
+ flags, to_closure, from_closure);
+ g_free(source_canon);
+ g_free(target_canon);
+ source_canon = target_canon = NULL;
+
+ if (binding == NULL) {
+ source_repr = PyObject_Repr((PyObject*)self);
+ target_repr = PyObject_Repr(target);
+ PyErr_Format(PyExc_TypeError, "Cannot create binding from %s.%s to %s.%s",
+ PYGLIB_PyUnicode_AsString(source_repr), source_name,
+ PYGLIB_PyUnicode_AsString(target_repr), target_name);
+ Py_DECREF(source_repr);
+ Py_DECREF(target_repr);
+ return NULL;
+ }
+
+ return pygbinding_weak_ref_new(G_OBJECT (binding));
}
static PyObject *
-pygobject_set_data(PyGObject *self, PyObject *args)
+connect_helper(PyGObject *self, gchar *name, PyObject *callback, PyObject *extra_args, PyObject *object, gboolean after)
{
- char *key;
- GQuark quark;
- PyObject *data;
+ guint sigid;
+ GQuark detail = 0;
+ GClosure *closure = NULL;
+ gulong handlerid;
+ GSignalQuery query_info;
- if (!PyArg_ParseTuple(args, "sO:GObject.set_data", &key, &data))
+ if (!g_signal_parse_name(name, G_OBJECT_TYPE(self->obj),
+ &sigid, &detail, TRUE)) {
+ PyObject *repr = PyObject_Repr((PyObject*)self);
+ PyErr_Format(PyExc_TypeError, "%s: unknown signal name: %s",
+ PYGLIB_PyUnicode_AsString(repr),
+ name);
+ Py_DECREF(repr);
return NULL;
-
- CHECK_GOBJECT(self);
-
- quark = g_quark_from_string(key);
- Py_INCREF(data);
- g_object_set_qdata_full(self->obj, quark, data, pyg_destroy_notify);
- Py_INCREF(Py_None);
- return Py_None;
+ }
+
+ g_signal_query (sigid, &query_info);
+ if (!pyg_gtype_is_custom (query_info.itype)) {
+ /* The signal is implemented by a non-Python class, probably
+ * something in the gi repository. */
+ closure = pygi_signal_closure_new (self, query_info.itype,
+ query_info.signal_name, callback,
+ extra_args, object);
+ }
+
+ if (!closure) {
+ /* The signal is either implemented at the Python level, or it comes
+ * from a foreign class that we don't have introspection data for. */
+ closure = pyg_closure_new (callback, extra_args, object);
+ }
+
+ pygobject_watch_closure((PyObject *)self, closure);
+ handlerid = g_signal_connect_closure_by_id(self->obj, sigid, detail,
+ closure, after);
+ return PyLong_FromUnsignedLong(handlerid);
}
static PyObject *
pygobject_connect(PyGObject *self, PyObject *args)
{
- PyObject *first, *callback, *extra_args;
+ PyObject *first, *callback, *extra_args, *ret;
gchar *name;
- guint sigid, len;
- gulong handlerid;
- GQuark detail = 0;
- GClosure *closure;
+ guint len;
len = PyTuple_Size(args);
if (len < 2) {
@@ -1483,38 +1699,21 @@ pygobject_connect(PyGObject *self, PyObject *args)
CHECK_GOBJECT(self);
- if (!g_signal_parse_name(name, G_OBJECT_TYPE(self->obj),
- &sigid, &detail, TRUE)) {
- PyErr_Format(PyExc_TypeError, "%s: unknown signal name: %s",
- PYGLIB_PyUnicode_AsString(PyObject_Repr((PyObject*)self)),
- name);
- return NULL;
- }
extra_args = PySequence_GetSlice(args, 2, len);
if (extra_args == NULL)
return NULL;
- closure = pygi_signal_closure_new(self, name, callback, extra_args, NULL);
- if (closure == NULL)
- closure = pyg_closure_new(callback, extra_args, NULL);
-
- pygobject_watch_closure((PyObject *)self, closure);
- handlerid = g_signal_connect_closure_by_id(self->obj, sigid, detail,
- closure, FALSE);
+ ret = connect_helper(self, name, callback, extra_args, NULL, FALSE);
Py_DECREF(extra_args);
- return PyLong_FromUnsignedLong(handlerid);
+ return ret;
}
static PyObject *
pygobject_connect_after(PyGObject *self, PyObject *args)
{
- PyObject *first, *callback, *extra_args;
+ PyObject *first, *callback, *extra_args, *ret;
gchar *name;
- guint sigid;
- gulong handlerid;
Py_ssize_t len;
- GQuark detail;
- GClosure *closure;
len = PyTuple_Size(args);
if (len < 2) {
@@ -1536,38 +1735,21 @@ pygobject_connect_after(PyGObject *self, PyObject *args)
CHECK_GOBJECT(self);
- if (!g_signal_parse_name(name, G_OBJECT_TYPE(self->obj),
- &sigid, &detail, TRUE)) {
- PyErr_Format(PyExc_TypeError, "%s: unknown signal name: %s",
- PYGLIB_PyUnicode_AsString(PyObject_Repr((PyObject*)self)),
- name);
- return NULL;
- }
extra_args = PySequence_GetSlice(args, 2, len);
if (extra_args == NULL)
return NULL;
- closure = pygi_signal_closure_new(self, name, callback, extra_args, NULL);
- if (closure == NULL)
- closure = pyg_closure_new(callback, extra_args, NULL);
-
- pygobject_watch_closure((PyObject *)self, closure);
- handlerid = g_signal_connect_closure_by_id(self->obj, sigid, detail,
- closure, TRUE);
+ ret = connect_helper(self, name, callback, extra_args, NULL, TRUE);
Py_DECREF(extra_args);
- return PyLong_FromUnsignedLong(handlerid);
+ return ret;
}
static PyObject *
pygobject_connect_object(PyGObject *self, PyObject *args)
{
- PyObject *first, *callback, *extra_args, *object;
+ PyObject *first, *callback, *extra_args, *object, *ret;
gchar *name;
- guint sigid;
- gulong handlerid;
Py_ssize_t len;
- GQuark detail;
- GClosure *closure;
len = PyTuple_Size(args);
if (len < 3) {
@@ -1589,38 +1771,21 @@ pygobject_connect_object(PyGObject *self, PyObject *args)
CHECK_GOBJECT(self);
- if (!g_signal_parse_name(name, G_OBJECT_TYPE(self->obj),
- &sigid, &detail, TRUE)) {
- PyErr_Format(PyExc_TypeError, "%s: unknown signal name: %s",
- PYGLIB_PyUnicode_AsString(PyObject_Repr((PyObject*)self)),
- name);
- return NULL;
- }
extra_args = PySequence_GetSlice(args, 3, len);
if (extra_args == NULL)
return NULL;
- closure = pygi_signal_closure_new(self, name, callback, extra_args, object);
- if (closure == NULL)
- closure = pyg_closure_new(callback, extra_args, object);
-
- pygobject_watch_closure((PyObject *)self, closure);
- handlerid = g_signal_connect_closure_by_id(self->obj, sigid, detail,
- closure, FALSE);
+ ret = connect_helper(self, name, callback, extra_args, object, FALSE);
Py_DECREF(extra_args);
- return PyLong_FromUnsignedLong(handlerid);
+ return ret;
}
static PyObject *
pygobject_connect_object_after(PyGObject *self, PyObject *args)
{
- PyObject *first, *callback, *extra_args, *object;
+ PyObject *first, *callback, *extra_args, *object, *ret;
gchar *name;
- guint sigid;
- gulong handlerid;
Py_ssize_t len;
- GQuark detail;
- GClosure *closure;
len = PyTuple_Size(args);
if (len < 3) {
@@ -1642,91 +1807,22 @@ pygobject_connect_object_after(PyGObject *self, PyObject *args)
CHECK_GOBJECT(self);
- if (!g_signal_parse_name(name, G_OBJECT_TYPE(self->obj),
- &sigid, &detail, TRUE)) {
- PyErr_Format(PyExc_TypeError, "%s: unknown signal name: %s",
- PYGLIB_PyUnicode_AsString(PyObject_Repr((PyObject*)self)),
- name);
- return NULL;
- }
extra_args = PySequence_GetSlice(args, 3, len);
if (extra_args == NULL)
return NULL;
- closure = pygi_signal_closure_new(self, name, callback, extra_args, object);
- if (closure == NULL)
- closure = pyg_closure_new(callback, extra_args, object);
-
- pygobject_watch_closure((PyObject *)self, closure);
- handlerid = g_signal_connect_closure_by_id(self->obj, sigid, detail,
- closure, TRUE);
+ ret = connect_helper(self, name, callback, extra_args, object, TRUE);
Py_DECREF(extra_args);
- return PyLong_FromUnsignedLong(handlerid);
-}
-
-static PyObject *
-pygobject_disconnect(PyGObject *self, PyObject *args)
-{
- gulong handler_id;
-
- if (!PyArg_ParseTuple(args, "k:GObject.disconnect", &handler_id))
- return NULL;
-
- CHECK_GOBJECT(self);
-
- g_signal_handler_disconnect(self->obj, handler_id);
- Py_INCREF(Py_None);
- return Py_None;
-}
-
-static PyObject *
-pygobject_handler_is_connected(PyGObject *self, PyObject *args)
-{
- gulong handler_id;
-
- if (!PyArg_ParseTuple(args, "k:GObject.handler_is_connected", &handler_id))
- return NULL;
-
-
- CHECK_GOBJECT(self);
-
- return PyBool_FromLong(g_signal_handler_is_connected(self->obj, handler_id));
-}
-
-static PyObject *
-pygobject_handler_block(PyGObject *self, PyObject *args)
-{
- gulong handler_id;
-
- if (!PyArg_ParseTuple(args, "k:GObject.handler_block", &handler_id))
- return NULL;
-
- CHECK_GOBJECT(self);
-
- g_signal_handler_block(self->obj, handler_id);
- Py_INCREF(Py_None);
- return Py_None;
-}
-
-static PyObject *
-pygobject_handler_unblock(PyGObject *self, PyObject *args)
-{
- gulong handler_id;
-
- if (!PyArg_ParseTuple(args, "k:GObject.handler_unblock", &handler_id))
- return NULL;
- g_signal_handler_unblock(self->obj, handler_id);
- Py_INCREF(Py_None);
- return Py_None;
+ return ret;
}
static PyObject *
pygobject_emit(PyGObject *self, PyObject *args)
{
- guint signal_id, i;
+ guint signal_id, i, j;
Py_ssize_t len;
GQuark detail;
- PyObject *first, *py_ret;
+ PyObject *first, *py_ret, *repr = NULL;
gchar *name;
GSignalQuery query;
GValue *params, ret = { 0, };
@@ -1747,9 +1843,11 @@ pygobject_emit(PyGObject *self, PyObject *args)
if (!g_signal_parse_name(name, G_OBJECT_TYPE(self->obj),
&signal_id, &detail, TRUE)) {
+ repr = PyObject_Repr((PyObject*)self);
PyErr_Format(PyExc_TypeError, "%s: unknown signal name: %s",
- PYGLIB_PyUnicode_AsString(PyObject_Repr((PyObject*)self)),
+ PYGLIB_PyUnicode_AsString(repr),
name);
+ Py_DECREF(repr);
return NULL;
}
g_signal_query(signal_id, &query);
@@ -1778,11 +1876,11 @@ pygobject_emit(PyGObject *self, PyObject *args)
g_snprintf(buf, sizeof(buf),
"could not convert type %s to %s required for parameter %d",
Py_TYPE(item)->tp_name,
- g_type_name(G_VALUE_TYPE(&params[i+1])), i);
+ G_VALUE_TYPE_NAME(&params[i+1]), i);
PyErr_SetString(PyExc_TypeError, buf);
- for (i = 0; i < query.n_params + 1; i++)
- g_value_unset(&params[i]);
+ for (j = 0; j <= i; j++)
+ g_value_unset(&params[j]);
g_free(params);
return NULL;
@@ -1810,30 +1908,6 @@ pygobject_emit(PyGObject *self, PyObject *args)
}
static PyObject *
-pygobject_stop_emission(PyGObject *self, PyObject *args)
-{
- gchar *signal;
- guint signal_id;
- GQuark detail;
-
- if (!PyArg_ParseTuple(args, "s:GObject.stop_emission", &signal))
- return NULL;
-
- CHECK_GOBJECT(self);
-
- if (!g_signal_parse_name(signal, G_OBJECT_TYPE(self->obj),
- &signal_id, &detail, TRUE)) {
- PyErr_Format(PyExc_TypeError, "%s: unknown signal name: %s",
- PYGLIB_PyUnicode_AsString(PyObject_Repr((PyObject*)self)),
- signal);
- return NULL;
- }
- g_signal_stop_emission(self->obj, signal_id, detail);
- Py_INCREF(Py_None);
- return Py_None;
-}
-
-static PyObject *
pygobject_chain_from_overridden(PyGObject *self, PyObject *args)
{
GSignalInvocationHint *ihint;
@@ -1955,7 +2029,7 @@ pygobject_deepcopy(PyGObject *self, PyObject *args)
static PyObject *
pygobject_disconnect_by_func(PyGObject *self, PyObject *args)
{
- PyObject *pyfunc = NULL;
+ PyObject *pyfunc = NULL, *repr = NULL;
GClosure *closure = NULL;
guint retval;
@@ -1971,8 +2045,10 @@ pygobject_disconnect_by_func(PyGObject *self, PyObject *args)
closure = gclosure_from_pyfunc(self, pyfunc);
if (!closure) {
+ repr = PyObject_Repr((PyObject*)pyfunc);
PyErr_Format(PyExc_TypeError, "nothing connected to %s",
- PYGLIB_PyUnicode_AsString(PyObject_Repr((PyObject*)pyfunc)));
+ PYGLIB_PyUnicode_AsString(repr));
+ Py_DECREF(repr);
return NULL;
}
@@ -1987,7 +2063,7 @@ pygobject_disconnect_by_func(PyGObject *self, PyObject *args)
static PyObject *
pygobject_handler_block_by_func(PyGObject *self, PyObject *args)
{
- PyObject *pyfunc = NULL;
+ PyObject *pyfunc = NULL, *repr = NULL;
GClosure *closure = NULL;
guint retval;
@@ -2003,8 +2079,10 @@ pygobject_handler_block_by_func(PyGObject *self, PyObject *args)
closure = gclosure_from_pyfunc(self, pyfunc);
if (!closure) {
+ repr = PyObject_Repr((PyObject*)pyfunc);
PyErr_Format(PyExc_TypeError, "nothing connected to %s",
- PYGLIB_PyUnicode_AsString(PyObject_Repr((PyObject*)pyfunc)));
+ PYGLIB_PyUnicode_AsString(repr));
+ Py_DECREF(repr);
return NULL;
}
@@ -2019,7 +2097,7 @@ pygobject_handler_block_by_func(PyGObject *self, PyObject *args)
static PyObject *
pygobject_handler_unblock_by_func(PyGObject *self, PyObject *args)
{
- PyObject *pyfunc = NULL;
+ PyObject *pyfunc = NULL, *repr = NULL;
GClosure *closure = NULL;
guint retval;
@@ -2035,8 +2113,10 @@ pygobject_handler_unblock_by_func(PyGObject *self, PyObject *args)
closure = gclosure_from_pyfunc(self, pyfunc);
if (!closure) {
+ repr = PyObject_Repr((PyObject*)pyfunc);
PyErr_Format(PyExc_TypeError, "nothing connected to %s",
- PYGLIB_PyUnicode_AsString(PyObject_Repr((PyObject*)pyfunc)));
+ PYGLIB_PyUnicode_AsString(repr));
+ Py_DECREF(repr);
return NULL;
}
@@ -2048,31 +2128,21 @@ pygobject_handler_unblock_by_func(PyGObject *self, PyObject *args)
return PYGLIB_PyLong_FromLong(retval);
}
+
static PyMethodDef pygobject_methods[] = {
{ "get_property", (PyCFunction)pygobject_get_property, METH_VARARGS },
{ "get_properties", (PyCFunction)pygobject_get_properties, METH_VARARGS },
{ "set_property", (PyCFunction)pygobject_set_property, METH_VARARGS },
{ "set_properties", (PyCFunction)pygobject_set_properties, METH_VARARGS|METH_KEYWORDS },
- { "freeze_notify", (PyCFunction)pygobject_freeze_notify, METH_VARARGS },
- { "notify", (PyCFunction)pygobject_notify, METH_VARARGS },
- { "thaw_notify", (PyCFunction)pygobject_thaw_notify, METH_VARARGS },
- { "get_data", (PyCFunction)pygobject_get_data, METH_VARARGS },
- { "set_data", (PyCFunction)pygobject_set_data, METH_VARARGS },
+ { "bind_property", (PyCFunction)pygobject_bind_property, METH_VARARGS|METH_KEYWORDS },
{ "connect", (PyCFunction)pygobject_connect, METH_VARARGS },
{ "connect_after", (PyCFunction)pygobject_connect_after, METH_VARARGS },
{ "connect_object", (PyCFunction)pygobject_connect_object, METH_VARARGS },
{ "connect_object_after", (PyCFunction)pygobject_connect_object_after, METH_VARARGS },
- { "disconnect", (PyCFunction)pygobject_disconnect, METH_VARARGS },
{ "disconnect_by_func", (PyCFunction)pygobject_disconnect_by_func, METH_VARARGS },
- { "handler_disconnect", (PyCFunction)pygobject_disconnect, METH_VARARGS },
- { "handler_is_connected", (PyCFunction)pygobject_handler_is_connected, METH_VARARGS },
- { "handler_block", (PyCFunction)pygobject_handler_block, METH_VARARGS },
- { "handler_unblock", (PyCFunction)pygobject_handler_unblock,METH_VARARGS },
{ "handler_block_by_func", (PyCFunction)pygobject_handler_block_by_func, METH_VARARGS },
{ "handler_unblock_by_func", (PyCFunction)pygobject_handler_unblock_by_func, METH_VARARGS },
{ "emit", (PyCFunction)pygobject_emit, METH_VARARGS },
- { "stop_emission", (PyCFunction)pygobject_stop_emission, METH_VARARGS },
- { "emit_stop_by_name", (PyCFunction)pygobject_stop_emission,METH_VARARGS },
{ "chain", (PyCFunction)pygobject_chain_from_overridden,METH_VARARGS },
{ "weak_ref", (PyCFunction)pygobject_weak_ref, METH_VARARGS },
{ "__copy__", (PyCFunction)pygobject_copy, METH_NOARGS },
@@ -2098,9 +2168,19 @@ pygobject_get_dict(PyGObject *self, void *closure)
static PyObject *
pygobject_get_refcount(PyGObject *self, void *closure)
{
+ if (self->obj == NULL) {
+ PyErr_Format(PyExc_TypeError, "GObject instance is not yet created");
+ return NULL;
+ }
return PYGLIB_PyLong_FromLong(self->obj->ref_count);
}
+static PyObject *
+pygobject_get_pointer(PyGObject *self, void *closure)
+{
+ return PYGLIB_CPointer_WrapPointer (self->obj, NULL);
+}
+
static int
pygobject_setattro(PyObject *self, PyObject *name, PyObject *value)
{
@@ -2119,6 +2199,7 @@ pygobject_setattro(PyObject *self, PyObject *name, PyObject *value)
static PyGetSetDef pygobject_getsets[] = {
{ "__dict__", (getter)pygobject_get_dict, (setter)0 },
{ "__grefcount__", (getter)pygobject_get_refcount, (setter)0, },
+ { "__gpointer__", (getter)pygobject_get_pointer, (setter)0, },
{ NULL, 0, 0 }
};
@@ -2246,19 +2327,70 @@ pygobject_weak_ref_call(PyGObjectWeakRef *self, PyObject *args, PyObject *kw)
return NULL;
if (self->obj)
- return pygobject_new_full(self->obj, FALSE, NULL);
+ return pygobject_new(self->obj);
else {
Py_INCREF(Py_None);
return Py_None;
}
}
+
+/* -------------- GBinding Weak Reference ----------------- */
+
+/**
+ * BindingWeakRef
+ *
+ * The BindingWeakRef object is used to manage GBinding objects within python
+ * created through GObject.bind_property. It is a sub-class PyGObjectWeakRef so
+ * that we can maintain the same reference counting semantics between Python
+ * and GObject Binding objects. This gives explicit direct control of the
+ * binding lifetime by using the "unbind" method on the BindingWeakRef object
+ * along with implicit management based on the lifetime of the source or
+ * target objects.
+ */
+
+PYGLIB_DEFINE_TYPE("gi._gobject.GBindingWeakRef", PyGBindingWeakRef_Type, PyGObjectWeakRef);
+
+static PyObject *
+pygbinding_weak_ref_new(GObject *obj)
+{
+ PyGObjectWeakRef *self;
+
+ self = PyObject_GC_New(PyGObjectWeakRef, &PyGBindingWeakRef_Type);
+ self->callback = NULL;
+ self->user_data = NULL;
+ self->obj = obj;
+ g_object_weak_ref(self->obj, (GWeakNotify) pygobject_weak_ref_notify, self);
+ return (PyObject *) self;
+}
+
+static PyObject *
+pygbinding_weak_ref_unbind(PyGObjectWeakRef *self, PyObject *args)
+{
+ if (!self->obj) {
+ PyErr_SetString(PyExc_ValueError, "weak binding ref already unreffed");
+ return NULL;
+ }
+ g_object_unref(self->obj);
+ Py_INCREF(Py_None);
+ return Py_None;
+}
+
+static PyMethodDef pygbinding_weak_ref_methods[] = {
+ { "unbind", (PyCFunction)pygbinding_weak_ref_unbind, METH_NOARGS},
+ { NULL, NULL, 0}
+};
+
+
static gpointer
pyobject_copy(gpointer boxed)
{
PyObject *object = boxed;
+ PyGILState_STATE state;
+ state = pyglib_gil_state_ensure();
Py_INCREF(object);
+ pyglib_gil_state_release(state);
return object;
}
@@ -2278,6 +2410,7 @@ pygobject_object_register_types(PyObject *d)
{
PyObject *o, *descr;
+ pygobject_custom_key = g_quark_from_static_string("PyGObject::custom");
pygobject_class_key = g_quark_from_static_string("PyGObject::class");
pygobject_class_init_key = g_quark_from_static_string("PyGObject::class-init");
pygobject_wrapper_key = g_quark_from_static_string("PyGObject::wrapper");
@@ -2354,4 +2487,12 @@ pygobject_object_register_types(PyObject *d)
if (PyType_Ready(&PyGObjectWeakRef_Type) < 0)
return;
PyDict_SetItemString(d, "GObjectWeakRef", (PyObject *) &PyGObjectWeakRef_Type);
+
+ PyGBindingWeakRef_Type.tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_GC;
+ PyGBindingWeakRef_Type.tp_doc = "A GBinding weak reference";
+ PyGBindingWeakRef_Type.tp_methods = pygbinding_weak_ref_methods;
+ PyGBindingWeakRef_Type.tp_base = &PyGObjectWeakRef_Type;
+ if (PyType_Ready(&PyGBindingWeakRef_Type) < 0)
+ return;
+ PyDict_SetItemString(d, "GBindingWeakRef", (PyObject *) &PyGBindingWeakRef_Type);
}
diff --git a/gi/_gobject/pygobject.h b/gi/_gobject/pygobject.h
index 8879fd0..76b8b11 100644
--- a/gi/_gobject/pygobject.h
+++ b/gi/_gobject/pygobject.h
@@ -24,7 +24,8 @@ struct _PyGClosure {
typedef enum {
PYGOBJECT_USING_TOGGLE_REF = 1 << 0,
- PYGOBJECT_IS_FLOATING_REF = 1 << 1
+ PYGOBJECT_IS_FLOATING_REF = 1 << 1,
+ PYGOBJECT_GOBJECT_WAS_FLOATING = 1 << 2,
} PyGObjectFlags;
/* closures is just an alias for what is found in the
@@ -102,7 +103,7 @@ struct _PyGObject_Functions {
PyObject *(* type_wrapper_new)(GType type);
gint (* enum_get_value)(GType enum_type, PyObject *obj, gint *val);
- gint (* flags_get_value)(GType flag_type, PyObject *obj, gint *val);
+ gint (* flags_get_value)(GType flag_type, PyObject *obj, guint *val);
void (* register_gtype_custom)(GType gtype,
PyObject *(* from_func)(const GValue *value),
int (* to_func)(GValue *value, PyObject *obj));
@@ -139,6 +140,7 @@ struct _PyGObject_Functions {
PyGThreadBlockFunc unblock_threads_func);
PyGThreadBlockFunc block_threads;
PyGThreadBlockFunc unblock_threads;
+
PyTypeObject *paramspec_type;
PyObject *(* paramspec_new)(GParamSpec *spec);
GParamSpec *(*paramspec_get)(PyObject *tuple);
@@ -167,7 +169,7 @@ struct _PyGObject_Functions {
const char *type_name_,
const char *strip_prefix,
GType gtype);
- PyObject* (*flags_from_gtype)(GType gtype, int value);
+ PyObject* (*flags_from_gtype)(GType gtype, guint value);
gboolean threads_enabled;
int (*enable_threads) (void);
@@ -182,14 +184,42 @@ struct _PyGObject_Functions {
void (*add_warning_redirection) (const char *domain,
PyObject *warning);
void (*disable_warning_redirections) (void);
- void (*type_register_custom)(const gchar *type_name,
- PyGTypeRegistrationFunction callback,
- gpointer data);
+
+ /* type_register_custom API now removed, but leave a pointer here to not
+ * break ABI. */
+ void *_type_register_custom;
+
gboolean (*gerror_exception_check) (GError **error);
PyObject* (*option_group_new) (GOptionGroup *group);
- GType (* type_from_object_strict) (PyObject *obj, gboolean strict);
+ GType (* type_from_object_strict) (PyObject *obj, gboolean strict);
+
+ PyObject *(* newgobj_full)(GObject *obj, gboolean steal, gpointer g_class);
+ PyTypeObject *object_type;
+ int (* value_from_pyobject_with_error)(GValue *value, PyObject *obj);
};
+
+#ifdef DISABLE_THREADING
+# define pyg_threads_enabled FALSE
+# define pyg_gil_state_ensure() 0
+# define pyg_gil_state_release(state)
+# define pyg_begin_allow_threads G_STMT_START {
+# define pyg_end_allow_threads } G_STMT_END
+#else
+# define pyg_threads_enabled TRUE
+# define pyg_gil_state_ensure PyGILState_Ensure
+# define pyg_gil_state_release PyGILState_Release
+# define pyg_begin_allow_threads Py_BEGIN_ALLOW_THREADS
+# define pyg_end_allow_threads Py_END_ALLOW_THREADS
+#endif
+
+/* Deprecated, only available for API compatibility. */
+#define pyg_enable_threads()
+#define pyg_set_thread_block_funcs(a, b)
+#define pyg_block_threads()
+#define pyg_unblock_threads()
+
+
#ifndef _INSIDE_PYGOBJECT_
#if defined(NO_IMPORT) || defined(NO_IMPORT_PYGOBJECT)
@@ -202,6 +232,8 @@ struct _PyGObject_Functions *_PyGObject_API;
#define pygobject_register_wrapper (_PyGObject_API->register_wrapper)
#define pygobject_lookup_class (_PyGObject_API->lookup_class)
#define pygobject_new (_PyGObject_API->newgobj)
+#define pygobject_new_full (_PyGObject_API->newgobj_full)
+#define PyGObject_Type (*_PyGObject_API->object_type)
#define pyg_closure_new (_PyGObject_API->closure_new)
#define pygobject_watch_closure (_PyGObject_API->object_watch_closure)
#define pyg_closure_set_exception_handler (_PyGObject_API->closure_set_exception_handler)
@@ -213,6 +245,7 @@ struct _PyGObject_Functions *_PyGObject_API;
#define pyg_flags_get_value (_PyGObject_API->flags_get_value)
#define pyg_register_gtype_custom (_PyGObject_API->register_gtype_custom)
#define pyg_value_from_pyobject (_PyGObject_API->value_from_pyobject)
+#define pyg_value_from_pyobject_with_error (_PyGObject_API->value_from_pyobject_with_error)
#define pyg_value_as_pyobject (_PyGObject_API->value_as_pyobject)
#define pyg_register_interface (_PyGObject_API->register_interface)
#define PyGBoxed_Type (*_PyGObject_API->boxed_type)
@@ -225,7 +258,6 @@ struct _PyGObject_Functions *_PyGObject_API;
#define pyg_flags_add_constants (_PyGObject_API->flags_add_constants)
#define pyg_constant_strip_prefix (_PyGObject_API->constant_strip_prefix)
#define pyg_error_check (_PyGObject_API->error_check)
-#define pyg_set_thread_block_funcs (_PyGObject_API->set_thread_block_funcs)
#define PyGParamSpec_Type (*_PyGObject_API->paramspec_type)
#define pyg_param_spec_new (_PyGObject_API->paramspec_new)
#define pyg_param_spec_from_object (_PyGObject_API->paramspec_get)
@@ -239,38 +271,13 @@ struct _PyGObject_Functions *_PyGObject_API;
#define PyGFlags_Type (*_PyGObject_API->flags_type)
#define pyg_flags_add (_PyGObject_API->flags_add)
#define pyg_flags_from_gtype (_PyGObject_API->flags_from_gtype)
-#define pyg_enable_threads (_PyGObject_API->enable_threads)
-#define pyg_gil_state_ensure (_PyGObject_API->gil_state_ensure)
-#define pyg_gil_state_release (_PyGObject_API->gil_state_release)
#define pyg_register_class_init (_PyGObject_API->register_class_init)
#define pyg_register_interface_info (_PyGObject_API->register_interface_info)
#define pyg_add_warning_redirection (_PyGObject_API->add_warning_redirection)
#define pyg_disable_warning_redirections (_PyGObject_API->disable_warning_redirections)
-#define pyg_type_register_custom_callback (_PyGObject_API->type_register_custom)
#define pyg_gerror_exception_check (_PyGObject_API->gerror_exception_check)
#define pyg_option_group_new (_PyGObject_API->option_group_new)
-#define pyg_block_threads() G_STMT_START { \
- if (_PyGObject_API->block_threads != NULL) \
- (* _PyGObject_API->block_threads)(); \
- } G_STMT_END
-#define pyg_unblock_threads() G_STMT_START { \
- if (_PyGObject_API->unblock_threads != NULL) \
- (* _PyGObject_API->unblock_threads)(); \
- } G_STMT_END
-
-#define pyg_threads_enabled (_PyGObject_API->threads_enabled)
-
-#define pyg_begin_allow_threads \
- G_STMT_START { \
- PyThreadState *_save = NULL; \
- if (_PyGObject_API->threads_enabled) \
- _save = PyEval_SaveThread();
-#define pyg_end_allow_threads \
- if (_PyGObject_API->threads_enabled) \
- PyEval_RestoreThread(_save); \
- } G_STMT_END
-
/**
* pygobject_init:
@@ -336,14 +343,8 @@ pygobject_init(int req_major, int req_minor, int req_micro)
}
cobject = PyObject_GetAttrString(gobject, "_PyGObject_API");
-#if PY_VERSION_HEX >= 0x03000000
if (cobject && PyCapsule_CheckExact(cobject))
_PyGObject_API = (struct _PyGObject_Functions *) PyCapsule_GetPointer(cobject, "gobject._PyGObject_API");
-
-#else
- if (cobject && PyCObject_Check(cobject))
- _PyGObject_API = (struct _PyGObject_Functions *) PyCObject_AsVoidPtr(cobject);
-#endif
else {
PyErr_SetString(PyExc_ImportError,
"could not import gobject (could not find _PyGObject_API object)");
diff --git a/gi/_gobject/pygtype.c b/gi/_gobject/pygtype.c
index 79e9dc6..9dc1153 100644
--- a/gi/_gobject/pygtype.c
+++ b/gi/_gobject/pygtype.c
@@ -268,7 +268,7 @@ _wrap_g_type_from_name(PyGTypeWrapper *_, PyObject *args)
if (!PyArg_ParseTuple(args, "s:GType.from_name", &type_name))
return NULL;
- type = _pyg_type_from_name(type_name);
+ type = g_type_from_name(type_name);
if (type == 0) {
PyErr_SetString(PyExc_RuntimeError, "unknown type name");
return NULL;
@@ -401,7 +401,7 @@ pyg_type_from_object_strict(PyObject *obj, gboolean strict)
if (PYGLIB_PyUnicode_Check(obj)) {
gchar *name = PYGLIB_PyUnicode_AsString(obj);
- type = _pyg_type_from_name(name);
+ type = g_type_from_name(name);
if (type != 0) {
return type;
}
@@ -538,7 +538,7 @@ pyg_enum_get_value(GType enum_type, PyObject *obj, gint *val)
* Returns: 0 on success or -1 on failure
*/
gint
-pyg_flags_get_value(GType flag_type, PyObject *obj, gint *val)
+pyg_flags_get_value(GType flag_type, PyObject *obj, guint *val)
{
GFlagsClass *fclass = NULL;
gint res = -1;
@@ -548,7 +548,7 @@ pyg_flags_get_value(GType flag_type, PyObject *obj, gint *val)
*val = 0;
res = 0;
} else if (PYGLIB_PyLong_Check(obj)) {
- *val = PYGLIB_PyLong_AsLong(obj);
+ *val = PYGLIB_PyLong_AsUnsignedLong(obj);
res = 0;
} else if (PyLong_Check(obj)) {
*val = PyLong_AsLongLong(obj);
@@ -663,8 +663,8 @@ pyg_register_gtype_custom(GType gtype,
static int
pyg_value_array_from_pyobject(GValue *value,
- PyObject *obj,
- const GParamSpecValueArray *pspec)
+ PyObject *obj,
+ const GParamSpecValueArray *pspec)
{
int len;
GValueArray *value_array;
@@ -672,63 +672,120 @@ pyg_value_array_from_pyobject(GValue *value,
len = PySequence_Length(obj);
if (len == -1) {
- PyErr_Clear();
- return -1;
+ PyErr_Clear();
+ return -1;
}
if (pspec && pspec->fixed_n_elements > 0 && len != pspec->fixed_n_elements)
- return -1;
+ return -1;
value_array = g_value_array_new(len);
for (i = 0; i < len; ++i) {
- PyObject *item = PySequence_GetItem(obj, i);
- GType type;
- GValue item_value = { 0, };
- int status;
-
- if (! item) {
- PyErr_Clear();
- g_value_array_free(value_array);
- return -1;
- }
+ PyObject *item = PySequence_GetItem(obj, i);
+ GType type;
+ GValue item_value = { 0, };
+ int status;
+
+ if (! item) {
+ PyErr_Clear();
+ g_value_array_free(value_array);
+ return -1;
+ }
- if (pspec && pspec->element_spec)
- type = G_PARAM_SPEC_VALUE_TYPE(pspec->element_spec);
- else if (item == Py_None)
- type = G_TYPE_POINTER; /* store None as NULL */
- else {
- type = pyg_type_from_object((PyObject*)Py_TYPE(item));
- if (! type) {
- PyErr_Clear();
- g_value_array_free(value_array);
- Py_DECREF(item);
- return -1;
- }
- }
+ if (pspec && pspec->element_spec)
+ type = G_PARAM_SPEC_VALUE_TYPE(pspec->element_spec);
+ else if (item == Py_None)
+ type = G_TYPE_POINTER; /* store None as NULL */
+ else {
+ type = pyg_type_from_object((PyObject*)Py_TYPE(item));
+ if (! type) {
+ PyErr_Clear();
+ g_value_array_free(value_array);
+ Py_DECREF(item);
+ return -1;
+ }
+ }
- g_value_init(&item_value, type);
- status = (pspec && pspec->element_spec)
- ? pyg_param_gvalue_from_pyobject(&item_value, item, pspec->element_spec)
- : pyg_value_from_pyobject(&item_value, item);
- Py_DECREF(item);
+ g_value_init(&item_value, type);
+ status = (pspec && pspec->element_spec)
+ ? pyg_param_gvalue_from_pyobject(&item_value, item, pspec->element_spec)
+ : pyg_value_from_pyobject(&item_value, item);
+ Py_DECREF(item);
- if (status == -1) {
- g_value_array_free(value_array);
- g_value_unset(&item_value);
- return -1;
- }
+ if (status == -1) {
+ g_value_array_free(value_array);
+ g_value_unset(&item_value);
+ return -1;
+ }
- g_value_array_append(value_array, &item_value);
- g_value_unset(&item_value);
+ g_value_array_append(value_array, &item_value);
+ g_value_unset(&item_value);
}
g_value_take_boxed(value, value_array);
return 0;
}
+static int
+pyg_array_from_pyobject(GValue *value,
+ PyObject *obj)
+{
+ int len;
+ GArray *array;
+ int i;
+
+ len = PySequence_Length(obj);
+ if (len == -1) {
+ PyErr_Clear();
+ return -1;
+ }
+
+ array = g_array_new(FALSE, TRUE, sizeof(GValue));
+
+ for (i = 0; i < len; ++i) {
+ PyObject *item = PySequence_GetItem(obj, i);
+ GType type;
+ GValue item_value = { 0, };
+ int status;
+
+ if (! item) {
+ PyErr_Clear();
+ g_array_free(array, FALSE);
+ return -1;
+ }
+
+ if (item == Py_None)
+ type = G_TYPE_POINTER; /* store None as NULL */
+ else {
+ type = pyg_type_from_object((PyObject*)Py_TYPE(item));
+ if (! type) {
+ PyErr_Clear();
+ g_array_free(array, FALSE);
+ Py_DECREF(item);
+ return -1;
+ }
+ }
+
+ g_value_init(&item_value, type);
+ status = pyg_value_from_pyobject(&item_value, item);
+ Py_DECREF(item);
+
+ if (status == -1) {
+ g_array_free(array, FALSE);
+ g_value_unset(&item_value);
+ return -1;
+ }
+
+ g_array_append_val(array, item_value);
+ }
+
+ g_value_take_boxed(value, array);
+ return 0;
+}
+
/**
- * pyg_value_from_pyobject:
+ * pyg_value_from_pyobject_with_error:
* @value: the GValue object to store the converted value in.
* @obj: the Python object to convert.
*
@@ -740,95 +797,110 @@ pyg_value_array_from_pyobject(GValue *value,
* Returns: 0 on success, -1 on error.
*/
int
-pyg_value_from_pyobject(GValue *value, PyObject *obj)
+pyg_value_from_pyobject_with_error(GValue *value, PyObject *obj)
{
PyObject *tmp;
GType value_type = G_VALUE_TYPE(value);
switch (G_TYPE_FUNDAMENTAL(value_type)) {
case G_TYPE_INTERFACE:
- /* we only handle interface types that have a GObject prereq */
- if (g_type_is_a(value_type, G_TYPE_OBJECT)) {
- if (obj == Py_None)
- g_value_set_object(value, NULL);
- else {
- if (!PyObject_TypeCheck(obj, &PyGObject_Type)) {
- return -1;
- }
- if (!G_TYPE_CHECK_INSTANCE_TYPE(pygobject_get(obj),
- value_type)) {
- return -1;
- }
- g_value_set_object(value, pygobject_get(obj));
- }
- } else {
- return -1;
- }
- break;
+ /* we only handle interface types that have a GObject prereq */
+ if (g_type_is_a(value_type, G_TYPE_OBJECT)) {
+ if (obj == Py_None)
+ g_value_set_object(value, NULL);
+ else {
+ if (!PyObject_TypeCheck(obj, &PyGObject_Type)) {
+ PyErr_SetString(PyExc_TypeError, "GObject is required");
+ return -1;
+ }
+ if (!G_TYPE_CHECK_INSTANCE_TYPE(pygobject_get(obj),
+ value_type)) {
+ PyErr_SetString(PyExc_TypeError, "Invalid GObject type for assignment");
+ return -1;
+ }
+ g_value_set_object(value, pygobject_get(obj));
+ }
+ } else {
+ PyErr_SetString(PyExc_TypeError, "Unsupported conversion");
+ return -1;
+ }
+ break;
case G_TYPE_CHAR:
+ if (PYGLIB_PyLong_Check(obj)) {
+ glong val;
+ val = PYGLIB_PyLong_AsLong(obj);
+ if (val >= -128 && val <= 127)
+ g_value_set_schar(value, (gchar) val);
+ else
+ return -1;
+ }
#if PY_VERSION_HEX < 0x03000000
- if (PyString_Check(obj)) {
- g_value_set_schar(value, PyString_AsString(obj)[0]);
- } else
+ else if (PyString_Check(obj)) {
+ g_value_set_schar(value, PyString_AsString(obj)[0]);
+ }
#endif
- if (PyUnicode_Check(obj)) {
- tmp = PyUnicode_AsUTF8String(obj);
- g_value_set_schar(value, PYGLIB_PyBytes_AsString(tmp)[0]);
- Py_DECREF(tmp);
- } else {
- PyErr_Clear();
- return -1;
- }
+ else if (PyUnicode_Check(obj)) {
+ tmp = PyUnicode_AsUTF8String(obj);
+ g_value_set_schar(value, PYGLIB_PyBytes_AsString(tmp)[0]);
+ Py_DECREF(tmp);
+ } else {
+ PyErr_SetString(PyExc_TypeError, "Cannot convert to TYPE_CHAR");
+ return -1;
+ }
- break;
+ break;
case G_TYPE_UCHAR:
- if (PYGLIB_PyLong_Check(obj)) {
- glong val;
- val = PYGLIB_PyLong_AsLong(obj);
- if (val >= 0 && val <= 255)
- g_value_set_uchar(value, (guchar)PYGLIB_PyLong_AsLong (obj));
- else
- return -1;
+ if (PYGLIB_PyLong_Check(obj)) {
+ glong val;
+ val = PYGLIB_PyLong_AsLong(obj);
+ if (val >= 0 && val <= 255)
+ g_value_set_uchar(value, (guchar) val);
+ else
+ return -1;
#if PY_VERSION_HEX < 0x03000000
- } else if (PyString_Check(obj)) {
- g_value_set_uchar(value, PyString_AsString(obj)[0]);
+ } else if (PyString_Check(obj)) {
+ g_value_set_uchar(value, PyString_AsString(obj)[0]);
#endif
- } else if (PyUnicode_Check(obj)) {
- tmp = PyUnicode_AsUTF8String(obj);
- g_value_set_uchar(value, PYGLIB_PyBytes_AsString(tmp)[0]);
- Py_DECREF(tmp);
- } else {
- PyErr_Clear();
- return -1;
- }
- break;
+ } else if (PyUnicode_Check(obj)) {
+ tmp = PyUnicode_AsUTF8String(obj);
+ g_value_set_uchar(value, PYGLIB_PyBytes_AsString(tmp)[0]);
+ Py_DECREF(tmp);
+ } else {
+ PyErr_Clear();
+ return -1;
+ }
+ break;
case G_TYPE_BOOLEAN:
- g_value_set_boolean(value, PyObject_IsTrue(obj));
- break;
+ g_value_set_boolean(value, PyObject_IsTrue(obj));
+ break;
case G_TYPE_INT:
- g_value_set_int(value, PYGLIB_PyLong_AsLong(obj));
- break;
+ g_value_set_int(value, PYGLIB_PyLong_AsLong(obj));
+ break;
case G_TYPE_UINT:
- {
- if (PYGLIB_PyLong_Check(obj)) {
- glong val;
-
- val = PYGLIB_PyLong_AsLong(obj);
- if (val >= 0 && val <= G_MAXUINT)
- g_value_set_uint(value, (guint)val);
- else
- return -1;
- } else {
- g_value_set_uint(value, PyLong_AsUnsignedLong(obj));
- }
- }
- break;
+ {
+ if (PYGLIB_PyLong_Check(obj)) {
+ guint val;
+
+ /* check that number is not negative */
+ if (PyLong_AsLongLong(obj) < 0)
+ return -1;
+
+ val = PyLong_AsUnsignedLong(obj);
+ if (val <= G_MAXUINT)
+ g_value_set_uint(value, val);
+ else
+ return -1;
+ } else {
+ g_value_set_uint(value, PyLong_AsUnsignedLong(obj));
+ }
+ }
+ break;
case G_TYPE_LONG:
- g_value_set_long(value, PYGLIB_PyLong_AsLong(obj));
- break;
+ g_value_set_long(value, PYGLIB_PyLong_AsLong(obj));
+ break;
case G_TYPE_ULONG:
#if PY_VERSION_HEX < 0x03000000
- if (PyInt_Check(obj)) {
+ if (PyInt_Check(obj)) {
long val;
val = PYGLIB_PyLong_AsLong(obj);
@@ -839,14 +911,14 @@ pyg_value_from_pyobject(GValue *value, PyObject *obj)
g_value_set_ulong(value, (gulong)val);
} else
#endif
- if (PyLong_Check(obj))
- g_value_set_ulong(value, PyLong_AsUnsignedLong(obj));
- else
- return -1;
+ if (PyLong_Check(obj))
+ g_value_set_ulong(value, PyLong_AsUnsignedLong(obj));
+ else
+ return -1;
break;
case G_TYPE_INT64:
- g_value_set_int64(value, PyLong_AsLongLong(obj));
- break;
+ g_value_set_int64(value, PyLong_AsLongLong(obj));
+ break;
case G_TYPE_UINT64:
#if PY_VERSION_HEX < 0x03000000
if (PyInt_Check(obj)) {
@@ -858,154 +930,209 @@ pyg_value_from_pyobject(GValue *value, PyObject *obj)
g_value_set_uint64(value, v);
} else
#endif
- if (PyLong_Check(obj))
- g_value_set_uint64(value, PyLong_AsUnsignedLongLong(obj));
- else
- return -1;
- break;
+ if (PyLong_Check(obj))
+ g_value_set_uint64(value, PyLong_AsUnsignedLongLong(obj));
+ else
+ return -1;
+ break;
case G_TYPE_ENUM:
- {
- gint val = 0;
- if (pyg_enum_get_value(G_VALUE_TYPE(value), obj, &val) < 0) {
- PyErr_Clear();
- return -1;
- }
- g_value_set_enum(value, val);
- }
- break;
+ {
+ gint val = 0;
+ if (pyg_enum_get_value(G_VALUE_TYPE(value), obj, &val) < 0) {
+ return -1;
+ }
+ g_value_set_enum(value, val);
+ }
+ break;
case G_TYPE_FLAGS:
- {
- gint val = 0;
- if (pyg_flags_get_value(G_VALUE_TYPE(value), obj, &val) < 0) {
- PyErr_Clear();
- return -1;
- }
- g_value_set_flags(value, val);
- }
- break;
+ {
+ guint val = 0;
+ if (pyg_flags_get_value(G_VALUE_TYPE(value), obj, &val) < 0) {
+ return -1;
+ }
+ g_value_set_flags(value, val);
+ }
+ break;
case G_TYPE_FLOAT:
- g_value_set_float(value, PyFloat_AsDouble(obj));
- break;
+ g_value_set_float(value, PyFloat_AsDouble(obj));
+ break;
case G_TYPE_DOUBLE:
- g_value_set_double(value, PyFloat_AsDouble(obj));
- break;
+ g_value_set_double(value, PyFloat_AsDouble(obj));
+ break;
case G_TYPE_STRING:
- if (obj == Py_None) {
- g_value_set_string(value, NULL);
- } else {
- PyObject* tmp_str = PyObject_Str(obj);
- if (tmp_str == NULL) {
- PyErr_Clear();
- if (PyUnicode_Check(obj)) {
- tmp = PyUnicode_AsUTF8String(obj);
- g_value_set_string(value, PYGLIB_PyBytes_AsString(tmp));
- Py_DECREF(tmp);
- } else {
- return -1;
- }
- } else {
+ if (obj == Py_None) {
+ g_value_set_string(value, NULL);
+ } else {
+ PyObject* tmp_str = PyObject_Str(obj);
+ if (tmp_str == NULL) {
+ PyErr_Clear();
+ if (PyUnicode_Check(obj)) {
+ tmp = PyUnicode_AsUTF8String(obj);
+ g_value_set_string(value, PYGLIB_PyBytes_AsString(tmp));
+ Py_DECREF(tmp);
+ } else {
+ PyErr_SetString(PyExc_TypeError, "Expected string");
+ return -1;
+ }
+ } else {
#if PY_VERSION_HEX < 0x03000000
- g_value_set_string(value, PyString_AsString(tmp_str));
+ g_value_set_string(value, PyString_AsString(tmp_str));
#else
- tmp = PyUnicode_AsUTF8String(tmp_str);
- g_value_set_string(value, PyBytes_AsString(tmp));
- Py_DECREF(tmp);
+ tmp = PyUnicode_AsUTF8String(tmp_str);
+ g_value_set_string(value, PyBytes_AsString(tmp));
+ Py_DECREF(tmp);
#endif
- }
- Py_XDECREF(tmp_str);
- }
- break;
+ }
+ Py_XDECREF(tmp_str);
+ }
+ break;
case G_TYPE_POINTER:
- if (obj == Py_None)
- g_value_set_pointer(value, NULL);
- else if (PyObject_TypeCheck(obj, &PyGPointer_Type) &&
- G_VALUE_HOLDS(value, ((PyGPointer *)obj)->gtype))
- g_value_set_pointer(value, pyg_pointer_get(obj, gpointer));
- else if (PYGLIB_CPointer_Check(obj))
- g_value_set_pointer(value, PYGLIB_CPointer_GetPointer(obj, NULL));
- else
- return -1;
- break;
+ if (obj == Py_None)
+ g_value_set_pointer(value, NULL);
+ else if (PyObject_TypeCheck(obj, &PyGPointer_Type) &&
+ G_VALUE_HOLDS(value, ((PyGPointer *)obj)->gtype))
+ g_value_set_pointer(value, pyg_pointer_get(obj, gpointer));
+ else if (PYGLIB_CPointer_Check(obj))
+ g_value_set_pointer(value, PYGLIB_CPointer_GetPointer(obj, NULL));
+ else if (G_VALUE_HOLDS_GTYPE (value))
+ g_value_set_gtype (value, pyg_type_from_object (obj));
+ else {
+ PyErr_SetString(PyExc_TypeError, "Expected pointer");
+ return -1;
+ }
+ break;
case G_TYPE_BOXED: {
- PyGTypeMarshal *bm;
-
- if (obj == Py_None)
- g_value_set_boxed(value, NULL);
- else if (G_VALUE_HOLDS(value, PY_TYPE_OBJECT))
- g_value_set_boxed(value, obj);
- else if (PyObject_TypeCheck(obj, &PyGBoxed_Type) &&
- G_VALUE_HOLDS(value, ((PyGBoxed *)obj)->gtype))
- g_value_set_boxed(value, pyg_boxed_get(obj, gpointer));
+ PyGTypeMarshal *bm;
+
+ if (obj == Py_None)
+ g_value_set_boxed(value, NULL);
+ else if (G_VALUE_HOLDS(value, PY_TYPE_OBJECT))
+ g_value_set_boxed(value, obj);
+ else if (PyObject_TypeCheck(obj, &PyGBoxed_Type) &&
+ G_VALUE_HOLDS(value, ((PyGBoxed *)obj)->gtype))
+ g_value_set_boxed(value, pyg_boxed_get(obj, gpointer));
else if (G_VALUE_HOLDS(value, G_TYPE_VALUE)) {
GType type;
GValue *n_value;
type = pyg_type_from_object((PyObject*)Py_TYPE(obj));
if (G_UNLIKELY (! type)) {
- PyErr_Clear();
return -1;
}
n_value = g_new0 (GValue, 1);
g_value_init (n_value, type);
g_value_take_boxed (value, n_value);
- return pyg_value_from_pyobject (n_value, obj);
+ return pyg_value_from_pyobject_with_error (n_value, obj);
}
else if (PySequence_Check(obj) &&
- G_VALUE_HOLDS(value, G_TYPE_VALUE_ARRAY))
- return pyg_value_array_from_pyobject(value, obj, NULL);
- else if (PYGLIB_PyUnicode_Check(obj) &&
- G_VALUE_HOLDS(value, G_TYPE_GSTRING)) {
+ G_VALUE_HOLDS(value, G_TYPE_VALUE_ARRAY))
+ return pyg_value_array_from_pyobject(value, obj, NULL);
+ else if (PySequence_Check(obj) &&
+ G_VALUE_HOLDS(value, G_TYPE_ARRAY))
+ return pyg_array_from_pyobject(value, obj);
+ else if (PYGLIB_PyUnicode_Check(obj) &&
+ G_VALUE_HOLDS(value, G_TYPE_GSTRING)) {
GString *string;
char *buffer;
Py_ssize_t len;
if (PYGLIB_PyUnicode_AsStringAndSize(obj, &buffer, &len))
return -1;
string = g_string_new_len(buffer, len);
- g_value_set_boxed(value, string);
- g_string_free (string, TRUE);
+ g_value_set_boxed(value, string);
+ g_string_free (string, TRUE);
break;
}
- else if ((bm = pyg_type_lookup(G_VALUE_TYPE(value))) != NULL)
- return bm->tovalue(value, obj);
- else if (PYGLIB_CPointer_Check(obj))
- g_value_set_boxed(value, PYGLIB_CPointer_GetPointer(obj, NULL));
- else
- return -1;
- break;
+ else if ((bm = pyg_type_lookup(G_VALUE_TYPE(value))) != NULL)
+ return bm->tovalue(value, obj);
+ else if (PYGLIB_CPointer_Check(obj))
+ g_value_set_boxed(value, PYGLIB_CPointer_GetPointer(obj, NULL));
+ else {
+ PyErr_SetString(PyExc_TypeError, "Expected Boxed");
+ return -1;
+ }
+ break;
}
case G_TYPE_PARAM:
- if (PyGParamSpec_Check(obj))
- g_value_set_param(value, PYGLIB_CPointer_GetPointer(obj, NULL));
- else
- return -1;
- break;
+ /* we need to support both the wrapped _gobject.GParamSpec and the GI
+ * GObject.ParamSpec */
+ if (G_IS_PARAM_SPEC (pygobject_get (obj)))
+ g_value_set_param(value, G_PARAM_SPEC (pygobject_get (obj)));
+ else if (PyGParamSpec_Check(obj))
+ g_value_set_param(value, PYGLIB_CPointer_GetPointer(obj, NULL));
+ else {
+ PyErr_SetString(PyExc_TypeError, "Expected ParamSpec");
+ return -1;
+ }
+ break;
case G_TYPE_OBJECT:
- if (obj == Py_None) {
- g_value_set_object(value, NULL);
- } else if (PyObject_TypeCheck(obj, &PyGObject_Type) &&
- G_TYPE_CHECK_INSTANCE_TYPE(pygobject_get(obj),
- G_VALUE_TYPE(value))) {
- g_value_set_object(value, pygobject_get(obj));
- } else
- return -1;
- break;
+ if (obj == Py_None) {
+ g_value_set_object(value, NULL);
+ } else if (PyObject_TypeCheck(obj, &PyGObject_Type) &&
+ G_TYPE_CHECK_INSTANCE_TYPE(pygobject_get(obj),
+ G_VALUE_TYPE(value))) {
+ g_value_set_object(value, pygobject_get(obj));
+ } else {
+ PyErr_SetString(PyExc_TypeError, "Expected GObject");
+ return -1;
+ }
+ break;
+ case G_TYPE_VARIANT:
+ {
+ if (obj == Py_None)
+ g_value_set_variant(value, NULL);
+ else if (pyg_type_from_object_strict(obj, FALSE) == G_TYPE_VARIANT)
+ g_value_set_variant(value, pyg_boxed_get(obj, GVariant));
+ else {
+ PyErr_SetString(PyExc_TypeError, "Expected Variant");
+ return -1;
+ }
+ break;
+ }
default:
- {
- PyGTypeMarshal *bm;
- if ((bm = pyg_type_lookup(G_VALUE_TYPE(value))) != NULL)
- return bm->tovalue(value, obj);
- break;
- }
+ {
+ PyGTypeMarshal *bm;
+ if ((bm = pyg_type_lookup(G_VALUE_TYPE(value))) != NULL) {
+ return bm->tovalue(value, obj);
+ } else {
+ PyErr_SetString(PyExc_TypeError, "Unknown value type");
+ return -1;
+ }
+ break;
}
+ }
+
+ /* If an error occurred, unset the GValue but don't clear the Python error. */
if (PyErr_Occurred()) {
g_value_unset(value);
- PyErr_Clear();
return -1;
}
+
return 0;
}
/**
+ * pyg_value_from_pyobject:
+ * @value: the GValue object to store the converted value in.
+ * @obj: the Python object to convert.
+ *
+ * Same basic function as pyg_value_from_pyobject_with_error but clears
+ * any Python errors before returning.
+ *
+ * Returns: 0 on success, -1 on error.
+ */
+int
+pyg_value_from_pyobject(GValue *value, PyObject *obj)
+{
+ int res = pyg_value_from_pyobject_with_error (value, obj);
+
+ if (PyErr_Occurred()) {
+ PyErr_Clear();
+ return -1;
+ }
+ return res;
+}
+
+/**
* pyg_value_as_pyobject:
* @value: the GValue object.
* @copy_boxed: true if boxed values should be copied.
@@ -1022,136 +1149,148 @@ pyg_value_as_pyobject(const GValue *value, gboolean copy_boxed)
switch (G_TYPE_FUNDAMENTAL(G_VALUE_TYPE(value))) {
case G_TYPE_INTERFACE:
- if (g_type_is_a(G_VALUE_TYPE(value), G_TYPE_OBJECT))
- return pygobject_new(g_value_get_object(value));
- else
- break;
+ if (g_type_is_a(G_VALUE_TYPE(value), G_TYPE_OBJECT))
+ return pygobject_new(g_value_get_object(value));
+ else
+ break;
case G_TYPE_CHAR: {
- gint8 val = g_value_get_schar(value);
- return PYGLIB_PyUnicode_FromStringAndSize((char *)&val, 1);
+ gint8 val = g_value_get_schar(value);
+ return PYGLIB_PyUnicode_FromStringAndSize((char *)&val, 1);
}
case G_TYPE_UCHAR: {
- guint8 val = g_value_get_uchar(value);
- return PYGLIB_PyBytes_FromStringAndSize((char *)&val, 1);
+ guint8 val = g_value_get_uchar(value);
+ return PYGLIB_PyBytes_FromStringAndSize((char *)&val, 1);
}
case G_TYPE_BOOLEAN: {
- return PyBool_FromLong(g_value_get_boolean(value));
+ return PyBool_FromLong(g_value_get_boolean(value));
}
case G_TYPE_INT:
- return PYGLIB_PyLong_FromLong(g_value_get_int(value));
+ return PYGLIB_PyLong_FromLong(g_value_get_int(value));
case G_TYPE_UINT:
- {
- /* in Python, the Int object is backed by a long. If a
+ {
+ /* in Python, the Int object is backed by a long. If a
long can hold the whole value of an unsigned int, use
an Int. Otherwise, use a Long object to avoid overflow.
This matches the ULongArg behavior in codegen/argtypes.h */
#if (G_MAXUINT <= G_MAXLONG)
- return PYGLIB_PyLong_FromLong((glong) g_value_get_uint(value));
+ return PYGLIB_PyLong_FromLong((glong) g_value_get_uint(value));
#else
- return PyLong_FromUnsignedLong((gulong) g_value_get_uint(value));
+ return PyLong_FromUnsignedLong((gulong) g_value_get_uint(value));
#endif
- }
+ }
case G_TYPE_LONG:
- return PYGLIB_PyLong_FromLong(g_value_get_long(value));
+ return PYGLIB_PyLong_FromLong(g_value_get_long(value));
case G_TYPE_ULONG:
- {
- gulong val = g_value_get_ulong(value);
+ {
+ gulong val = g_value_get_ulong(value);
- if (val <= G_MAXLONG)
- return PYGLIB_PyLong_FromLong((glong) val);
- else
- return PyLong_FromUnsignedLong(val);
- }
+ if (val <= G_MAXLONG)
+ return PYGLIB_PyLong_FromLong((glong) val);
+ else
+ return PyLong_FromUnsignedLong(val);
+ }
case G_TYPE_INT64:
- {
- gint64 val = g_value_get_int64(value);
+ {
+ gint64 val = g_value_get_int64(value);
- if (G_MINLONG <= val && val <= G_MAXLONG)
- return PYGLIB_PyLong_FromLong((glong) val);
- else
- return PyLong_FromLongLong(val);
- }
+ if (G_MINLONG <= val && val <= G_MAXLONG)
+ return PYGLIB_PyLong_FromLong((glong) val);
+ else
+ return PyLong_FromLongLong(val);
+ }
case G_TYPE_UINT64:
- {
- guint64 val = g_value_get_uint64(value);
+ {
+ guint64 val = g_value_get_uint64(value);
- if (val <= G_MAXLONG)
- return PYGLIB_PyLong_FromLong((glong) val);
- else
- return PyLong_FromUnsignedLongLong(val);
- }
+ if (val <= G_MAXLONG)
+ return PYGLIB_PyLong_FromLong((glong) val);
+ else
+ return PyLong_FromUnsignedLongLong(val);
+ }
case G_TYPE_ENUM:
- return pyg_enum_from_gtype(G_VALUE_TYPE(value), g_value_get_enum(value));
+ return pyg_enum_from_gtype(G_VALUE_TYPE(value), g_value_get_enum(value));
case G_TYPE_FLAGS:
- return pyg_flags_from_gtype(G_VALUE_TYPE(value), g_value_get_flags(value));
+ return pyg_flags_from_gtype(G_VALUE_TYPE(value), g_value_get_flags(value));
case G_TYPE_FLOAT:
- return PyFloat_FromDouble(g_value_get_float(value));
+ return PyFloat_FromDouble(g_value_get_float(value));
case G_TYPE_DOUBLE:
- return PyFloat_FromDouble(g_value_get_double(value));
+ return PyFloat_FromDouble(g_value_get_double(value));
case G_TYPE_STRING:
- {
- const gchar *str = g_value_get_string(value);
+ {
+ const gchar *str = g_value_get_string(value);
- if (str)
- return PYGLIB_PyUnicode_FromString(str);
- Py_INCREF(Py_None);
- return Py_None;
- }
+ if (str)
+ return PYGLIB_PyUnicode_FromString(str);
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
case G_TYPE_POINTER:
- return pyg_pointer_new(G_VALUE_TYPE(value),
- g_value_get_pointer(value));
+ if (G_VALUE_HOLDS_GTYPE (value))
+ return pyg_type_wrapper_new (g_value_get_gtype (value));
+ else
+ return pyg_pointer_new(G_VALUE_TYPE(value),
+ g_value_get_pointer(value));
case G_TYPE_BOXED: {
- PyGTypeMarshal *bm;
+ PyGTypeMarshal *bm;
- if (G_VALUE_HOLDS(value, PY_TYPE_OBJECT)) {
- PyObject *ret = (PyObject *)g_value_dup_boxed(value);
- if (ret == NULL) {
- Py_INCREF(Py_None);
- return Py_None;
- }
- return ret;
+ if (G_VALUE_HOLDS(value, PY_TYPE_OBJECT)) {
+ PyObject *ret = (PyObject *)g_value_dup_boxed(value);
+ if (ret == NULL) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+ return ret;
} else if (G_VALUE_HOLDS(value, G_TYPE_VALUE)) {
GValue *n_value = g_value_get_boxed (value);
return pyg_value_as_pyobject(n_value, copy_boxed);
} else if (G_VALUE_HOLDS(value, G_TYPE_VALUE_ARRAY)) {
- GValueArray *array = (GValueArray *) g_value_get_boxed(value);
- PyObject *ret = PyList_New(array->n_values);
- int i;
- for (i = 0; i < array->n_values; ++i)
- PyList_SET_ITEM(ret, i, pyg_value_as_pyobject
- (array->values + i, copy_boxed));
- return ret;
- } else if (G_VALUE_HOLDS(value, G_TYPE_GSTRING)) {
- GString *string = (GString *) g_value_get_boxed(value);
- PyObject *ret = PYGLIB_PyUnicode_FromStringAndSize(string->str, string->len);
- return ret;
- }
- bm = pyg_type_lookup(G_VALUE_TYPE(value));
- if (bm) {
- return bm->fromvalue(value);
- } else {
- if (copy_boxed)
- return pyg_boxed_new(G_VALUE_TYPE(value),
- g_value_get_boxed(value), TRUE, TRUE);
- else
- return pyg_boxed_new(G_VALUE_TYPE(value),
- g_value_get_boxed(value),FALSE,FALSE);
- }
+ GValueArray *array = (GValueArray *) g_value_get_boxed(value);
+ PyObject *ret = PyList_New(array->n_values);
+ int i;
+ for (i = 0; i < array->n_values; ++i)
+ PyList_SET_ITEM(ret, i, pyg_value_as_pyobject
+ (array->values + i, copy_boxed));
+ return ret;
+ } else if (G_VALUE_HOLDS(value, G_TYPE_GSTRING)) {
+ GString *string = (GString *) g_value_get_boxed(value);
+ PyObject *ret = PYGLIB_PyUnicode_FromStringAndSize(string->str, string->len);
+ return ret;
+ }
+ bm = pyg_type_lookup(G_VALUE_TYPE(value));
+ if (bm) {
+ return bm->fromvalue(value);
+ } else {
+ if (copy_boxed)
+ return pyg_boxed_new(G_VALUE_TYPE(value),
+ g_value_get_boxed(value), TRUE, TRUE);
+ else
+ return pyg_boxed_new(G_VALUE_TYPE(value),
+ g_value_get_boxed(value),FALSE,FALSE);
+ }
}
case G_TYPE_PARAM:
- return pyg_param_spec_new(g_value_get_param(value));
+ return pyg_param_spec_new(g_value_get_param(value));
case G_TYPE_OBJECT:
- return pygobject_new(g_value_get_object(value));
+ return pygobject_new(g_value_get_object(value));
+ case G_TYPE_VARIANT:
+ {
+ GVariant *v = g_value_get_variant(value);
+ if (v == NULL) {
+ Py_INCREF(Py_None);
+ return Py_None;
+ }
+ return pyg_boxed_new(G_TYPE_VARIANT, g_variant_ref(v), FALSE, FALSE);
+ }
default:
- {
- PyGTypeMarshal *bm;
- if ((bm = pyg_type_lookup(G_VALUE_TYPE(value))))
- return bm->fromvalue(value);
- break;
- }
+ {
+ PyGTypeMarshal *bm;
+ if ((bm = pyg_type_lookup(G_VALUE_TYPE(value))))
+ return bm->fromvalue(value);
+ break;
+ }
}
g_snprintf(buf, sizeof(buf), "unknown type %s",
- g_type_name(G_VALUE_TYPE(value)));
+ g_type_name(G_VALUE_TYPE(value)));
PyErr_SetString(PyExc_TypeError, buf);
return NULL;
}
@@ -1223,9 +1362,12 @@ pyg_closure_marshal(GClosure *closure,
goto out;
}
- if (return_value && pyg_value_from_pyobject(return_value, ret) != 0) {
- PyErr_SetString(PyExc_TypeError,
- "can't convert return value to desired type");
+ if (G_IS_VALUE(return_value) && pyg_value_from_pyobject(return_value, ret) != 0) {
+ /* If we already have an exception set, use that, otherwise set a
+ * generic one */
+ if (!PyErr_Occurred())
+ PyErr_SetString(PyExc_TypeError,
+ "can't convert return value to desired type");
if (pc->exception_handler)
pc->exception_handler(return_value, n_param_values, param_values);
@@ -1401,7 +1543,7 @@ pyg_signal_class_closure_marshal(GClosure *closure,
}
Py_DECREF(method);
Py_DECREF(params);
- if (return_value)
+ if (G_IS_VALUE(return_value))
pyg_value_from_pyobject(return_value, ret);
Py_DECREF(ret);
pyglib_gil_state_release(state);
@@ -1717,69 +1859,10 @@ pyg_param_gvalue_as_pyobject(const GValue* gvalue,
}
}
-/**
- * pyg_type_registration_callback
- * @gtypename: type name
- * @callback: function to run
- *
- */
-typedef struct {
- PyGTypeRegistrationFunction callback;
- gpointer data;
-} CustomTypeData;
-
-void
-pyg_type_register_custom_callback(const gchar *typename,
- PyGTypeRegistrationFunction callback,
- gpointer user_data)
+gboolean
+pyg_gtype_is_custom(GType gtype)
{
- CustomTypeData *data;
-
- if (!custom_type_registration)
- custom_type_registration = g_hash_table_new_full (g_str_hash, g_str_equal,
- g_free, g_free);
-
- data = g_new (CustomTypeData, 1);
- data->callback = callback;
- data->data = user_data;
-
- g_hash_table_insert(custom_type_registration,
- g_strdup(typename),
- data);
-}
-
-PyTypeObject *
-pyg_type_get_custom(const gchar *name)
-{
- CustomTypeData *data;
- PyTypeObject *retval;
-
- if (!custom_type_registration)
- return NULL;
-
- data = g_hash_table_lookup(custom_type_registration, name);
- if (!data)
- return NULL;
-
- retval = data->callback(name, data->data);
-
- g_hash_table_remove(custom_type_registration, name);
-
- return retval;
-}
-
-GType
-_pyg_type_from_name(const gchar *name)
-{
- GType type;
-
- type = g_type_from_name(name);
- if (type == G_TYPE_INVALID) {
- pyg_type_get_custom(name);
- type = g_type_from_name(name);
- }
-
- return type;
+ return g_type_get_qdata (gtype, pygobject_custom_key) != NULL;
}
static PyObject *
diff --git a/gi/_gobject/signalhelper.py b/gi/_gobject/signalhelper.py
new file mode 100644
index 0000000..b630158
--- /dev/null
+++ b/gi/_gobject/signalhelper.py
@@ -0,0 +1,258 @@
+# -*- Mode: Python; py-indent-offset: 4 -*-
+# pygobject - Python bindings for the GObject library
+# Copyright (C) 2012 Simon Feltman
+#
+# gobject/signalhelper.py: GObject signal binding decorator object
+#
+# 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 Street, Fifth Floor, Boston, MA 02110-1301
+# USA
+
+import sys
+import inspect
+
+from . import _gobject
+
+# Callable went away in python 3.0 and came back in 3.2.
+# Use versioning to figure out when to define it, otherwise we have to deal with
+# the complexity of using __builtin__ or builtin between python versions to
+# check if callable exists which PyFlakes will also complain about.
+if (3, 0) <= sys.version_info < (3, 2):
+ def callable(fn):
+ return hasattr(fn, '__call__')
+
+
+class Signal(str):
+ """
+ Object which gives a nice API for creating and binding signals.
+
+ Example:
+ class Spam(GObject.GObject):
+ velocity = 0
+
+ @GObject.Signal
+ def pushed(self):
+ self.velocity += 1
+
+ @GObject.Signal(flags=GObject.SignalFlags.RUN_LAST)
+ def pulled(self):
+ self.velocity -= 1
+
+ stomped = GObject.Signal('stomped', arg_types=(int,))
+
+ @GObject.Signal
+ def annotated_signal(self, a:int, b:str):
+ "Python3 annotation support for parameter types.
+
+ def on_pushed(obj):
+ print(obj)
+
+ spam = Spam()
+ spam.pushed.connect(on_pushed)
+ spam.pushed.emit()
+ """
+ class BoundSignal(str):
+ """
+ Temporary binding object which can be used for connecting signals
+ without specifying the signal name string to connect.
+ """
+ def __new__(cls, name, *args, **kargs):
+ return str.__new__(cls, name)
+
+ def __init__(self, signal, gobj):
+ str.__init__(self)
+ self.signal = signal
+ self.gobj = gobj
+
+ def __repr__(self):
+ return 'BoundSignal("%s")' % self
+
+ def __call__(self, *args, **kargs):
+ """Call the signals closure."""
+ return self.signal.func(self.gobj, *args, **kargs)
+
+ def connect(self, callback, *args, **kargs):
+ """Same as GObject.GObject.connect except there is no need to specify
+ the signal name."""
+ return self.gobj.connect(self, callback, *args, **kargs)
+
+ def connect_detailed(self, callback, detail, *args, **kargs):
+ """Same as GObject.GObject.connect except there is no need to specify
+ the signal name. In addition concats "::<detail>" to the signal name
+ when connecting; for use with notifications like "notify" when a property
+ changes.
+ """
+ return self.gobj.connect(self + '::' + detail, callback, *args, **kargs)
+
+ def disconnect(self, handler_id):
+ """Same as GObject.GObject.disconnect."""
+ self.instance.disconnect(handler_id)
+
+ def emit(self, *args, **kargs):
+ """Same as GObject.GObject.emit except there is no need to specify
+ the signal name."""
+ return self.gobj.emit(str(self), *args, **kargs)
+
+ def __new__(cls, name='', *args, **kargs):
+ if callable(name):
+ name = name.__name__
+ return str.__new__(cls, name)
+
+ def __init__(self, name='', func=None, flags=_gobject.SIGNAL_RUN_FIRST,
+ return_type=None, arg_types=None, doc='', accumulator=None, accu_data=None):
+ """
+ @param name: name of signal or closure method when used as direct decorator.
+ @type name: string or callable
+ @param func: closure method.
+ @type func: callable
+ @param flags: flags specifying when to run closure
+ @type flags: GObject.SignalFlags
+ @param return_type: return type
+ @type return_type: type
+ @param arg_types: list of argument types specifying the signals function signature
+ @type arg_types: None
+ @param doc: documentation of signal object
+ @type doc: string
+ @param accumulator: accumulator method with the signature:
+ func(ihint, return_accu, handler_return, accu_data) -> boolean
+ @type accumulator: function
+ @param accu_data: user data passed to the accumulator
+ @type accu_data: object
+ """
+ if func and not name:
+ name = func.__name__
+ elif callable(name):
+ func = name
+ name = func.__name__
+ if func and not doc:
+ doc = func.__doc__
+
+ str.__init__(self)
+
+ if func and not (return_type or arg_types):
+ return_type, arg_types = get_signal_annotations(func)
+ if arg_types is None:
+ arg_types = tuple()
+
+ self.func = func
+ self.flags = flags
+ self.return_type = return_type
+ self.arg_types = arg_types
+ self.__doc__ = doc
+ self.accumulator = accumulator
+ self.accu_data = accu_data
+
+ def __get__(self, instance, owner=None):
+ """Returns a BoundSignal when accessed on an object instance."""
+ if instance is None:
+ return self
+ return self.BoundSignal(self, instance)
+
+ def __call__(self, obj, *args, **kargs):
+ """Allows for instantiated Signals to be used as a decorator or calling
+ of the underlying signal method."""
+
+ # If obj is a GObject, than we call this signal as a closure otherwise
+ # it is used as a re-application of a decorator.
+ if isinstance(obj, _gobject.GObject):
+ self.func(obj, *args, **kargs)
+ else:
+ # If self is already an allocated name, use it otherwise create a new named
+ # signal using the closure name as the name.
+ if str(self):
+ name = str(self)
+ else:
+ name = obj.__name__
+ # Return a new value of this type since it is based on an immutable string.
+ return type(self)(name=name, func=obj, flags=self.flags,
+ return_type=self.return_type, arg_types=self.arg_types,
+ doc=self.__doc__, accumulator=self.accumulator, accu_data=self.accu_data)
+
+ def copy(self, newName=None):
+ """Returns a renamed copy of the Signal."""
+ if newName is None:
+ newName = self.name
+ return type(self)(name=newName, func=self.func, flags=self.flags,
+ return_type=self.return_type, arg_types=self.arg_types,
+ doc=self.__doc__, accumulator=self.accumulator, accu_data=self.accu_data)
+
+ def get_signal_args(self):
+ """Returns a tuple of: (flags, return_type, arg_types, accumulator, accu_data)"""
+ return (self.flags, self.return_type, self.arg_types, self.accumulator, self.accu_data)
+
+
+class SignalOverride(Signal):
+ """Specialized sub-class of signal which can be used as a decorator for overriding
+ existing signals on GObjects.
+
+ Example:
+ class MyWidget(Gtk.Widget):
+ @GObject.SignalOverride
+ def configure_event(self):
+ pass
+ """
+ def get_signal_args(self):
+ """Returns the string 'override'."""
+ return 'override'
+
+
+def get_signal_annotations(func):
+ """Attempt pulling python 3 function annotations off of 'func' for
+ use as a signals type information. Returns an ordered nested tuple
+ of (return_type, (arg_type1, arg_type2, ...)). If the given function
+ does not have annotations then (None, tuple()) is returned.
+ """
+ arg_types = tuple()
+ return_type = None
+
+ if hasattr(func, '__annotations__'):
+ spec = inspect.getfullargspec(func)
+ arg_types = tuple(spec.annotations[arg] for arg in spec.args
+ if arg in spec.annotations)
+ if 'return' in spec.annotations:
+ return_type = spec.annotations['return']
+
+ return return_type, arg_types
+
+
+def install_signals(cls):
+ """Adds Signal instances on a GObject derived class into the '__gsignals__'
+ dictionary to be picked up and registered as real GObject signals.
+ """
+ gsignals = cls.__dict__.get('__gsignals__', {})
+ newsignals = {}
+ for name, signal in cls.__dict__.items():
+ if isinstance(signal, Signal):
+ signalName = str(signal)
+ # Fixup a signal which is unnamed by using the class variable name.
+ # Since Signal is based on string which immutable,
+ # we must copy and replace the class variable.
+ if not signalName:
+ signalName = name
+ signal = signal.copy(name)
+ setattr(cls, name, signal)
+ if signalName in gsignals:
+ raise ValueError('Signal "%s" has already been registered.' % name)
+ newsignals[signalName] = signal
+ gsignals[signalName] = signal.get_signal_args()
+
+ cls.__gsignals__ = gsignals
+
+ # Setup signal closures by adding the specially named
+ # method to the class in the form of "do_<signal_name>".
+ for name, signal in newsignals.items():
+ if signal.func is not None:
+ funcName = 'do_' + name.replace('-', '_')
+ if not hasattr(cls, funcName):
+ setattr(cls, funcName, signal.func)