From d515c550b1574ab0bdd751ebf31600347ecc396b Mon Sep 17 00:00:00 2001 From: DongHun Kwak Date: Wed, 12 Jul 2017 08:40:57 +0900 Subject: [PATCH] Imported Upstream version 3.11.91 Change-Id: I6a9a58284ff7f0bec0f4afba0c8bb3a909287ce6 Signed-off-by: DongHun Kwak --- ChangeLog | 187 +++++++++++++++++++++++++ Makefile.am | 2 +- Makefile.in | 2 +- NEWS | 7 + PKG-INFO | 4 +- configure | 65 ++++++--- configure.ac | 5 +- gi/gimodule.c | 2 +- gi/gobjectmodule.c | 2 +- gi/pygi-array.c | 29 ++-- gi/pygi-basictype.c | 16 +++ gi/pygi-cache.c | 64 +++++++-- gi/pygi-cache.h | 10 +- gi/pygi-ccallback.c | 3 +- gi/pygi-closure.c | 6 +- gi/pygi-enum-marshal.c | 16 --- gi/pygi-invoke-state-struct.h | 42 +++--- gi/pygi-invoke.c | 241 ++++++++++++++++++--------------- gi/pygi-invoke.h | 2 +- gi/pygi-marshal-cleanup.c | 4 +- gi/pygi-property.c | 2 +- gi/pygtype.c | 2 +- tests/test_generictreemodel.py | 16 ++- tests/test_overrides_gtk.py | 32 ++--- tests/test_properties.py | 27 ++-- 25 files changed, 550 insertions(+), 238 deletions(-) diff --git a/ChangeLog b/ChangeLog index 0b234c2..f8382f8 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,190 @@ +commit 1a63a04eaf2a77c1752b90e80ab571677f27ac3d +Author: Simon Feltman +Date: Mon Mar 3 06:49:09 2014 -0800 + + build: Update release-news to use srcdir + + Use $(top_srcdir)/NEWS for pulling in news items to ensure + "make release-news" works in a vpath build environment. + + Makefile.am | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +commit 5798f94b6a727b930b07fe840b0aef264f98a80e +Author: Simon Feltman +Date: Fri Feb 7 20:16:21 2014 -0800 + + Use ffi_call directly instead of g_callable_info_invoke + + Cleanup internal callable cache and state tracking by removing + multiple + counting schemes for differently sized "in" and "out" argument arrays. + Use a single count based on the total number of arguments passed to C + (inclusive of instance argument and GError exception where + applicable). + Size all state tracking arrays to the same size and ensure argument + cache + indices always line up with these arrays. This cleans up logic + which was + required by g_callable_info_invoke for splitting "in" and "out" + arguments + up. + + Cleanup array marshaling which can now rely on the new scheme + which ensures + the "arg_values" array always points to the correct location for + length + argument values. + + Cache the ffi_cif struct in PyGICallableCache via GIFunctionInvoker + and + related GI methods. Overall, these changes can give a performance + boost of + almost 2x for simple function calls (see ticket for micro benchmarks). + + https://bugzilla.gnome.org/show_bug.cgi?id=723642 + + gi/pygi-array.c | 26 ++--- + gi/pygi-cache.c | 61 +++++++++-- + gi/pygi-cache.h | 10 +- + gi/pygi-ccallback.c | 3 +- + gi/pygi-closure.c | 6 +- + gi/pygi-invoke-state-struct.h | 42 +++++--- + gi/pygi-invoke.c | 241 + +++++++++++++++++++++++------------------- + gi/pygi-invoke.h | 2 +- + gi/pygi-marshal-cleanup.c | 4 +- + 9 files changed, 230 insertions(+), 165 deletions(-) + +commit ad680ae9c37a0091628a7d66010fbf70aa1a2e43 +Author: Simon Feltman +Date: Mon Mar 3 04:51:09 2014 -0800 + + tests: Move class definition depending on GTK+ within function + evaluation + + Move the definition of WindowWithSizeAllocOverride inside of the test + function call to so it is lazily defined. This avoids problems + running tests + on systems without GTK+ installed. + + tests/test_overrides_gtk.py | 32 ++++++++++++++++---------------- + 1 file changed, 16 insertions(+), 16 deletions(-) + +commit 45d45e7c2704d68a3008f739e501fa332d326b8b +Author: Simon Feltman +Date: Mon Mar 3 04:45:59 2014 -0800 + + tests: Conditionalize usage of GTK+ in tests_generictreemodel + + This allows running make check without GTK+ installed. + + tests/test_generictreemodel.py | 16 +++++++++++++--- + 1 file changed, 13 insertions(+), 3 deletions(-) + +commit 038563ed620e0d966e385a1779455d9b0e148c41 +Author: Simon Feltman +Date: Mon Mar 3 04:39:35 2014 -0800 + + tests: Conditionalize usage of regress typelib in test_properties + + Unconditional usage of regress breaks tests when PyGObject is + built without + cairo. + + tests/test_properties.py | 27 +++++++++++++++++---------- + 1 file changed, 17 insertions(+), 10 deletions(-) + +commit 1fa93ddc51b2d223d772aee7930fc96c0ced0e00 +Author: Simon Feltman +Date: Mon Mar 3 02:44:12 2014 -0800 + + configure.ac: Use -std=c90 and error on declaration-after-statement + + Replace gcc option of -std=c9x with c90 and add + -Werror=declaration-after-statement + This ensures we keep compatibility with msvc builds. + + configure.ac | 3 ++- + 1 file changed, 2 insertions(+), 1 deletion(-) + +commit cee414ab5725c51d79a2c6aa1e8760e9fd754545 +Author: Simon Feltman +Date: Mon Mar 3 02:38:30 2014 -0800 + + Use g_snprintf instead of snprintf + + Use g_snprintf for consistency with the rest of gobjectmodule.c + + gi/gobjectmodule.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +commit b016ae6793839b2a6a00a69d00de30937bc611be +Author: Simon Feltman +Date: Thu Feb 27 04:27:41 2014 -0800 + + Use C style comments + + Update various locations which use C99 single line comments to + conform to + C90 style comments. Found with: make CFLAGS="-std=C90" + + gi/gimodule.c | 2 +- + gi/pygi-array.c | 3 ++- + gi/pygi-property.c | 2 +- + gi/pygtype.c | 2 +- + 4 files changed, 5 insertions(+), 4 deletions(-) + +commit df7cba1495c167f1019dec7f4398dc5de62a5937 +Author: Chun-wei Fan +Date: Tue Feb 25 14:38:41 2014 +0800 + + Fix Build on Visual Studio + + Some items from pygi-enum-marshal.c were moved to pygi-basictype.c, + which + included the use of the NAN and INFINITY macros/constants, so the + definitions for those need to be moved to pygi-basictype.c as well. + Also + avoid defining a variable in the middle of the block. + + https://bugzilla.gnome.org/show_bug.cgi?id=725122 + + gi/pygi-basictype.c | 16 ++++++++++++++++ + gi/pygi-cache.c | 3 ++- + gi/pygi-enum-marshal.c | 16 ---------------- + 3 files changed, 18 insertions(+), 17 deletions(-) + +commit bb5550bc85ac0ff60ea39912416e347f27853fb4 +Author: Simon Feltman +Date: Mon Feb 17 17:22:40 2014 -0800 + + Update release steps to be more explicit in regards to NEWS + + Add an explicit step to commit the NEWS changes and push prior + tagging. + + HACKING | 11 ++++++----- + 1 file changed, 6 insertions(+), 5 deletions(-) + +commit c6ac95286bce858f1925a9d6173a91866d7e9f88 +Author: Simon Feltman +Date: Mon Feb 17 17:18:10 2014 -0800 + + configure.ac: post release version bump to 3.11.91 + + configure.ac | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +commit f87e341c5528d066371d4ec493956db28dd0bafa +Author: Simon Feltman +Date: Mon Feb 17 17:08:13 2014 -0800 + + release 3.11.90 + + NEWS | 4 ++++ + 1 file changed, 4 insertions(+) + commit 9b345b153e86ca6c9b7290cf2ad3b38f6ad9d0e5 Author: Simon Feltman Date: Wed Feb 12 10:28:35 2014 -0800 diff --git a/Makefile.am b/Makefile.am index ea0b4ba..208ed13 100644 --- a/Makefile.am +++ b/Makefile.am @@ -130,7 +130,7 @@ release-news: @echo -e "\n\n\nFor blogging, you can copy&paste this HTML formatted news:" @echo "-------------- 8< -------------" - @last=`head -n1 NEWS | cut -f1 -d' '`; \ + @last=`head -n1 $(top_srcdir)/NEWS | cut -f1 -d' '`; \ echo "
    "; \ for commit in `git rev-list $$last..`; do \ data=`git log --format="format:%s%n%an%n%b" $$commit^..$$commit`; \ diff --git a/Makefile.in b/Makefile.in index 7ba43dd..4cf5c4e 100644 --- a/Makefile.in +++ b/Makefile.in @@ -1094,7 +1094,7 @@ release-news: @echo -e "\n\n\nFor blogging, you can copy&paste this HTML formatted news:" @echo "-------------- 8< -------------" - @last=`head -n1 NEWS | cut -f1 -d' '`; \ + @last=`head -n1 $(top_srcdir)/NEWS | cut -f1 -d' '`; \ echo "
      "; \ for commit in `git rev-list $$last..`; do \ data=`git log --format="format:%s%n%an%n%b" $$commit^..$$commit`; \ diff --git a/NEWS b/NEWS index 45cbb0c..df04403 100644 --- a/NEWS +++ b/NEWS @@ -1,3 +1,10 @@ +3.11.91 03-Mar-2014 + - Use ffi_call directly instead of g_callable_info_invoke + (Simon Feltman) (#723642) + - configure.ac: Use -std=c90 and error on declaration-after-statement + (Simon Feltman) + - Fix Build on Visual Studio (Chun-wei Fan) (#725122) + 3.11.90 17-Feb-2014 - Use GObject type checking for instance arguments (Simon Feltman) (#724009) - configure.ac: post release version bump to 3.11.90 (Simon Feltman) diff --git a/PKG-INFO b/PKG-INFO index 1899a6a..ae9e0b7 100644 --- a/PKG-INFO +++ b/PKG-INFO @@ -1,6 +1,6 @@ Metadata-Version: 1.0 Name: PyGObject -Version: 3.11.90 +Version: 3.11.91 Summary: Python bindings for GObject Home-page: http://www.pygtk.org/ Author: James Henstridge @@ -8,7 +8,7 @@ Author-email: james@daa.com.au Maintainer: Johan Dahlin Maintainer-email: johan@gnome.org License: GNU LGPL -Download-url: ftp://ftp.gnome.org/pub/GNOME/sources/pygobject/3.11/pygobject-3.11.90.tar.gz +Download-url: ftp://ftp.gnome.org/pub/GNOME/sources/pygobject/3.11/pygobject-3.11.91.tar.gz Description: Python bindings for GLib and GObject Platform: POSIX, Windows Classifier: Development Status :: 5 - Production/Stable diff --git a/configure b/configure index ee6b1df..f4ba831 100755 --- a/configure +++ b/configure @@ -1,6 +1,6 @@ #! /bin/sh # Guess values for system-dependent variables and create Makefiles. -# Generated by GNU Autoconf 2.69 for pygobject 3.11.90. +# Generated by GNU Autoconf 2.69 for pygobject 3.11.91. # # Report bugs to . # @@ -591,8 +591,8 @@ MAKEFLAGS= # Identity of this package. PACKAGE_NAME='pygobject' PACKAGE_TARNAME='pygobject' -PACKAGE_VERSION='3.11.90' -PACKAGE_STRING='pygobject 3.11.90' +PACKAGE_VERSION='3.11.91' +PACKAGE_STRING='pygobject 3.11.91' PACKAGE_BUGREPORT='http://bugzilla.gnome.org/enter_bug.cgi?product=pygobject' PACKAGE_URL='https://live.gnome.org/PyGObject/' @@ -1398,7 +1398,7 @@ if test "$ac_init_help" = "long"; then # Omit some internal or obsolete options to make the list less imposing. # This message is too long to be a string in the A/UX 3.1 sh. cat <<_ACEOF -\`configure' configures pygobject 3.11.90 to adapt to many kinds of systems. +\`configure' configures pygobject 3.11.91 to adapt to many kinds of systems. Usage: $0 [OPTION]... [VAR=VALUE]... @@ -1468,7 +1468,7 @@ fi if test -n "$ac_init_help"; then case $ac_init_help in - short | recursive ) echo "Configuration of pygobject 3.11.90:";; + short | recursive ) echo "Configuration of pygobject 3.11.91:";; esac cat <<\_ACEOF @@ -1605,7 +1605,7 @@ fi test -n "$ac_init_help" && exit $ac_status if $ac_init_version; then cat <<\_ACEOF -pygobject configure 3.11.90 +pygobject configure 3.11.91 generated by GNU Autoconf 2.69 Copyright (C) 2012 Free Software Foundation, Inc. @@ -1883,7 +1883,7 @@ cat >config.log <<_ACEOF This file contains any messages produced by compilers while running configure, to aid debugging if configure makes a mistake. -It was created by pygobject $as_me 3.11.90, which was +It was created by pygobject $as_me 3.11.91, which was generated by GNU Autoconf 2.69. Invocation command line was $ $0 $@ @@ -2247,9 +2247,9 @@ $as_echo "#define PYGOBJECT_MINOR_VERSION 11" >>confdefs.h PYGOBJECT_MINOR_VERSION=11 -$as_echo "#define PYGOBJECT_MICRO_VERSION 90" >>confdefs.h +$as_echo "#define PYGOBJECT_MICRO_VERSION 91" >>confdefs.h -PYGOBJECT_MICRO_VERSION=90 +PYGOBJECT_MICRO_VERSION=91 ac_config_headers="$ac_config_headers config.h" @@ -2760,7 +2760,7 @@ fi # Define the identity of the package. PACKAGE='pygobject' - VERSION='3.11.90' + VERSION='3.11.91' cat >>confdefs.h <<_ACEOF @@ -14672,6 +14672,39 @@ $as_echo_n "checking whether $CC understands -fno-strict-aliasing... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ +int +main () +{ + + ; + return 0; +} +_ACEOF +if ac_fn_c_try_compile "$LINENO"; then : + jh_has_option=yes +else + jh_has_option=no +fi +rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext + { $as_echo "$as_me:${as_lineno-$LINENO}: result: $jh_has_option" >&5 +$as_echo "$jh_has_option" >&6; } + if test $jh_has_option = no; then + CFLAGS="$save_CFLAGS" + fi + ;; +esac + +case " $CFLAGS " in +*[\ \ ]-Werror=declaration-after-statement[\ \ ]*) + ;; +*) + save_CFLAGS="$CFLAGS" + CFLAGS="$CFLAGS -Werror=declaration-after-statement" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -Werror=declaration-after-statement" >&5 +$as_echo_n "checking whether $CC understands -Werror=declaration-after-statement... " >&6; } + cat confdefs.h - <<_ACEOF >conftest.$ac_ext +/* end confdefs.h. */ + int main () { @@ -14700,13 +14733,13 @@ esac *) case " $CFLAGS " in -*[\ \ ]-std=c9x[\ \ ]*) +*[\ \ ]-std=c90[\ \ ]*) ;; *) save_CFLAGS="$CFLAGS" - CFLAGS="$CFLAGS -std=c9x" - { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -std=c9x" >&5 -$as_echo_n "checking whether $CC understands -std=c9x... " >&6; } + CFLAGS="$CFLAGS -std=c90" + { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC understands -std=c90" >&5 +$as_echo_n "checking whether $CC understands -std=c90... " >&6; } cat confdefs.h - <<_ACEOF >conftest.$ac_ext /* end confdefs.h. */ @@ -15291,7 +15324,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1 # report actual input values of CONFIG_FILES etc. instead of their # values after options handling. ac_log=" -This file was extended by pygobject $as_me 3.11.90, which was +This file was extended by pygobject $as_me 3.11.91, which was generated by GNU Autoconf 2.69. Invocation command line was CONFIG_FILES = $CONFIG_FILES @@ -15358,7 +15391,7 @@ _ACEOF cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`" ac_cs_version="\\ -pygobject config.status 3.11.90 +pygobject config.status 3.11.91 configured by $0, generated by GNU Autoconf 2.69, with options \\"\$ac_cs_config\\" diff --git a/configure.ac b/configure.ac index a4d4683..f700bbe 100644 --- a/configure.ac +++ b/configure.ac @@ -18,7 +18,7 @@ m4_define(python3_min_ver, 3.1) dnl the pygobject version number m4_define(pygobject_major_version, 3) m4_define(pygobject_minor_version, 11) -m4_define(pygobject_micro_version, 90) +m4_define(pygobject_micro_version, 91) m4_define(pygobject_version, pygobject_major_version.pygobject_minor_version.pygobject_micro_version) dnl versions of packages we require ... @@ -254,12 +254,13 @@ if test "x$GCC" = "xyes"; then JH_ADD_CFLAG([-Wall]) JH_ADD_CFLAG([-Werror=unused-variable]) JH_ADD_CFLAG([-fno-strict-aliasing]) + JH_ADD_CFLAG([-Werror=declaration-after-statement]) case $host_os in solaris*) ;; *) - JH_ADD_CFLAG([-std=c9x]) + JH_ADD_CFLAG([-std=c90]) ;; esac diff --git a/gi/gimodule.c b/gi/gimodule.c index ef3e205..25fc3d6 100644 --- a/gi/gimodule.c +++ b/gi/gimodule.c @@ -274,7 +274,7 @@ _wrap_pyg_flags_register_new_gtype_and_add (PyObject *self, static void initialize_interface (GTypeInterface *iface, PyTypeObject *pytype) { - // pygobject prints a warning if interface_init is NULL + /* pygobject prints a warning if interface_init is NULL */ } static PyObject * diff --git a/gi/gobjectmodule.c b/gi/gobjectmodule.c index 82d52a1..b156190 100644 --- a/gi/gobjectmodule.c +++ b/gi/gobjectmodule.c @@ -934,7 +934,7 @@ get_type_name_for_class(PyTypeObject *class) while (name_serial < 1000) { g_free(type_name); - snprintf(name_serial_str, 16, "-v%i", name_serial); + g_snprintf(name_serial_str, 16, "-v%i", name_serial); module = PyObject_GetAttrString((PyObject *)class, "__module__"); if (module && PYGLIB_PyUnicode_Check(module)) { type_name = g_strconcat(PYGLIB_PyUnicode_AsString(module), ".", diff --git a/gi/pygi-array.c b/gi/pygi-array.c index 937c6b3..c17ace0 100644 --- a/gi/pygi-array.c +++ b/gi/pygi-array.c @@ -370,24 +370,10 @@ array_success: PyGIArgCache *child_cache = _pygi_callable_cache_get_arg (callable_cache, array_cache->len_arg_index); - if (child_cache->direction == PYGI_DIRECTION_BIDIRECTIONAL) { - gint *len_arg = (gint *)state->in_args[child_cache->c_arg_index].v_pointer; - /* if we are not setup yet just set the in arg */ - if (len_arg == NULL) { - if (!gi_argument_from_py_ssize_t (&state->in_args[child_cache->c_arg_index], - length, - child_cache->type_tag)) { - goto err; - } - } else { - *len_arg = length; - } - } else { - if (!gi_argument_from_py_ssize_t (&state->in_args[child_cache->c_arg_index], - length, - child_cache->type_tag)) { - goto err; - } + if (!gi_argument_from_py_ssize_t (&state->arg_values[child_cache->c_arg_index], + length, + child_cache->type_tag)) { + goto err; } } @@ -528,7 +514,7 @@ _pygi_marshal_to_py_array (PyGIInvokeState *state, len = g_strv_length ((gchar **)arg->v_pointer); } } else { - GIArgument *len_arg = state->args[array_cache->len_arg_index]; + GIArgument *len_arg = &state->arg_values[array_cache->len_arg_index]; PyGIArgCache *arg_cache = _pygi_callable_cache_get_arg (callable_cache, array_cache->len_arg_index); @@ -600,7 +586,8 @@ _pygi_marshal_to_py_array (PyGIInvokeState *state, } else if (item_arg_cache->type_tag == GI_TYPE_TAG_INTERFACE) { PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *) item_arg_cache; - // FIXME: This probably doesn't work with boxed types or gvalues. See fx. _pygi_marshal_from_py_array() + /* FIXME: This probably doesn't work with boxed types or gvalues. + * See fx. _pygi_marshal_from_py_array() */ switch (g_base_info_get_type (iface_cache->interface_info)) { case GI_INFO_TYPE_STRUCT: if (arg_cache->transfer == GI_TRANSFER_EVERYTHING && @@ -683,7 +670,7 @@ _wrap_c_array (PyGIInvokeState *state, } else if (array_cache->is_zero_terminated) { len = g_strv_length ((gchar **)data); } else if (array_cache->len_arg_index >= 0) { - GIArgument *len_arg = state->args[array_cache->len_arg_index]; + GIArgument *len_arg = &state->arg_values[array_cache->len_arg_index]; len = len_arg->v_long; } diff --git a/gi/pygi-basictype.c b/gi/pygi-basictype.c index 6fbe929..c9606a9 100644 --- a/gi/pygi-basictype.c +++ b/gi/pygi-basictype.c @@ -25,6 +25,22 @@ #include "pygi-argument.h" #include "pygi-private.h" +#ifdef G_OS_WIN32 +#ifdef _MSC_VER +#include + +#ifndef NAN +static const unsigned long __nan[2] = {0xffffffff, 0x7fffffff}; +#define NAN (*(const float *) __nan) +#endif + +#ifndef INFINITY +#define INFINITY HUGE_VAL +#endif + +#endif +#endif + /* * From Python Marshaling diff --git a/gi/pygi-cache.c b/gi/pygi-cache.c index 8055c15..c29733f 100644 --- a/gi/pygi-cache.c +++ b/gi/pygi-cache.c @@ -22,6 +22,7 @@ #include +#include "pyglib.h" #include "pygi-info.h" #include "pygi-cache.h" #include "pygi-marshal-cleanup.h" @@ -132,6 +133,7 @@ pygi_callable_cache_free (PyGICallableCache *cache) if (cache->return_cache != NULL) pygi_arg_cache_free (cache->return_cache); + g_function_invoker_destroy (&cache->invoker); g_slice_free (PyGICallableCache, cache); } @@ -475,6 +477,7 @@ _args_cache_generate (GICallableInfo *callable_info, GITransfer return_transfer; PyGIArgCache *return_cache; PyGIDirection return_direction; + gssize last_explicit_arg_index; /* Return arguments are always considered out */ return_direction = _pygi_get_direction (callable_cache, GI_DIRECTION_OUT); @@ -529,7 +532,6 @@ _args_cache_generate (GICallableInfo *callable_info, _pygi_callable_cache_set_arg (callable_cache, arg_index, instance_cache); arg_index++; - callable_cache->n_from_py_args++; callable_cache->n_py_args++; } @@ -551,8 +553,6 @@ _args_cache_generate (GICallableInfo *callable_info, arg_cache->meta_type = PYGI_META_ARG_TYPE_CLOSURE; arg_cache->c_arg_index = i; - callable_cache->n_from_py_args++; - } else { GITypeInfo *type_info; @@ -566,16 +566,15 @@ _args_cache_generate (GICallableInfo *callable_info, */ arg_cache = _pygi_callable_cache_get_arg (callable_cache, arg_index); if (arg_cache != NULL) { + /* ensure c_arg_index always aligns with callable_cache->args_cache + * and all of the various PyGIInvokeState arrays. */ + arg_cache->c_arg_index = arg_index; + if (arg_cache->meta_type == PYGI_META_ARG_TYPE_CHILD_WITH_PYARG) { arg_cache->py_arg_index = callable_cache->n_py_args; callable_cache->n_py_args++; } - if (direction & PYGI_DIRECTION_FROM_PYTHON) { - arg_cache->c_arg_index = callable_cache->n_from_py_args; - callable_cache->n_from_py_args++; - } - if (direction & PYGI_DIRECTION_TO_PYTHON) { callable_cache->n_to_py_args++; } @@ -589,7 +588,6 @@ _args_cache_generate (GICallableInfo *callable_info, if (direction & PYGI_DIRECTION_FROM_PYTHON) { py_arg_index = callable_cache->n_py_args; - callable_cache->n_from_py_args++; callable_cache->n_py_args++; } @@ -637,7 +635,7 @@ _args_cache_generate (GICallableInfo *callable_info, callable_cache->n_py_required_args = 0; callable_cache->user_data_varargs_index = -1; - gssize last_explicit_arg_index = -1; + last_explicit_arg_index = -1; /* Reverse loop through all the arguments to setup arg_name_list/hash * and find the number of required arguments */ @@ -685,8 +683,47 @@ _args_cache_generate (GICallableInfo *callable_info, return TRUE; } +static gboolean +_setup_invoker (GICallableInfo *callable_info, + GIInfoType info_type, + GIFunctionInvoker *invoker, + GCallback function_ptr) +{ + GError *error = NULL; + + if (info_type == GI_INFO_TYPE_FUNCTION) { + if (g_function_info_prep_invoker ((GIFunctionInfo *)callable_info, + invoker, + &error)) { + return TRUE; + } + if (!pyglib_error_check (&error)) { + PyErr_Format (PyExc_RuntimeError, + "unknown error creating invoker for %s", + g_base_info_get_name ((GIBaseInfo *)callable_info)); + } + return FALSE; + + } else { + if (!g_function_invoker_new_for_address (function_ptr, + (GIFunctionInfo *)callable_info, + invoker, + &error)) { + if (!pyglib_error_check (&error)) { + PyErr_Format (PyExc_RuntimeError, + "unknown error creating invoker for %s", + g_base_info_get_name ((GIBaseInfo *)callable_info)); + } + return FALSE; + } + } + return TRUE; +} + PyGICallableCache * -pygi_callable_cache_new (GICallableInfo *callable_info, gboolean is_ccallback) +pygi_callable_cache_new (GICallableInfo *callable_info, + GCallback function_ptr, + gboolean is_ccallback) { gint n_args; PyGICallableCache *cache; @@ -698,6 +735,7 @@ pygi_callable_cache_new (GICallableInfo *callable_info, gboolean is_ccallback) return NULL; cache->name = g_base_info_get_name ((GIBaseInfo *)callable_info); + cache->throws = g_callable_info_can_throw_gerror ((GIBaseInfo *)callable_info); if (g_base_info_is_deprecated (callable_info)) { const gchar *deprecated = g_base_info_get_attribute (callable_info, "deprecated"); @@ -748,6 +786,10 @@ pygi_callable_cache_new (GICallableInfo *callable_info, gboolean is_ccallback) if (!_args_cache_generate (callable_info, cache)) goto err; + if (!_setup_invoker (callable_info, type, &cache->invoker, function_ptr)) { + goto err; + } + return cache; err: pygi_callable_cache_free (cache); diff --git a/gi/pygi-cache.h b/gi/pygi-cache.h index 5521605..407e38c 100644 --- a/gi/pygi-cache.h +++ b/gi/pygi-cache.h @@ -25,6 +25,7 @@ #include #include +#include #include "pygi-invoke-state-struct.h" @@ -167,14 +168,11 @@ struct _PyGICallableCache GSList *to_py_args; GSList *arg_name_list; /* for keyword arg matching */ GHashTable *arg_name_hash; + gboolean throws; /* Index of user_data arg that can eat variable args passed to a callable. */ gssize user_data_varargs_index; - /* Number of in args passed to g_function_info_invoke. - * This is used for the length of PyGIInvokeState.in_args */ - gssize n_from_py_args; - /* Number of out args passed to g_function_info_invoke. * This is used for the length of PyGIInvokeState.out_values */ gssize n_to_py_args; @@ -191,6 +189,9 @@ struct _PyGICallableCache /* Minimum number of args required to call the callable from Python. * This count does not include args with defaults. */ gssize n_py_required_args; + + /* An invoker with ffi_cif already setup */ + GIFunctionInvoker invoker; }; gboolean @@ -243,6 +244,7 @@ pygi_callable_cache_free (PyGICallableCache *cache); PyGICallableCache * pygi_callable_cache_new (GICallableInfo *callable_info, + GCallback function_ptr, gboolean is_ccallback); #define _pygi_callable_cache_args_len(cache) ((cache)->args_cache)->len diff --git a/gi/pygi-ccallback.c b/gi/pygi-ccallback.c index 01e109b..2a6c520 100644 --- a/gi/pygi-ccallback.c +++ b/gi/pygi-ccallback.c @@ -34,7 +34,7 @@ _ccallback_call(PyGICCallback *self, PyObject *args, PyObject *kwargs) PyObject *result; if (self->cache == NULL) { - self->cache = pygi_callable_cache_new (self->info, TRUE); + self->cache = pygi_callable_cache_new (self->info, self->callback, TRUE); if (self->cache == NULL) return NULL; } @@ -43,7 +43,6 @@ _ccallback_call(PyGICCallback *self, PyObject *args, PyObject *kwargs) args, kwargs, self->cache, - self->callback, self->user_data); return result; } diff --git a/gi/pygi-closure.c b/gi/pygi-closure.c index a30363f..b803541 100644 --- a/gi/pygi-closure.c +++ b/gi/pygi-closure.c @@ -800,7 +800,7 @@ _pygi_marshal_from_py_interface_callback (PyGIInvokeState *state, * The return trip to python will marshal this back and pull the python user data out. */ if (user_data_cache != NULL) { - state->in_args[user_data_cache->c_arg_index].v_pointer = closure; + state->arg_values[user_data_cache->c_arg_index].v_pointer = closure; } /* Setup a GDestroyNotify callback if this method supports it along with @@ -817,7 +817,7 @@ _pygi_marshal_from_py_interface_callback (PyGIInvokeState *state, if (destroy_cache) { if (user_data_cache != NULL) { PyGICClosure *destroy_notify = _pygi_destroy_notify_create (); - state->in_args[destroy_cache->c_arg_index].v_pointer = destroy_notify->closure; + state->arg_values[destroy_cache->c_arg_index].v_pointer = destroy_notify->closure; } else { gchar *msg = g_strdup_printf("Callables passed to %s will leak references because " "the method does not support a user_data argument. " @@ -829,7 +829,7 @@ _pygi_marshal_from_py_interface_callback (PyGIInvokeState *state, return FALSE; } g_free(msg); - state->in_args[destroy_cache->c_arg_index].v_pointer = _pygi_destroy_notify_dummy; + state->arg_values[destroy_cache->c_arg_index].v_pointer = _pygi_destroy_notify_dummy; } } diff --git a/gi/pygi-enum-marshal.c b/gi/pygi-enum-marshal.c index dec5924..32ca9dc 100644 --- a/gi/pygi-enum-marshal.c +++ b/gi/pygi-enum-marshal.c @@ -25,22 +25,6 @@ #include "pygi-enum-marshal.h" #include "pygi-private.h" -#ifdef _WIN32 -#ifdef _MSC_VER -#include - -#ifndef NAN -static const unsigned long __nan[2] = {0xffffffff, 0x7fffffff}; -#define NAN (*(const float *) __nan) -#endif - -#ifndef INFINITY -#define INFINITY HUGE_VAL -#endif - -#endif -#endif - static gboolean gi_argument_from_c_long (GIArgument *arg_out, long c_long_in, diff --git a/gi/pygi-invoke-state-struct.h b/gi/pygi-invoke-state-struct.h index 139b878..174f473 100644 --- a/gi/pygi-invoke-state-struct.h +++ b/gi/pygi-invoke-state-struct.h @@ -11,39 +11,49 @@ typedef struct _PyGIInvokeState { PyObject *py_in_args; gssize n_py_in_args; - gssize current_arg; GType implementor_gtype; + /* Number of arguments the ffi wrapped C function takes. Used as the exact + * count for argument related arrays held in this struct. + */ + gssize n_args; + + /* List of arguments passed to ffi. Elements can point directly to values held in + * arg_values for "in/from Python" or indirectly via arg_pointers for + * "out/inout/to Python". In the latter case, the arg_pointers[x]->v_pointer + * member points to memory for the value storage. + */ GIArgument **args; - GIArgument *in_args; + + /* Holds memory for the C value of arguments marshaled "to" or "from" Python. */ + GIArgument *arg_values; + + /* Holds pointers to values in arg_values or a caller allocated chunk of + * memory via arg_pointers[x].v_pointer. + */ + GIArgument *arg_pointers; /* Array of pointers allocated to the same length as args which holds from_py * marshaler cleanup data. */ gpointer *args_cleanup_data; - /* Out args and out values - * In order to pass a parameter and get something back out in C - * we need to pass a pointer to the value, e.g. - * int *out_integer; - * - * so while out_args == out_integer, out_value == *out_integer - * or in other words out_args = &out_values - * - * We do all of our processing on out_values but we pass out_args to - * the actual function. - */ - GIArgument *out_args; - GIArgument *out_values; - + /* Memory to receive the result of the C ffi function call. */ GIArgument return_arg; + /* A GError exception which is indirectly bound into the last position of + * the "args" array if the callable caches "throws" member is set. + */ GError *error; gboolean failed; gpointer user_data; + + /* Function pointer to call with ffi. */ + gpointer function_ptr; + } PyGIInvokeState; G_END_DECLS diff --git a/gi/pygi-invoke.c b/gi/pygi-invoke.c index 1d89912..3bb4dc6 100644 --- a/gi/pygi-invoke.c +++ b/gi/pygi-invoke.c @@ -29,61 +29,24 @@ static inline gboolean _invoke_callable (PyGIInvokeState *state, PyGICallableCache *cache, - GICallableInfo *callable_info, - GCallback function_ptr) + GICallableInfo *callable_info) { - GError *error; - gint retval; - - error = NULL; + GIFFIReturnValue ffi_return_value = {0}; Py_BEGIN_ALLOW_THREADS; - /* FIXME: use this for now but we can streamline the calls */ - if (cache->function_type == PYGI_FUNCTION_TYPE_VFUNC) - retval = g_vfunc_info_invoke ( callable_info, - state->implementor_gtype, - state->in_args, - cache->n_from_py_args, - state->out_args, - cache->n_to_py_args, - &state->return_arg, - &error); - else if (g_base_info_get_type (callable_info) == GI_INFO_TYPE_CALLBACK) - retval = g_callable_info_invoke (callable_info, - function_ptr, - state->in_args, - cache->n_from_py_args, - state->out_args, - cache->n_to_py_args, - &state->return_arg, - FALSE, - FALSE, - &error); - else - retval = g_function_info_invoke ( callable_info, - state->in_args, - cache->n_from_py_args, - state->out_args, - cache->n_to_py_args, - &state->return_arg, - &error); - Py_END_ALLOW_THREADS; - - if (!retval) { - g_assert (error != NULL); - pyglib_error_check (&error); - - /* It is unclear if the error occured before or after the C - * function was invoked so for now assume success - * We eventually should marshal directly to FFI so we no longer - * have to use the reference implementation - */ - pygi_marshal_cleanup_args_from_py_marshal_success (state, cache); + ffi_call (&cache->invoker.cif, + state->function_ptr, + (void *)&ffi_return_value, + (void **)state->args); - return FALSE; - } + Py_END_ALLOW_THREADS; + /* If the callable throws, the address of state->error will be bound into + * the state->args as the last value. When the callee sets an error using + * the state->args passed, it will have the side effect of setting + * state->error allowing for easy checking here. + */ if (state->error != NULL) { if (pyglib_error_check (&(state->error))) { /* even though we errored out, the call itself was successful, @@ -93,6 +56,12 @@ _invoke_callable (PyGIInvokeState *state, } } + if (cache->return_cache) { + gi_type_info_extract_ffi_return_value (cache->return_cache->type_info, + &ffi_return_value, + &state->return_arg); + } + return TRUE; } @@ -280,13 +249,24 @@ _py_args_combine_and_check_length (PyGICallableCache *cache, } static inline gboolean -_invoke_state_init_from_callable_cache (PyGIInvokeState *state, +_invoke_state_init_from_callable_cache (GIBaseInfo *info, + PyGIInvokeState *state, PyGICallableCache *cache, PyObject *py_args, PyObject *kwargs) { PyObject *combined_args = NULL; state->implementor_gtype = 0; + state->n_args = _pygi_callable_cache_args_len (cache); + + if (cache->throws) { + state->n_args++; + } + + /* Copy the function pointer to the state for the normal case. For vfuncs, + * this will be filled out based on the implementor_gtype calculated below. + */ + state->function_ptr = cache->invoker.native_address; /* TODO: We don't use the class parameter sent in by the structure * so we remove it from the py_args tuple but we can keep it @@ -308,6 +288,8 @@ _invoke_state_init_from_callable_cache (PyGIInvokeState *state, } } else if (cache->function_type == PYGI_FUNCTION_TYPE_VFUNC) { PyObject *py_gtype; + GError *error = NULL; + py_gtype = PyTuple_GetItem (py_args, 0); if (py_gtype == NULL) { PyErr_SetString (PyExc_TypeError, @@ -319,6 +301,18 @@ _invoke_state_init_from_callable_cache (PyGIInvokeState *state, if (state->implementor_gtype == 0) return FALSE; + + /* vfunc addresses are pulled into the state at call time and cannot be + * cached because the call site can specify a different portion of the + * class hierarchy. e.g. Object.do_func vs. SubObject.do_func might + * retrieve a different vfunc address but GI gives us the same vfunc info. + */ + state->function_ptr = g_vfunc_info_get_address ((GIVFuncInfo *)info, + state->implementor_gtype, + &error); + if (pyglib_error_check (&error)) { + return FALSE; + } } if (cache->function_type == PYGI_FUNCTION_TYPE_CONSTRUCTOR || @@ -344,68 +338,65 @@ _invoke_state_init_from_callable_cache (PyGIInvokeState *state, } state->n_py_in_args = PyTuple_Size (state->py_in_args); - state->args = g_slice_alloc0 (_pygi_callable_cache_args_len (cache) * sizeof (GIArgument *)); - if (state->args == NULL && _pygi_callable_cache_args_len (cache) != 0) { + state->args = g_slice_alloc0 (state->n_args * sizeof (GIArgument *)); + if (state->args == NULL && state->n_args != 0) { PyErr_NoMemory(); return FALSE; } - state->args_cleanup_data = g_slice_alloc0 (_pygi_callable_cache_args_len (cache) * sizeof (gpointer)); - if (state->args_cleanup_data == NULL && _pygi_callable_cache_args_len (cache) != 0) { + state->args_cleanup_data = g_slice_alloc0 (state->n_args * sizeof (gpointer)); + if (state->args_cleanup_data == NULL && state->n_args != 0) { PyErr_NoMemory(); return FALSE; } - state->in_args = g_slice_alloc0 (cache->n_from_py_args * sizeof(GIArgument)); - if (state->in_args == NULL && cache->n_from_py_args != 0) { + state->arg_values = g_slice_alloc0 (state->n_args * sizeof(GIArgument)); + if (state->arg_values == NULL && state->n_args != 0) { PyErr_NoMemory (); return FALSE; } - state->out_values = g_slice_alloc0 (cache->n_to_py_args * sizeof(GIArgument)); - if (state->out_values == NULL && cache->n_to_py_args != 0) { - PyErr_NoMemory (); - return FALSE; - } - - state->out_args = g_slice_alloc0 (cache->n_to_py_args * sizeof(GIArgument)); - if (state->out_args == NULL && cache->n_to_py_args != 0) { + state->arg_pointers = g_slice_alloc0 (state->n_args * sizeof(GIArgument)); + if (state->arg_pointers == NULL && state->n_args != 0) { PyErr_NoMemory (); return FALSE; } state->error = NULL; + if (cache->throws) { + gssize error_index = state->n_args - 1; + /* The ffi argument for GError needs to be a triple pointer. */ + state->arg_pointers[error_index].v_pointer = &state->error; + state->args[error_index] = &(state->arg_pointers[error_index]); + } + return TRUE; } static inline void _invoke_state_clear (PyGIInvokeState *state, PyGICallableCache *cache) { - g_slice_free1 (_pygi_callable_cache_args_len (cache) * sizeof(GIArgument *), state->args); - g_slice_free1 (_pygi_callable_cache_args_len (cache) * sizeof(gpointer), state->args_cleanup_data); - g_slice_free1 (cache->n_from_py_args * sizeof(GIArgument), state->in_args); - g_slice_free1 (cache->n_to_py_args * sizeof(GIArgument), state->out_args); - g_slice_free1 (cache->n_to_py_args * sizeof(GIArgument), state->out_values); + g_slice_free1 (state->n_args * sizeof(GIArgument *), state->args); + g_slice_free1 (state->n_args * sizeof(gpointer), state->args_cleanup_data); + g_slice_free1 (state->n_args * sizeof(GIArgument), state->arg_values); + g_slice_free1 (state->n_args * sizeof(GIArgument), state->arg_pointers); Py_XDECREF (state->py_in_args); } -static gboolean _caller_alloc (PyGIInvokeState *state, - PyGIArgCache *arg_cache, - gssize arg_count, - gssize out_count) +static gboolean +_caller_alloc (PyGIArgCache *arg_cache, GIArgument *arg) { if (arg_cache->type_tag == GI_TYPE_TAG_INTERFACE) { PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache; - state->out_args[out_count].v_pointer = NULL; - state->args[arg_count] = &state->out_args[out_count]; + arg->v_pointer = NULL; if (g_type_is_a (iface_cache->g_type, G_TYPE_BOXED)) { - state->args[arg_count]->v_pointer = + arg->v_pointer = _pygi_boxed_alloc (iface_cache->interface_info, NULL); } else if (iface_cache->g_type == G_TYPE_VALUE) { - state->args[arg_count]->v_pointer = g_slice_new0 (GValue); + arg->v_pointer = g_slice_new0 (GValue); } else if (iface_cache->is_foreign) { PyObject *foreign_struct = pygi_struct_foreign_convert_from_g_argument ( @@ -415,34 +406,59 @@ static gboolean _caller_alloc (PyGIInvokeState *state, pygi_struct_foreign_convert_to_g_argument (foreign_struct, iface_cache->interface_info, GI_TRANSFER_EVERYTHING, - state->args[arg_count]); + arg); } else { gssize size = g_struct_info_get_size( (GIStructInfo *)iface_cache->interface_info); - state->args[arg_count]->v_pointer = g_malloc0 (size); + arg->v_pointer = g_malloc0 (size); } } else if (arg_cache->type_tag == GI_TYPE_TAG_ARRAY) { PyGIArgGArray *array_cache = (PyGIArgGArray *)arg_cache; - state->out_args[out_count].v_pointer = g_array_new (TRUE, TRUE, array_cache->item_size); - state->args[arg_count] = &state->out_args[out_count]; + arg->v_pointer = g_array_new (TRUE, TRUE, array_cache->item_size); } else { return FALSE; } - if (state->args[arg_count]->v_pointer == NULL) + if (arg->v_pointer == NULL) return FALSE; return TRUE; } +/* _invoke_marshal_in_args: + * + * Fills out the state struct argument lists. arg_values will always hold + * actual values marshaled either to or from Python and C. arg_pointers will + * hold pointers (via v_pointer) to auxilary value storage. This will normally + * point to values stored in arg_values. In the case of caller allocated + * out args, arg_pointers[x].v_pointer will point to newly allocated memory. + * arg_pointers inserts a level of pointer indirection between arg_values + * and the argument list ffi receives when dealing with non-caller allocated + * out arguments. + * + * For example: + * [[ + * void callee (int *i, int j) { *i = 50 - j; } + * void caller () { + * int i = 0; + * callee (&i, 8); + * } + * + * args[0] == &arg_pointers[0]; + * arg_pointers[0].v_pointer == &arg_values[0]; + * arg_values[0].v_int == 42; + * + * args[1] == &arg_values[1]; + * arg_values[1].v_int == 8; + * ]] + * + */ static inline gboolean _invoke_marshal_in_args (PyGIInvokeState *state, PyGICallableCache *cache) { - gssize i, in_count, out_count; - in_count = 0; - out_count = 0; + gssize i; if (state->n_py_in_args > cache->n_py_args) { PyErr_Format (PyExc_TypeError, @@ -454,14 +470,14 @@ _invoke_marshal_in_args (PyGIInvokeState *state, PyGICallableCache *cache) } for (i = 0; i < _pygi_callable_cache_args_len (cache); i++) { - GIArgument *c_arg; + GIArgument *c_arg = &state->arg_values[i]; PyGIArgCache *arg_cache = g_ptr_array_index (cache->args_cache, i); PyObject *py_arg = NULL; switch (arg_cache->direction) { case PYGI_DIRECTION_FROM_PYTHON: - state->args[i] = &(state->in_args[in_count]); - in_count++; + /* The ffi argument points directly at memory in arg_values. */ + state->args[i] = c_arg; if (arg_cache->meta_type == PYGI_META_ARG_TYPE_CLOSURE) { state->args[i]->v_pointer = state->user_data; @@ -491,13 +507,6 @@ _invoke_marshal_in_args (PyGIInvokeState *state, PyGICallableCache *cache) break; case PYGI_DIRECTION_BIDIRECTIONAL: - /* this will be filled in if it is an child value */ - if (state->in_args[in_count].v_pointer != NULL) - state->out_values[out_count] = state->in_args[in_count]; - - state->in_args[in_count].v_pointer = &state->out_values[out_count]; - in_count++; - if (arg_cache->meta_type != PYGI_META_ARG_TYPE_CHILD) { if (arg_cache->py_arg_index >= state->n_py_in_args) { PyErr_Format (PyExc_TypeError, @@ -515,9 +524,27 @@ _invoke_marshal_in_args (PyGIInvokeState *state, PyGICallableCache *cache) PyTuple_GET_ITEM (state->py_in_args, arg_cache->py_arg_index); } + /* Fall through */ + case PYGI_DIRECTION_TO_PYTHON: + /* arg_pointers always stores a pointer to the data to be marshaled "to python" + * even in cases where arg_pointers is not being used as indirection between + * ffi and arg_values. This gives a guarantee that out argument marshaling + * (_invoke_marshal_out_args) can always rely on arg_pointers pointing to + * the correct chunk of memory to marshal. + */ + state->arg_pointers[i].v_pointer = c_arg; + if (arg_cache->is_caller_allocates) { - if (!_caller_alloc (state, arg_cache, i, out_count)) { + /* In the case of caller allocated out args, we don't use + * an extra level of indirection and state->args will point + * directly at the data to be marshaled. However, as noted + * above, arg_pointers will also point to this caller allocated + * chunk of memory used by out argument marshaling. + */ + state->args[i] = c_arg; + + if (!_caller_alloc (arg_cache, c_arg)) { PyErr_Format (PyExc_TypeError, "Could not caller allocate argument %zd of callable %s", i, cache->name); @@ -527,14 +554,14 @@ _invoke_marshal_in_args (PyGIInvokeState *state, PyGICallableCache *cache) return FALSE; } } else { - state->out_args[out_count].v_pointer = &state->out_values[out_count]; - state->args[i] = &state->out_values[out_count]; + /* Non-caller allocated out args will use arg_pointers as an + * extra level of indirection */ + state->args[i] = &state->arg_pointers[i]; } - out_count++; + break; } - c_arg = state->args[i]; if (py_arg == _PyGIDefaultArgPlaceholder) { *c_arg = arg_cache->default_value; } else if (arg_cache->from_py_marshaller != NULL) { @@ -642,7 +669,7 @@ _invoke_marshal_out_args (PyGIInvokeState *state, PyGICallableCache *cache) py_out = arg_cache->to_py_marshaller (state, cache, arg_cache, - state->args[arg_cache->c_arg_index]); + state->arg_pointers[arg_cache->c_arg_index].v_pointer); if (py_out == NULL) { pygi_marshal_cleanup_args_to_py_parameter_fail (state, cache, @@ -665,7 +692,7 @@ _invoke_marshal_out_args (PyGIInvokeState *state, PyGICallableCache *cache) PyObject *py_obj = arg_cache->to_py_marshaller (state, cache, arg_cache, - state->args[arg_cache->c_arg_index]); + state->arg_pointers[arg_cache->c_arg_index].v_pointer); if (py_obj == NULL) { if (has_return) @@ -688,12 +715,12 @@ _invoke_marshal_out_args (PyGIInvokeState *state, PyGICallableCache *cache) PyObject * pygi_callable_info_invoke (GIBaseInfo *info, PyObject *py_args, PyObject *kwargs, PyGICallableCache *cache, - GCallback function_ptr, gpointer user_data) + gpointer user_data) { PyGIInvokeState state = { 0, }; PyObject *ret = NULL; - if (!_invoke_state_init_from_callable_cache (&state, cache, py_args, kwargs)) + if (!_invoke_state_init_from_callable_cache (info, &state, cache, py_args, kwargs)) goto err; if (cache->function_type == PYGI_FUNCTION_TYPE_CCALLBACK) @@ -702,7 +729,7 @@ pygi_callable_info_invoke (GIBaseInfo *info, PyObject *py_args, if (!_invoke_marshal_in_args (&state, cache)) goto err; - if (!_invoke_callable (&state, cache, info, function_ptr)) + if (!_invoke_callable (&state, cache, info)) goto err; ret = _invoke_marshal_out_args (&state, cache); @@ -720,10 +747,10 @@ _wrap_g_callable_info_invoke (PyGIBaseInfo *self, PyObject *py_args, PyObject *kwargs) { if (self->cache == NULL) { - self->cache = pygi_callable_cache_new (self->info, FALSE); + self->cache = pygi_callable_cache_new (self->info, NULL, FALSE); if (self->cache == NULL) return NULL; } - return pygi_callable_info_invoke (self->info, py_args, kwargs, self->cache, NULL, NULL); + return pygi_callable_info_invoke (self->info, py_args, kwargs, self->cache, NULL); } diff --git a/gi/pygi-invoke.h b/gi/pygi-invoke.h index 051bc8d..a481be3 100644 --- a/gi/pygi-invoke.h +++ b/gi/pygi-invoke.h @@ -32,7 +32,7 @@ G_BEGIN_DECLS PyObject *pygi_callable_info_invoke (GIBaseInfo *info, PyObject *py_args, PyObject *kwargs, PyGICallableCache *cache, - GCallback function_ptr, gpointer user_data); + gpointer user_data); PyObject *_wrap_g_callable_info_invoke (PyGIBaseInfo *self, PyObject *py_args, PyObject *kwargs); diff --git a/gi/pygi-marshal-cleanup.c b/gi/pygi-marshal-cleanup.c index 3d82601..169e149 100644 --- a/gi/pygi-marshal-cleanup.c +++ b/gi/pygi-marshal-cleanup.c @@ -136,7 +136,7 @@ pygi_marshal_cleanup_args_to_py_marshal_success (PyGIInvokeState *state, while (cache_item) { PyGIArgCache *arg_cache = (PyGIArgCache *) cache_item->data; PyGIMarshalCleanupFunc cleanup_func = arg_cache->to_py_cleanup; - gpointer data = state->args[arg_cache->c_arg_index]->v_pointer; + gpointer data = state->arg_values[arg_cache->c_arg_index].v_pointer; if (cleanup_func != NULL && data != NULL) cleanup_func (state, @@ -168,7 +168,7 @@ pygi_marshal_cleanup_args_from_py_parameter_fail (PyGIInvokeState *state, for (i = 0; i < _pygi_callable_cache_args_len (cache) && i <= failed_arg_index; i++) { PyGIArgCache *arg_cache = _pygi_callable_cache_get_arg (cache, i); PyGIMarshalCleanupFunc cleanup_func = arg_cache->from_py_cleanup; - gpointer data = state->args[i]->v_pointer; + gpointer data = state->arg_values[i].v_pointer; PyObject *py_arg = PyTuple_GET_ITEM (state->py_in_args, arg_cache->py_arg_index); diff --git a/gi/pygi-property.c b/gi/pygi-property.c index 3f6d038..6f80506 100644 --- a/gi/pygi-property.c +++ b/gi/pygi-property.c @@ -302,7 +302,7 @@ pygi_set_property_value_real (PyGObject *instance, g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec)); - // FIXME: Lots of types still unhandled + /* FIXME: Lots of types still unhandled */ type_tag = g_type_info_get_tag (type_info); switch (type_tag) { case GI_TYPE_TAG_INTERFACE: diff --git a/gi/pygtype.c b/gi/pygtype.c index e1fb4e6..fb21282 100644 --- a/gi/pygtype.c +++ b/gi/pygtype.c @@ -946,7 +946,7 @@ gclosure_from_pyfunc(PyGObject *object, PyObject *func) PyGClosure *pyclosure = l->data; int res = PyObject_RichCompareBool(pyclosure->callback, func, Py_EQ); if (res == -1) { - PyErr_Clear(); // Is there anything else to do? + PyErr_Clear(); /* Is there anything else to do? */ } else if (res) { return (GClosure*)pyclosure; } diff --git a/tests/test_generictreemodel.py b/tests/test_generictreemodel.py index 9fa89ff..6ba71bc 100644 --- a/tests/test_generictreemodel.py +++ b/tests/test_generictreemodel.py @@ -28,9 +28,15 @@ import unittest # pygobject from gi.repository import GObject -from gi.repository import Gtk -from pygtkcompat.generictreemodel import GenericTreeModel -from pygtkcompat.generictreemodel import _get_user_data_as_pyobject + +try: + from gi.repository import Gtk + from pygtkcompat.generictreemodel import GenericTreeModel + from pygtkcompat.generictreemodel import _get_user_data_as_pyobject + has_gtk = True +except ImportError: + GenericTreeModel = object + has_gtk = False class Node(object): @@ -127,6 +133,7 @@ class TesterModel(GenericTreeModel): return child.parent() +@unittest.skipUnless(has_gtk, 'Gtk not available') class TestReferences(unittest.TestCase): def setUp(self): pass @@ -279,6 +286,7 @@ class TestReferences(unittest.TestCase): self.assertEqual(ref(), None) +@unittest.skipUnless(has_gtk, 'Gtk not available') class TestIteration(unittest.TestCase): def test_iter_next_root(self): model = TesterModel() @@ -306,6 +314,7 @@ class ErrorModel(GenericTreeModel): pass +@unittest.skipUnless(has_gtk, 'Gtk not available') class ExceptHook(object): """ Temporarily installs an exception hook in a context which @@ -337,6 +346,7 @@ class ExceptHook(object): assert issubclass(got, expected), error_message +@unittest.skipUnless(has_gtk, 'Gtk not available') class TestReturnsAfterError(unittest.TestCase): def setUp(self): self.model = ErrorModel() diff --git a/tests/test_overrides_gtk.py b/tests/test_overrides_gtk.py index 210cf45..2a0fd90 100644 --- a/tests/test_overrides_gtk.py +++ b/tests/test_overrides_gtk.py @@ -633,26 +633,26 @@ class TestGtk(unittest.TestCase): @unittest.skipUnless(Gtk, 'Gtk not available') class TestSignals(unittest.TestCase): - class WindowWithSizeAllocOverride(Gtk.ScrolledWindow): - __gsignals__ = {'size-allocate': 'override'} + def test_class_closure_override_with_aliased_type(self): + class WindowWithSizeAllocOverride(Gtk.ScrolledWindow): + __gsignals__ = {'size-allocate': 'override'} - def __init__(self): - Gtk.ScrolledWindow.__init__(self) - self._alloc_called = False - self._alloc_value = None - self._alloc_error = None + def __init__(self): + Gtk.ScrolledWindow.__init__(self) + self._alloc_called = False + self._alloc_value = None + self._alloc_error = None - def do_size_allocate(self, alloc): - self._alloc_called = True - self._alloc_value = alloc + def do_size_allocate(self, alloc): + self._alloc_called = True + self._alloc_value = alloc - try: - Gtk.ScrolledWindow.do_size_allocate(self, alloc) - except Exception as e: - self._alloc_error = e + try: + Gtk.ScrolledWindow.do_size_allocate(self, alloc) + except Exception as e: + self._alloc_error = e - def test_class_closure_override_with_aliased_type(self): - win = self.WindowWithSizeAllocOverride() + win = WindowWithSizeAllocOverride() rect = Gdk.Rectangle() rect.width = 100 rect.height = 100 diff --git a/tests/test_properties.py b/tests/test_properties.py index d7ceb89..c0579f7 100644 --- a/tests/test_properties.py +++ b/tests/test_properties.py @@ -21,10 +21,15 @@ from gi.repository.GObject import \ from gi.repository import Gio from gi.repository import GLib -from gi.repository import Regress from gi.repository import GIMarshallingTests from gi import _propertyhelper as propertyhelper +try: + from gi.repository import Regress + has_regress = True +except ImportError: + has_regress = False + if sys.version_info < (3, 0): TEST_UTF8 = "\xe2\x99\xa5" UNICODE_UTF8 = unicode(TEST_UTF8, 'UTF-8') @@ -73,19 +78,20 @@ class PropertyObject(GObject.GObject): type=Gio.File, flags=PARAM_READWRITE | PARAM_CONSTRUCT) -class PropertyInheritanceObject(Regress.TestObj): - # override property from the base class, with a different type - string = GObject.Property(type=int) - - # a property entirely defined at the Python level - python_prop = GObject.Property(type=str) +if has_regress: + class PropertyInheritanceObject(Regress.TestObj): + # override property from the base class, with a different type + string = GObject.Property(type=int) + # a property entirely defined at the Python level + python_prop = GObject.Property(type=str) -class PropertySubClassObject(PropertyInheritanceObject): - # override property from the base class, with a different type - python_prop = GObject.Property(type=int) + class PropertySubClassObject(PropertyInheritanceObject): + # override property from the base class, with a different type + python_prop = GObject.Property(type=int) +@unittest.skipUnless(has_regress, 'Missing Regress typelib') class TestPropertyInheritanceObject(unittest.TestCase): def test_override_gi_property(self): self.assertNotEqual(Regress.TestObj.props.string.value_type, @@ -728,6 +734,7 @@ class TestProperty(unittest.TestCase): b.prop1 = 20 self.assertEqual(b.prop1, 20) + @unittest.skipUnless(has_regress, 'Missing regress typelib') def test_property_subclass_c(self): class A(Regress.TestSubObj): prop1 = GObject.Property(type=int) -- 2.34.1