diff options
author | DongHun Kwak <dh0128.kwak@samsung.com> | 2017-07-12 08:39:06 +0900 |
---|---|---|
committer | DongHun Kwak <dh0128.kwak@samsung.com> | 2017-07-12 08:39:09 +0900 |
commit | 23384e73cb73bc8875384183d5916e33af4196d4 (patch) | |
tree | be92faf8967d24f2be88a92b4f7506e9d65fbf3d /gi/_gobject | |
parent | 705bf16f6a14a07ccdc0c1a5fe1b31d92c3bd96e (diff) | |
download | pygobject2-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.am | 29 | ||||
-rw-r--r-- | gi/_gobject/Makefile.in | 98 | ||||
-rw-r--r-- | gi/_gobject/__init__.py | 84 | ||||
-rw-r--r-- | gi/_gobject/constants.py | 41 | ||||
-rw-r--r-- | gi/_gobject/gobjectmodule.c | 692 | ||||
-rw-r--r-- | gi/_gobject/propertyhelper.py | 264 | ||||
-rw-r--r-- | gi/_gobject/pygboxed.c | 3 | ||||
-rw-r--r-- | gi/_gobject/pygenum.c | 37 | ||||
-rw-r--r-- | gi/_gobject/pygflags.c | 74 | ||||
-rw-r--r-- | gi/_gobject/pyginterface.c | 2 | ||||
-rw-r--r-- | gi/_gobject/pygobject-private.h | 56 | ||||
-rw-r--r-- | gi/_gobject/pygobject.c | 769 | ||||
-rw-r--r-- | gi/_gobject/pygobject.h | 79 | ||||
-rw-r--r-- | gi/_gobject/pygtype.c | 845 | ||||
-rw-r--r-- | gi/_gobject/signalhelper.py | 258 |
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", >ype)) - 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", >ype)) - 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", >ype)) - 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", ¶m_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(¶m_values[0], FALSE)); + PyTuple_SetItem (params, 1, pyg_value_as_pyobject(¶m_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 (¶m_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(¶ms[i+1])), i); + G_VALUE_TYPE_NAME(¶ms[i+1]), i); PyErr_SetString(PyExc_TypeError, buf); - for (i = 0; i < query.n_params + 1; i++) - g_value_unset(¶ms[i]); + for (j = 0; j <= i; j++) + g_value_unset(¶ms[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) |