diff options
Diffstat (limited to 'gi')
-rw-r--r-- | gi/Makefile.am | 133 | ||||
-rw-r--r-- | gi/Makefile.in | 1154 | ||||
-rw-r--r-- | gi/__init__.py | 113 | ||||
-rw-r--r-- | gi/_constants.py | 47 | ||||
-rw-r--r-- | gi/_error.py | 55 | ||||
-rw-r--r-- | gi/_glib/Makefile.am | 91 | ||||
-rw-r--r-- | gi/_glib/Makefile.in | 915 | ||||
-rw-r--r-- | gi/_glib/__init__.py | 25 | ||||
-rw-r--r-- | gi/_glib/glibmodule.c | 103 | ||||
-rw-r--r-- | gi/_glib/pyglib-private.h | 49 | ||||
-rw-r--r-- | gi/_glib/pyglib-python-compat.h | 220 | ||||
-rw-r--r-- | gi/_glib/pyglib.c | 475 | ||||
-rw-r--r-- | gi/_glib/pyglib.h | 77 | ||||
-rw-r--r-- | gi/_gobject/Makefile.am | 87 | ||||
-rw-r--r-- | gi/_gobject/Makefile.in | 923 | ||||
-rw-r--r-- | gi/_gobject/__init__.py | 60 | ||||
-rw-r--r-- | gi/_gobject/constants.py | 49 | ||||
-rw-r--r-- | gi/_gobject/gobjectmodule.c | 2220 | ||||
-rw-r--r-- | gi/_gobject/pygflags.h | 27 | ||||
-rw-r--r-- | gi/_gobject/pygobject-private.h | 204 | ||||
-rw-r--r-- | gi/_gobject/pygparamspec.c | 404 | ||||
-rw-r--r-- | gi/_gobject/pygtype.c | 1927 | ||||
-rw-r--r-- | gi/_gobject/pygtype.h | 28 | ||||
-rw-r--r-- | gi/_gtktemplate.py | 307 | ||||
-rw-r--r-- | gi/_option.py (renamed from gi/_glib/option.py) | 113 | ||||
-rw-r--r-- | gi/_ossighelper.py | 239 | ||||
-rw-r--r-- | gi/_propertyhelper.py (renamed from gi/_gobject/propertyhelper.py) | 157 | ||||
-rw-r--r-- | gi/_signalhelper.py (renamed from gi/_gobject/signalhelper.py) | 153 | ||||
-rw-r--r-- | gi/docstring.py | 181 | ||||
-rw-r--r-- | gi/gimodule.c | 2211 | ||||
-rw-r--r-- | gi/gimodule.h | 17 | ||||
-rw-r--r-- | gi/importer.py | 133 | ||||
-rw-r--r-- | gi/meson.build | 91 | ||||
-rw-r--r-- | gi/module.py | 223 | ||||
-rw-r--r-- | gi/overrides/GIMarshallingTests.py | 6 | ||||
-rw-r--r-- | gi/overrides/GLib.py | 569 | ||||
-rw-r--r-- | gi/overrides/GObject.py | 525 | ||||
-rw-r--r-- | gi/overrides/Gdk.py | 547 | ||||
-rw-r--r-- | gi/overrides/GdkPixbuf.py | 53 | ||||
-rw-r--r-- | gi/overrides/Gio.py | 321 | ||||
-rw-r--r-- | gi/overrides/Gtk.py | 1535 | ||||
-rw-r--r-- | gi/overrides/Makefile.am | 23 | ||||
-rw-r--r-- | gi/overrides/Makefile.in | 582 | ||||
-rw-r--r-- | gi/overrides/Pango.py | 22 | ||||
-rw-r--r-- | gi/overrides/__init__.py | 357 | ||||
-rw-r--r-- | gi/overrides/keysyms.py | 1494 | ||||
-rw-r--r-- | gi/overrides/meson.build | 15 | ||||
-rw-r--r-- | gi/pygboxed.c (renamed from gi/_gobject/pygboxed.c) | 162 | ||||
-rw-r--r-- | gi/pygboxed.h (renamed from gi/_gobject/pygboxed.h) | 15 | ||||
-rw-r--r-- | gi/pygenum.c (renamed from gi/_gobject/pygenum.c) | 147 | ||||
-rw-r--r-- | gi/pygenum.h | 47 | ||||
-rw-r--r-- | gi/pygflags.c (renamed from gi/_gobject/pygflags.c) | 155 | ||||
-rw-r--r-- | gi/pygflags.h | 46 | ||||
-rw-r--r-- | gi/pygi-argument.c | 1087 | ||||
-rw-r--r-- | gi/pygi-argument.h | 41 | ||||
-rw-r--r-- | gi/pygi-array.c | 978 | ||||
-rw-r--r-- | gi/pygi-array.h | 43 | ||||
-rw-r--r-- | gi/pygi-basictype.c | 1338 | ||||
-rw-r--r-- | gi/pygi-basictype.h | 89 | ||||
-rw-r--r-- | gi/pygi-boxed.c | 168 | ||||
-rw-r--r-- | gi/pygi-boxed.h | 23 | ||||
-rw-r--r-- | gi/pygi-cache.c | 1867 | ||||
-rw-r--r-- | gi/pygi-cache.h | 255 | ||||
-rw-r--r-- | gi/pygi-ccallback.c | 52 | ||||
-rw-r--r-- | gi/pygi-ccallback.h | 17 | ||||
-rw-r--r-- | gi/pygi-closure.c | 1074 | ||||
-rw-r--r-- | gi/pygi-closure.h | 20 | ||||
-rw-r--r-- | gi/pygi-enum-marshal.c | 407 | ||||
-rw-r--r-- | gi/pygi-enum-marshal.h | 42 | ||||
-rw-r--r-- | gi/pygi-error.c | 374 | ||||
-rw-r--r-- | gi/pygi-error.h | 50 | ||||
-rw-r--r-- | gi/pygi-foreign-api.h | 85 | ||||
-rw-r--r-- | gi/pygi-foreign-cairo.c | 549 | ||||
-rw-r--r-- | gi/pygi-foreign.c | 114 | ||||
-rw-r--r-- | gi/pygi-foreign.h | 23 | ||||
-rw-r--r-- | gi/pygi-hashtable.c | 420 | ||||
-rw-r--r-- | gi/pygi-hashtable.h | 36 | ||||
-rw-r--r-- | gi/pygi-info.c | 1686 | ||||
-rw-r--r-- | gi/pygi-info.h | 28 | ||||
-rw-r--r-- | gi/pygi-invoke-state-struct.h | 64 | ||||
-rw-r--r-- | gi/pygi-invoke.c | 685 | ||||
-rw-r--r-- | gi/pygi-invoke.h | 16 | ||||
-rw-r--r-- | gi/pygi-list.c | 500 | ||||
-rw-r--r-- | gi/pygi-list.h | 39 | ||||
-rw-r--r-- | gi/pygi-marshal-cleanup.c | 523 | ||||
-rw-r--r-- | gi/pygi-marshal-cleanup.h | 65 | ||||
-rw-r--r-- | gi/pygi-marshal-from-py.c | 1870 | ||||
-rw-r--r-- | gi/pygi-marshal-from-py.h | 151 | ||||
-rw-r--r-- | gi/pygi-marshal-to-py.c | 891 | ||||
-rw-r--r-- | gi/pygi-marshal-to-py.h | 104 | ||||
-rw-r--r-- | gi/pygi-object.c | 381 | ||||
-rw-r--r-- | gi/pygi-object.h | 52 | ||||
-rw-r--r-- | gi/pygi-private.h | 87 | ||||
-rw-r--r-- | gi/pygi-property.c | 251 | ||||
-rw-r--r-- | gi/pygi-property.h | 21 | ||||
-rw-r--r-- | gi/pygi-repository.c | 144 | ||||
-rw-r--r-- | gi/pygi-repository.h | 12 | ||||
-rw-r--r-- | gi/pygi-resulttuple.c | 368 | ||||
-rw-r--r-- | gi/pygi-resulttuple.h (renamed from gi/_gobject/pygenum.h) | 27 | ||||
-rw-r--r-- | gi/pygi-signal-closure.c | 107 | ||||
-rw-r--r-- | gi/pygi-signal-closure.h | 17 | ||||
-rw-r--r-- | gi/pygi-source.c | 139 | ||||
-rw-r--r-- | gi/pygi-source.h | 4 | ||||
-rw-r--r-- | gi/pygi-struct-marshal.c | 646 | ||||
-rw-r--r-- | gi/pygi-struct-marshal.h | 69 | ||||
-rw-r--r-- | gi/pygi-struct.c | 177 | ||||
-rw-r--r-- | gi/pygi-struct.h | 23 | ||||
-rw-r--r-- | gi/pygi-type.c | 1367 | ||||
-rw-r--r-- | gi/pygi-type.h | 52 | ||||
-rw-r--r-- | gi/pygi-util.c | 126 | ||||
-rw-r--r-- | gi/pygi-util.h | 56 | ||||
-rw-r--r-- | gi/pygi-value.c | 933 | ||||
-rw-r--r-- | gi/pygi-value.h | 52 | ||||
-rw-r--r-- | gi/pygi.h | 190 | ||||
-rw-r--r-- | gi/pyginterface.c (renamed from gi/_gobject/pyginterface.c) | 70 | ||||
-rw-r--r-- | gi/pyginterface.h (renamed from gi/_gobject/pyginterface.h) | 6 | ||||
-rw-r--r-- | gi/pygobject-external.h | 75 | ||||
-rw-r--r-- | gi/pygobject-internal.h | 7 | ||||
-rw-r--r-- | gi/pygobject-object.c (renamed from gi/_gobject/pygobject.c) | 729 | ||||
-rw-r--r-- | gi/pygobject-object.h | 52 | ||||
-rw-r--r-- | gi/pygobject.h (renamed from gi/_gobject/pygobject.h) | 42 | ||||
-rw-r--r-- | gi/pygoptioncontext.c (renamed from gi/_glib/pygoptioncontext.c) | 88 | ||||
-rw-r--r-- | gi/pygoptioncontext.h (renamed from gi/_glib/pygoptioncontext.h) | 6 | ||||
-rw-r--r-- | gi/pygoptiongroup.c (renamed from gi/_glib/pygoptiongroup.c) | 55 | ||||
-rw-r--r-- | gi/pygoptiongroup.h (renamed from gi/_glib/pygoptiongroup.h) | 9 | ||||
-rw-r--r-- | gi/pygparamspec.c | 423 | ||||
-rw-r--r-- | gi/pygparamspec.h (renamed from gi/_gobject/pygparamspec.h) | 8 | ||||
-rw-r--r-- | gi/pygpointer.c (renamed from gi/_gobject/pygpointer.c) | 71 | ||||
-rw-r--r-- | gi/pygpointer.h (renamed from gi/_gobject/pygpointer.h) | 16 | ||||
-rw-r--r-- | gi/pygspawn.c (renamed from gi/_glib/pygspawn.c) | 92 | ||||
-rw-r--r-- | gi/pygspawn.h (renamed from gi/_glib/pygspawn.h) | 6 | ||||
-rw-r--r-- | gi/pygtkcompat.py | 1 | ||||
-rw-r--r-- | gi/repository/Makefile.am | 16 | ||||
-rw-r--r-- | gi/repository/Makefile.in | 574 | ||||
-rw-r--r-- | gi/repository/__init__.py | 2 | ||||
-rw-r--r-- | gi/repository/meson.build | 5 | ||||
-rw-r--r-- | gi/types.py | 158 |
137 files changed, 21069 insertions, 22349 deletions
diff --git a/gi/Makefile.am b/gi/Makefile.am deleted file mode 100644 index fc11ff8..0000000 --- a/gi/Makefile.am +++ /dev/null @@ -1,133 +0,0 @@ -SUBDIRS = \ - repository \ - overrides \ - _glib \ - _gobject - -extension_cppflags = \ - $(PYTHON_INCLUDES) \ - -DPY_SSIZE_T_CLEAN - -extension_ldflags = \ - -module \ - -avoid-version \ - -shrext $(PYTHON_SO) - -if OS_WIN32 -# Windows requires Python modules to be explicitly linked to libpython. -# Extension modules are shared libaries (.dll), but need to be -# called .pyd for Python to load it as an extension module. -extension_libadd = \ - $(PYTHON_LIBS) - -extension_ldflags += \ - -no-undefined -endif - -pygidir = $(pyexecdir)/gi - -pygi_PYTHON = \ - __init__.py \ - types.py \ - module.py \ - importer.py \ - pygtkcompat.py \ - docstring.py - -pygi_LTLIBRARIES = _gi.la - -_gi_la_SOURCES = \ - pygi-repository.c \ - pygi-repository.h \ - pygi-info.c \ - pygi-info.h \ - pygi-foreign.c \ - pygi-foreign.h \ - pygi-struct.c \ - pygi-struct.h \ - pygi-source.c \ - pygi-source.h \ - pygi-argument.c \ - pygi-argument.h \ - pygi-type.c \ - pygi-type.h \ - pygi-boxed.c \ - pygi-boxed.h \ - pygi-closure.c \ - pygi-closure.h \ - pygi-ccallback.c \ - pygi-ccallback.h \ - pygi.h \ - pygi-private.h \ - pygi-property.c \ - pygi-property.h \ - pygi-signal-closure.c \ - pygi-signal-closure.h \ - pygobject-external.h \ - gimodule.c \ - pygi-invoke.c \ - pygi-invoke.h \ - pygi-invoke-state-struct.h \ - pygi-cache.h \ - pygi-cache.c \ - pygi-marshal-from-py.c \ - pygi-marshal-from-py.h \ - pygi-marshal-to-py.c \ - pygi-marshal-to-py.h \ - pygi-marshal-cleanup.c \ - pygi-marshal-cleanup.h -_gi_la_CFLAGS = \ - $(GI_CFLAGS) -_gi_la_CPPFLAGS = \ - $(extension_cppflags) \ - -I$(top_srcdir)/gi/_glib \ - -I$(top_srcdir)/gi/_gobject -_gi_la_LIBADD = \ - $(extension_libadd) \ - $(GI_LIBS) \ - $(top_builddir)/gi/_glib/libpyglib-gi-2.0-@PYTHON_BASENAME@.la -_gi_la_LDFLAGS = \ - $(extension_ldflags) \ - -export-symbols-regex "init_gi|PyInit__gi" - -if ENABLE_CAIRO -pygi_LTLIBRARIES += _gi_cairo.la -endif - -_gi_cairo_la_SOURCES = \ - pygi-foreign-cairo.c -_gi_cairo_la_CFLAGS = \ - $(GI_CFLAGS) \ - $(PYCAIRO_CFLAGS) -_gi_cairo_la_CPPFLAGS = \ - $(extension_cppflags) \ - -I$(top_srcdir)/gi/_glib \ - -I$(top_srcdir)/gi/_gobject -_gi_cairo_la_LIBADD = \ - $(extension_libadd) \ - $(GI_LIBS) \ - $(PYCAIRO_LIBS) -_gi_cairo_la_LDFLAGS = \ - $(extension_ldflags) \ - -export-symbols-regex "init_gi_cairo|PyInit__gi_cairo" - - -# This is to ensure we have a symlink to the .so in the -# build directory, which the Python interpreter can load -# directly without having to know how to parse .la files. -%$(PYTHON_SO): %.la - $(LN_S) -f .libs/$@ $@ - -# 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 $(pygi_PYTHON); do \ - [ -e $(builddir)/$$f ] || $(LN_S) $(srcdir)/$$f $(builddir)/$$f; \ - done - -all-local: $(LTLIBRARIES:.la=$(PYTHON_SO)) build_pylinks - -check-local: $(LTLIBRARIES:.la=$(PYTHON_SO)) build_pylinks -clean-local: - rm -f $(LTLIBRARIES:.la=$(PYTHON_SO)) diff --git a/gi/Makefile.in b/gi/Makefile.in deleted file mode 100644 index abc8c4e..0000000 --- a/gi/Makefile.in +++ /dev/null @@ -1,1154 +0,0 @@ -# Makefile.in generated by automake 1.13.3 from Makefile.am. -# @configure_input@ - -# Copyright (C) 1994-2013 Free Software Foundation, Inc. - -# This Makefile.in is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY, to the extent permitted by law; without -# even the implied warranty of MERCHANTABILITY or FITNESS FOR A -# PARTICULAR PURPOSE. - -@SET_MAKE@ - -VPATH = @srcdir@ -am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' -am__make_running_with_option = \ - case $${target_option-} in \ - ?) ;; \ - *) echo "am__make_running_with_option: internal error: invalid" \ - "target option '$${target_option-}' specified" >&2; \ - exit 1;; \ - esac; \ - has_opt=no; \ - sane_makeflags=$$MAKEFLAGS; \ - if $(am__is_gnu_make); then \ - sane_makeflags=$$MFLAGS; \ - else \ - case $$MAKEFLAGS in \ - *\\[\ \ ]*) \ - bs=\\; \ - sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ - | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ - esac; \ - fi; \ - skip_next=no; \ - strip_trailopt () \ - { \ - flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ - }; \ - for flg in $$sane_makeflags; do \ - test $$skip_next = yes && { skip_next=no; continue; }; \ - case $$flg in \ - *=*|--*) continue;; \ - -*I) strip_trailopt 'I'; skip_next=yes;; \ - -*I?*) strip_trailopt 'I';; \ - -*O) strip_trailopt 'O'; skip_next=yes;; \ - -*O?*) strip_trailopt 'O';; \ - -*l) strip_trailopt 'l'; skip_next=yes;; \ - -*l?*) strip_trailopt 'l';; \ - -[dEDm]) skip_next=yes;; \ - -[JT]) skip_next=yes;; \ - esac; \ - case $$flg in \ - *$$target_option*) has_opt=yes; break;; \ - esac; \ - done; \ - test $$has_opt = yes -am__make_dryrun = (target_option=n; $(am__make_running_with_option)) -am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) -pkgdatadir = $(datadir)/@PACKAGE@ -pkgincludedir = $(includedir)/@PACKAGE@ -pkglibdir = $(libdir)/@PACKAGE@ -pkglibexecdir = $(libexecdir)/@PACKAGE@ -am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd -install_sh_DATA = $(install_sh) -c -m 644 -install_sh_PROGRAM = $(install_sh) -c -install_sh_SCRIPT = $(install_sh) -c -INSTALL_HEADER = $(INSTALL_DATA) -transform = $(program_transform_name) -NORMAL_INSTALL = : -PRE_INSTALL = : -POST_INSTALL = : -NORMAL_UNINSTALL = : -PRE_UNINSTALL = : -POST_UNINSTALL = : -build_triplet = @build@ -host_triplet = @host@ -@OS_WIN32_TRUE@am__append_1 = \ -@OS_WIN32_TRUE@ -no-undefined - -@ENABLE_CAIRO_TRUE@am__append_2 = _gi_cairo.la -subdir = gi -DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ - $(top_srcdir)/depcomp $(pygi_PYTHON) $(top_srcdir)/py-compile -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 -am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ - $(ACLOCAL_M4) -mkinstalldirs = $(install_sh) -d -CONFIG_HEADER = $(top_builddir)/config.h -CONFIG_CLEAN_FILES = -CONFIG_CLEAN_VPATH_FILES = -am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; -am__vpath_adj = case $$p in \ - $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ - *) f=$$p;; \ - esac; -am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; -am__install_max = 40 -am__nobase_strip_setup = \ - srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` -am__nobase_strip = \ - for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" -am__nobase_list = $(am__nobase_strip_setup); \ - for p in $$list; do echo "$$p $$p"; done | \ - sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ - $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ - if (++n[$$2] == $(am__install_max)) \ - { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ - END { for (dir in files) print dir, files[dir] }' -am__base_list = \ - sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ - sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' -am__uninstall_files_from_dir = { \ - test -z "$$files" \ - || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ - || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ - $(am__cd) "$$dir" && rm -f $$files; }; \ - } -am__installdirs = "$(DESTDIR)$(pygidir)" "$(DESTDIR)$(pygidir)" -LTLIBRARIES = $(pygi_LTLIBRARIES) -am__DEPENDENCIES_1 = -@OS_WIN32_TRUE@am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1) -_gi_la_DEPENDENCIES = $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \ - $(top_builddir)/gi/_glib/libpyglib-gi-2.0-@PYTHON_BASENAME@.la -am__gi_la_OBJECTS = _gi_la-pygi-repository.lo _gi_la-pygi-info.lo \ - _gi_la-pygi-foreign.lo _gi_la-pygi-struct.lo \ - _gi_la-pygi-source.lo _gi_la-pygi-argument.lo \ - _gi_la-pygi-type.lo _gi_la-pygi-boxed.lo \ - _gi_la-pygi-closure.lo _gi_la-pygi-ccallback.lo \ - _gi_la-pygi-property.lo _gi_la-pygi-signal-closure.lo \ - _gi_la-gimodule.lo _gi_la-pygi-invoke.lo _gi_la-pygi-cache.lo \ - _gi_la-pygi-marshal-from-py.lo _gi_la-pygi-marshal-to-py.lo \ - _gi_la-pygi-marshal-cleanup.lo -_gi_la_OBJECTS = $(am__gi_la_OBJECTS) -AM_V_lt = $(am__v_lt_@AM_V@) -am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) -am__v_lt_0 = --silent -am__v_lt_1 = -_gi_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ - $(LIBTOOLFLAGS) --mode=link $(CCLD) $(_gi_la_CFLAGS) $(CFLAGS) \ - $(_gi_la_LDFLAGS) $(LDFLAGS) -o $@ -_gi_cairo_la_DEPENDENCIES = $(am__DEPENDENCIES_2) \ - $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) -am__gi_cairo_la_OBJECTS = _gi_cairo_la-pygi-foreign-cairo.lo -_gi_cairo_la_OBJECTS = $(am__gi_cairo_la_OBJECTS) -_gi_cairo_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ - $(LIBTOOLFLAGS) --mode=link $(CCLD) $(_gi_cairo_la_CFLAGS) \ - $(CFLAGS) $(_gi_cairo_la_LDFLAGS) $(LDFLAGS) -o $@ -@ENABLE_CAIRO_TRUE@am__gi_cairo_la_rpath = -rpath $(pygidir) -AM_V_P = $(am__v_P_@AM_V@) -am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) -am__v_P_0 = false -am__v_P_1 = : -AM_V_GEN = $(am__v_GEN_@AM_V@) -am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) -am__v_GEN_0 = @echo " GEN " $@; -am__v_GEN_1 = -AM_V_at = $(am__v_at_@AM_V@) -am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) -am__v_at_0 = @ -am__v_at_1 = -DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) -depcomp = $(SHELL) $(top_srcdir)/depcomp -am__depfiles_maybe = depfiles -am__mv = mv -f -COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ - $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ - $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ - $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ - $(AM_CFLAGS) $(CFLAGS) -AM_V_CC = $(am__v_CC_@AM_V@) -am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) -am__v_CC_0 = @echo " CC " $@; -am__v_CC_1 = -CCLD = $(CC) -LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ - $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ - $(AM_LDFLAGS) $(LDFLAGS) -o $@ -AM_V_CCLD = $(am__v_CCLD_@AM_V@) -am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) -am__v_CCLD_0 = @echo " CCLD " $@; -am__v_CCLD_1 = -SOURCES = $(_gi_la_SOURCES) $(_gi_cairo_la_SOURCES) -DIST_SOURCES = $(_gi_la_SOURCES) $(_gi_cairo_la_SOURCES) -RECURSIVE_TARGETS = all-recursive check-recursive cscopelist-recursive \ - ctags-recursive dvi-recursive html-recursive info-recursive \ - install-data-recursive install-dvi-recursive \ - install-exec-recursive install-html-recursive \ - install-info-recursive install-pdf-recursive \ - install-ps-recursive install-recursive installcheck-recursive \ - installdirs-recursive pdf-recursive ps-recursive \ - tags-recursive uninstall-recursive -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) -am__pep3147_tweak = \ - sed -e 's|\.py$$||' -e 's|[^/]*$$|__pycache__/&.*.py|' -py_compile = $(top_srcdir)/py-compile -RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \ - distclean-recursive maintainer-clean-recursive -am__recursive_targets = \ - $(RECURSIVE_TARGETS) \ - $(RECURSIVE_CLEAN_TARGETS) \ - $(am__extra_recursive_targets) -AM_RECURSIVE_TARGETS = $(am__recursive_targets:-recursive=) TAGS CTAGS \ - distdir -am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) -# Read a list of newline-separated strings from the standard input, -# and print each of them once, without duplicates. Input order is -# *not* preserved. -am__uniquify_input = $(AWK) '\ - BEGIN { nonempty = 0; } \ - { items[$$0] = 1; nonempty = 1; } \ - END { if (nonempty) { for (i in items) print i; }; } \ -' -# Make sure the list of sources is unique. This is necessary because, -# e.g., the same source file might be shared among _SOURCES variables -# for different programs/libraries. -am__define_uniq_tagged_files = \ - list='$(am__tagged_files)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | $(am__uniquify_input)` -ETAGS = etags -CTAGS = ctags -DIST_SUBDIRS = $(SUBDIRS) -DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) -am__relativize = \ - dir0=`pwd`; \ - sed_first='s,^\([^/]*\)/.*$$,\1,'; \ - sed_rest='s,^[^/]*/*,,'; \ - sed_last='s,^.*/\([^/]*\)$$,\1,'; \ - sed_butlast='s,/*[^/]*$$,,'; \ - while test -n "$$dir1"; do \ - first=`echo "$$dir1" | sed -e "$$sed_first"`; \ - if test "$$first" != "."; then \ - if test "$$first" = ".."; then \ - dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \ - dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \ - else \ - first2=`echo "$$dir2" | sed -e "$$sed_first"`; \ - if test "$$first2" = "$$first"; then \ - dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \ - else \ - dir2="../$$dir2"; \ - fi; \ - dir0="$$dir0"/"$$first"; \ - fi; \ - fi; \ - dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \ - done; \ - reldir="$$dir2" -ACLOCAL = @ACLOCAL@ -ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@ -AMTAR = @AMTAR@ -AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ -AR = @AR@ -AS = @AS@ -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@ -DATADIR = @DATADIR@ -DEFS = @DEFS@ -DEPDIR = @DEPDIR@ -DLLTOOL = @DLLTOOL@ -DSYMUTIL = @DSYMUTIL@ -DUMPBIN = @DUMPBIN@ -ECHO_C = @ECHO_C@ -ECHO_N = @ECHO_N@ -ECHO_T = @ECHO_T@ -EGREP = @EGREP@ -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@ -GI_DATADIR = @GI_DATADIR@ -GI_LIBS = @GI_LIBS@ -GLIB_CFLAGS = @GLIB_CFLAGS@ -GLIB_COMPILE_RESOURCES = @GLIB_COMPILE_RESOURCES@ -GLIB_GENMARSHAL = @GLIB_GENMARSHAL@ -GLIB_LIBS = @GLIB_LIBS@ -GLIB_MKENUMS = @GLIB_MKENUMS@ -GOBJECT_QUERY = @GOBJECT_QUERY@ -GREP = @GREP@ -INSTALL = @INSTALL@ -INSTALL_DATA = @INSTALL_DATA@ -INSTALL_PROGRAM = @INSTALL_PROGRAM@ -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@ -LIBOBJS = @LIBOBJS@ -LIBS = @LIBS@ -LIBTOOL = @LIBTOOL@ -LIPO = @LIPO@ -LN_S = @LN_S@ -LTLIBOBJS = @LTLIBOBJS@ -MAKEINFO = @MAKEINFO@ -MANIFEST_TOOL = @MANIFEST_TOOL@ -MKDIR_P = @MKDIR_P@ -NM = @NM@ -NMEDIT = @NMEDIT@ -OBJDUMP = @OBJDUMP@ -OBJEXT = @OBJEXT@ -OTOOL = @OTOOL@ -OTOOL64 = @OTOOL64@ -PACKAGE = @PACKAGE@ -PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ -PACKAGE_NAME = @PACKAGE_NAME@ -PACKAGE_STRING = @PACKAGE_STRING@ -PACKAGE_TARNAME = @PACKAGE_TARNAME@ -PACKAGE_URL = @PACKAGE_URL@ -PACKAGE_VERSION = @PACKAGE_VERSION@ -PATH_SEPARATOR = @PATH_SEPARATOR@ -PKG_CONFIG = @PKG_CONFIG@ -PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ -PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ -PLATFORM = @PLATFORM@ -PYCAIRO_CFLAGS = @PYCAIRO_CFLAGS@ -PYCAIRO_LIBS = @PYCAIRO_LIBS@ -PYGOBJECT_MAJOR_VERSION = @PYGOBJECT_MAJOR_VERSION@ -PYGOBJECT_MICRO_VERSION = @PYGOBJECT_MICRO_VERSION@ -PYGOBJECT_MINOR_VERSION = @PYGOBJECT_MINOR_VERSION@ -PYTHON = @PYTHON@ -PYTHON_BASENAME = @PYTHON_BASENAME@ -PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ -PYTHON_INCLUDES = @PYTHON_INCLUDES@ -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@ -SET_MAKE = @SET_MAKE@ -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@ -abs_top_srcdir = @abs_top_srcdir@ -ac_ct_AR = @ac_ct_AR@ -ac_ct_CC = @ac_ct_CC@ -ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ -am__include = @am__include@ -am__leading_dot = @am__leading_dot@ -am__quote = @am__quote@ -am__tar = @am__tar@ -am__untar = @am__untar@ -bindir = @bindir@ -build = @build@ -build_alias = @build_alias@ -build_cpu = @build_cpu@ -build_os = @build_os@ -build_vendor = @build_vendor@ -builddir = @builddir@ -datadir = @datadir@ -datarootdir = @datarootdir@ -docdir = @docdir@ -dvidir = @dvidir@ -exec_prefix = @exec_prefix@ -host = @host@ -host_alias = @host_alias@ -host_cpu = @host_cpu@ -host_os = @host_os@ -host_vendor = @host_vendor@ -htmldir = @htmldir@ -includedir = @includedir@ -infodir = @infodir@ -install_sh = @install_sh@ -libdir = @libdir@ -libexecdir = @libexecdir@ -localedir = @localedir@ -localstatedir = @localstatedir@ -mandir = @mandir@ -mkdir_p = @mkdir_p@ -oldincludedir = @oldincludedir@ -pdfdir = @pdfdir@ -pkgpyexecdir = @pkgpyexecdir@ -pkgpythondir = @pkgpythondir@ -prefix = @prefix@ -program_transform_name = @program_transform_name@ -psdir = @psdir@ -pyexecdir = @pyexecdir@ -pythondir = @pythondir@ -sbindir = @sbindir@ -sharedstatedir = @sharedstatedir@ -srcdir = @srcdir@ -sysconfdir = @sysconfdir@ -target_alias = @target_alias@ -top_build_prefix = @top_build_prefix@ -top_builddir = @top_builddir@ -top_srcdir = @top_srcdir@ -SUBDIRS = \ - repository \ - overrides \ - _glib \ - _gobject - -extension_cppflags = \ - $(PYTHON_INCLUDES) \ - -DPY_SSIZE_T_CLEAN - -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 -# called .pyd for Python to load it as an extension module. -@OS_WIN32_TRUE@extension_libadd = \ -@OS_WIN32_TRUE@ $(PYTHON_LIBS) - -pygidir = $(pyexecdir)/gi -pygi_PYTHON = \ - __init__.py \ - types.py \ - module.py \ - importer.py \ - pygtkcompat.py \ - docstring.py - -pygi_LTLIBRARIES = _gi.la $(am__append_2) -_gi_la_SOURCES = \ - pygi-repository.c \ - pygi-repository.h \ - pygi-info.c \ - pygi-info.h \ - pygi-foreign.c \ - pygi-foreign.h \ - pygi-struct.c \ - pygi-struct.h \ - pygi-source.c \ - pygi-source.h \ - pygi-argument.c \ - pygi-argument.h \ - pygi-type.c \ - pygi-type.h \ - pygi-boxed.c \ - pygi-boxed.h \ - pygi-closure.c \ - pygi-closure.h \ - pygi-ccallback.c \ - pygi-ccallback.h \ - pygi.h \ - pygi-private.h \ - pygi-property.c \ - pygi-property.h \ - pygi-signal-closure.c \ - pygi-signal-closure.h \ - pygobject-external.h \ - gimodule.c \ - pygi-invoke.c \ - pygi-invoke.h \ - pygi-invoke-state-struct.h \ - pygi-cache.h \ - pygi-cache.c \ - pygi-marshal-from-py.c \ - pygi-marshal-from-py.h \ - pygi-marshal-to-py.c \ - pygi-marshal-to-py.h \ - pygi-marshal-cleanup.c \ - pygi-marshal-cleanup.h - -_gi_la_CFLAGS = \ - $(GI_CFLAGS) - -_gi_la_CPPFLAGS = \ - $(extension_cppflags) \ - -I$(top_srcdir)/gi/_glib \ - -I$(top_srcdir)/gi/_gobject - -_gi_la_LIBADD = \ - $(extension_libadd) \ - $(GI_LIBS) \ - $(top_builddir)/gi/_glib/libpyglib-gi-2.0-@PYTHON_BASENAME@.la - -_gi_la_LDFLAGS = \ - $(extension_ldflags) \ - -export-symbols-regex "init_gi|PyInit__gi" - -_gi_cairo_la_SOURCES = \ - pygi-foreign-cairo.c - -_gi_cairo_la_CFLAGS = \ - $(GI_CFLAGS) \ - $(PYCAIRO_CFLAGS) - -_gi_cairo_la_CPPFLAGS = \ - $(extension_cppflags) \ - -I$(top_srcdir)/gi/_glib \ - -I$(top_srcdir)/gi/_gobject - -_gi_cairo_la_LIBADD = \ - $(extension_libadd) \ - $(GI_LIBS) \ - $(PYCAIRO_LIBS) - -_gi_cairo_la_LDFLAGS = \ - $(extension_ldflags) \ - -export-symbols-regex "init_gi_cairo|PyInit__gi_cairo" - -all: all-recursive - -.SUFFIXES: -.SUFFIXES: .c .lo .o .obj -$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) - @for dep in $?; do \ - case '$(am__configure_deps)' in \ - *$$dep*) \ - ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ - && { if test -f $@; then exit 0; else break; fi; }; \ - exit 1;; \ - esac; \ - done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign gi/Makefile'; \ - $(am__cd) $(top_srcdir) && \ - $(AUTOMAKE) --foreign gi/Makefile -.PRECIOUS: Makefile -Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status - @case '$?' in \ - *config.status*) \ - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ - *) \ - echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ - cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ - esac; - -$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh - -$(top_srcdir)/configure: $(am__configure_deps) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh -$(ACLOCAL_M4): $(am__aclocal_m4_deps) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh -$(am__aclocal_m4_deps): - -install-pygiLTLIBRARIES: $(pygi_LTLIBRARIES) - @$(NORMAL_INSTALL) - @list='$(pygi_LTLIBRARIES)'; test -n "$(pygidir)" || list=; \ - list2=; for p in $$list; do \ - if test -f $$p; then \ - list2="$$list2 $$p"; \ - else :; fi; \ - done; \ - test -z "$$list2" || { \ - echo " $(MKDIR_P) '$(DESTDIR)$(pygidir)'"; \ - $(MKDIR_P) "$(DESTDIR)$(pygidir)" || exit 1; \ - echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(pygidir)'"; \ - $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(pygidir)"; \ - } - -uninstall-pygiLTLIBRARIES: - @$(NORMAL_UNINSTALL) - @list='$(pygi_LTLIBRARIES)'; test -n "$(pygidir)" || list=; \ - for p in $$list; do \ - $(am__strip_dir) \ - echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(pygidir)/$$f'"; \ - $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(pygidir)/$$f"; \ - done - -clean-pygiLTLIBRARIES: - -test -z "$(pygi_LTLIBRARIES)" || rm -f $(pygi_LTLIBRARIES) - @list='$(pygi_LTLIBRARIES)'; \ - locs=`for p in $$list; do echo $$p; done | \ - sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ - sort -u`; \ - test -z "$$locs" || { \ - echo rm -f $${locs}; \ - rm -f $${locs}; \ - } - -_gi.la: $(_gi_la_OBJECTS) $(_gi_la_DEPENDENCIES) $(EXTRA__gi_la_DEPENDENCIES) - $(AM_V_CCLD)$(_gi_la_LINK) -rpath $(pygidir) $(_gi_la_OBJECTS) $(_gi_la_LIBADD) $(LIBS) - -_gi_cairo.la: $(_gi_cairo_la_OBJECTS) $(_gi_cairo_la_DEPENDENCIES) $(EXTRA__gi_cairo_la_DEPENDENCIES) - $(AM_V_CCLD)$(_gi_cairo_la_LINK) $(am__gi_cairo_la_rpath) $(_gi_cairo_la_OBJECTS) $(_gi_cairo_la_LIBADD) $(LIBS) - -mostlyclean-compile: - -rm -f *.$(OBJEXT) - -distclean-compile: - -rm -f *.tab.c - -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/_gi_cairo_la-pygi-foreign-cairo.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/_gi_la-gimodule.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/_gi_la-pygi-argument.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/_gi_la-pygi-boxed.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/_gi_la-pygi-cache.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/_gi_la-pygi-ccallback.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/_gi_la-pygi-closure.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/_gi_la-pygi-foreign.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/_gi_la-pygi-info.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/_gi_la-pygi-invoke.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/_gi_la-pygi-marshal-cleanup.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/_gi_la-pygi-marshal-from-py.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/_gi_la-pygi-marshal-to-py.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/_gi_la-pygi-property.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/_gi_la-pygi-repository.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/_gi_la-pygi-signal-closure.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/_gi_la-pygi-source.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/_gi_la-pygi-struct.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/_gi_la-pygi-type.Plo@am__quote@ - -.c.o: -@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $< - -.c.obj: -@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'` - -.c.lo: -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< - -_gi_la-pygi-repository.lo: pygi-repository.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(_gi_la_CPPFLAGS) $(CPPFLAGS) $(_gi_la_CFLAGS) $(CFLAGS) -MT _gi_la-pygi-repository.lo -MD -MP -MF $(DEPDIR)/_gi_la-pygi-repository.Tpo -c -o _gi_la-pygi-repository.lo `test -f 'pygi-repository.c' || echo '$(srcdir)/'`pygi-repository.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/_gi_la-pygi-repository.Tpo $(DEPDIR)/_gi_la-pygi-repository.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pygi-repository.c' object='_gi_la-pygi-repository.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(_gi_la_CPPFLAGS) $(CPPFLAGS) $(_gi_la_CFLAGS) $(CFLAGS) -c -o _gi_la-pygi-repository.lo `test -f 'pygi-repository.c' || echo '$(srcdir)/'`pygi-repository.c - -_gi_la-pygi-info.lo: pygi-info.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(_gi_la_CPPFLAGS) $(CPPFLAGS) $(_gi_la_CFLAGS) $(CFLAGS) -MT _gi_la-pygi-info.lo -MD -MP -MF $(DEPDIR)/_gi_la-pygi-info.Tpo -c -o _gi_la-pygi-info.lo `test -f 'pygi-info.c' || echo '$(srcdir)/'`pygi-info.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/_gi_la-pygi-info.Tpo $(DEPDIR)/_gi_la-pygi-info.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pygi-info.c' object='_gi_la-pygi-info.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(_gi_la_CPPFLAGS) $(CPPFLAGS) $(_gi_la_CFLAGS) $(CFLAGS) -c -o _gi_la-pygi-info.lo `test -f 'pygi-info.c' || echo '$(srcdir)/'`pygi-info.c - -_gi_la-pygi-foreign.lo: pygi-foreign.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(_gi_la_CPPFLAGS) $(CPPFLAGS) $(_gi_la_CFLAGS) $(CFLAGS) -MT _gi_la-pygi-foreign.lo -MD -MP -MF $(DEPDIR)/_gi_la-pygi-foreign.Tpo -c -o _gi_la-pygi-foreign.lo `test -f 'pygi-foreign.c' || echo '$(srcdir)/'`pygi-foreign.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/_gi_la-pygi-foreign.Tpo $(DEPDIR)/_gi_la-pygi-foreign.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pygi-foreign.c' object='_gi_la-pygi-foreign.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(_gi_la_CPPFLAGS) $(CPPFLAGS) $(_gi_la_CFLAGS) $(CFLAGS) -c -o _gi_la-pygi-foreign.lo `test -f 'pygi-foreign.c' || echo '$(srcdir)/'`pygi-foreign.c - -_gi_la-pygi-struct.lo: pygi-struct.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(_gi_la_CPPFLAGS) $(CPPFLAGS) $(_gi_la_CFLAGS) $(CFLAGS) -MT _gi_la-pygi-struct.lo -MD -MP -MF $(DEPDIR)/_gi_la-pygi-struct.Tpo -c -o _gi_la-pygi-struct.lo `test -f 'pygi-struct.c' || echo '$(srcdir)/'`pygi-struct.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/_gi_la-pygi-struct.Tpo $(DEPDIR)/_gi_la-pygi-struct.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pygi-struct.c' object='_gi_la-pygi-struct.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(_gi_la_CPPFLAGS) $(CPPFLAGS) $(_gi_la_CFLAGS) $(CFLAGS) -c -o _gi_la-pygi-struct.lo `test -f 'pygi-struct.c' || echo '$(srcdir)/'`pygi-struct.c - -_gi_la-pygi-source.lo: pygi-source.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(_gi_la_CPPFLAGS) $(CPPFLAGS) $(_gi_la_CFLAGS) $(CFLAGS) -MT _gi_la-pygi-source.lo -MD -MP -MF $(DEPDIR)/_gi_la-pygi-source.Tpo -c -o _gi_la-pygi-source.lo `test -f 'pygi-source.c' || echo '$(srcdir)/'`pygi-source.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/_gi_la-pygi-source.Tpo $(DEPDIR)/_gi_la-pygi-source.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pygi-source.c' object='_gi_la-pygi-source.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(_gi_la_CPPFLAGS) $(CPPFLAGS) $(_gi_la_CFLAGS) $(CFLAGS) -c -o _gi_la-pygi-source.lo `test -f 'pygi-source.c' || echo '$(srcdir)/'`pygi-source.c - -_gi_la-pygi-argument.lo: pygi-argument.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(_gi_la_CPPFLAGS) $(CPPFLAGS) $(_gi_la_CFLAGS) $(CFLAGS) -MT _gi_la-pygi-argument.lo -MD -MP -MF $(DEPDIR)/_gi_la-pygi-argument.Tpo -c -o _gi_la-pygi-argument.lo `test -f 'pygi-argument.c' || echo '$(srcdir)/'`pygi-argument.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/_gi_la-pygi-argument.Tpo $(DEPDIR)/_gi_la-pygi-argument.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pygi-argument.c' object='_gi_la-pygi-argument.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(_gi_la_CPPFLAGS) $(CPPFLAGS) $(_gi_la_CFLAGS) $(CFLAGS) -c -o _gi_la-pygi-argument.lo `test -f 'pygi-argument.c' || echo '$(srcdir)/'`pygi-argument.c - -_gi_la-pygi-type.lo: pygi-type.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(_gi_la_CPPFLAGS) $(CPPFLAGS) $(_gi_la_CFLAGS) $(CFLAGS) -MT _gi_la-pygi-type.lo -MD -MP -MF $(DEPDIR)/_gi_la-pygi-type.Tpo -c -o _gi_la-pygi-type.lo `test -f 'pygi-type.c' || echo '$(srcdir)/'`pygi-type.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/_gi_la-pygi-type.Tpo $(DEPDIR)/_gi_la-pygi-type.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pygi-type.c' object='_gi_la-pygi-type.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(_gi_la_CPPFLAGS) $(CPPFLAGS) $(_gi_la_CFLAGS) $(CFLAGS) -c -o _gi_la-pygi-type.lo `test -f 'pygi-type.c' || echo '$(srcdir)/'`pygi-type.c - -_gi_la-pygi-boxed.lo: pygi-boxed.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(_gi_la_CPPFLAGS) $(CPPFLAGS) $(_gi_la_CFLAGS) $(CFLAGS) -MT _gi_la-pygi-boxed.lo -MD -MP -MF $(DEPDIR)/_gi_la-pygi-boxed.Tpo -c -o _gi_la-pygi-boxed.lo `test -f 'pygi-boxed.c' || echo '$(srcdir)/'`pygi-boxed.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/_gi_la-pygi-boxed.Tpo $(DEPDIR)/_gi_la-pygi-boxed.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pygi-boxed.c' object='_gi_la-pygi-boxed.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(_gi_la_CPPFLAGS) $(CPPFLAGS) $(_gi_la_CFLAGS) $(CFLAGS) -c -o _gi_la-pygi-boxed.lo `test -f 'pygi-boxed.c' || echo '$(srcdir)/'`pygi-boxed.c - -_gi_la-pygi-closure.lo: pygi-closure.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(_gi_la_CPPFLAGS) $(CPPFLAGS) $(_gi_la_CFLAGS) $(CFLAGS) -MT _gi_la-pygi-closure.lo -MD -MP -MF $(DEPDIR)/_gi_la-pygi-closure.Tpo -c -o _gi_la-pygi-closure.lo `test -f 'pygi-closure.c' || echo '$(srcdir)/'`pygi-closure.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/_gi_la-pygi-closure.Tpo $(DEPDIR)/_gi_la-pygi-closure.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pygi-closure.c' object='_gi_la-pygi-closure.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(_gi_la_CPPFLAGS) $(CPPFLAGS) $(_gi_la_CFLAGS) $(CFLAGS) -c -o _gi_la-pygi-closure.lo `test -f 'pygi-closure.c' || echo '$(srcdir)/'`pygi-closure.c - -_gi_la-pygi-ccallback.lo: pygi-ccallback.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(_gi_la_CPPFLAGS) $(CPPFLAGS) $(_gi_la_CFLAGS) $(CFLAGS) -MT _gi_la-pygi-ccallback.lo -MD -MP -MF $(DEPDIR)/_gi_la-pygi-ccallback.Tpo -c -o _gi_la-pygi-ccallback.lo `test -f 'pygi-ccallback.c' || echo '$(srcdir)/'`pygi-ccallback.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/_gi_la-pygi-ccallback.Tpo $(DEPDIR)/_gi_la-pygi-ccallback.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pygi-ccallback.c' object='_gi_la-pygi-ccallback.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(_gi_la_CPPFLAGS) $(CPPFLAGS) $(_gi_la_CFLAGS) $(CFLAGS) -c -o _gi_la-pygi-ccallback.lo `test -f 'pygi-ccallback.c' || echo '$(srcdir)/'`pygi-ccallback.c - -_gi_la-pygi-property.lo: pygi-property.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(_gi_la_CPPFLAGS) $(CPPFLAGS) $(_gi_la_CFLAGS) $(CFLAGS) -MT _gi_la-pygi-property.lo -MD -MP -MF $(DEPDIR)/_gi_la-pygi-property.Tpo -c -o _gi_la-pygi-property.lo `test -f 'pygi-property.c' || echo '$(srcdir)/'`pygi-property.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/_gi_la-pygi-property.Tpo $(DEPDIR)/_gi_la-pygi-property.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pygi-property.c' object='_gi_la-pygi-property.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(_gi_la_CPPFLAGS) $(CPPFLAGS) $(_gi_la_CFLAGS) $(CFLAGS) -c -o _gi_la-pygi-property.lo `test -f 'pygi-property.c' || echo '$(srcdir)/'`pygi-property.c - -_gi_la-pygi-signal-closure.lo: pygi-signal-closure.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(_gi_la_CPPFLAGS) $(CPPFLAGS) $(_gi_la_CFLAGS) $(CFLAGS) -MT _gi_la-pygi-signal-closure.lo -MD -MP -MF $(DEPDIR)/_gi_la-pygi-signal-closure.Tpo -c -o _gi_la-pygi-signal-closure.lo `test -f 'pygi-signal-closure.c' || echo '$(srcdir)/'`pygi-signal-closure.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/_gi_la-pygi-signal-closure.Tpo $(DEPDIR)/_gi_la-pygi-signal-closure.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pygi-signal-closure.c' object='_gi_la-pygi-signal-closure.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(_gi_la_CPPFLAGS) $(CPPFLAGS) $(_gi_la_CFLAGS) $(CFLAGS) -c -o _gi_la-pygi-signal-closure.lo `test -f 'pygi-signal-closure.c' || echo '$(srcdir)/'`pygi-signal-closure.c - -_gi_la-gimodule.lo: gimodule.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(_gi_la_CPPFLAGS) $(CPPFLAGS) $(_gi_la_CFLAGS) $(CFLAGS) -MT _gi_la-gimodule.lo -MD -MP -MF $(DEPDIR)/_gi_la-gimodule.Tpo -c -o _gi_la-gimodule.lo `test -f 'gimodule.c' || echo '$(srcdir)/'`gimodule.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/_gi_la-gimodule.Tpo $(DEPDIR)/_gi_la-gimodule.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gimodule.c' object='_gi_la-gimodule.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(_gi_la_CPPFLAGS) $(CPPFLAGS) $(_gi_la_CFLAGS) $(CFLAGS) -c -o _gi_la-gimodule.lo `test -f 'gimodule.c' || echo '$(srcdir)/'`gimodule.c - -_gi_la-pygi-invoke.lo: pygi-invoke.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(_gi_la_CPPFLAGS) $(CPPFLAGS) $(_gi_la_CFLAGS) $(CFLAGS) -MT _gi_la-pygi-invoke.lo -MD -MP -MF $(DEPDIR)/_gi_la-pygi-invoke.Tpo -c -o _gi_la-pygi-invoke.lo `test -f 'pygi-invoke.c' || echo '$(srcdir)/'`pygi-invoke.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/_gi_la-pygi-invoke.Tpo $(DEPDIR)/_gi_la-pygi-invoke.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pygi-invoke.c' object='_gi_la-pygi-invoke.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(_gi_la_CPPFLAGS) $(CPPFLAGS) $(_gi_la_CFLAGS) $(CFLAGS) -c -o _gi_la-pygi-invoke.lo `test -f 'pygi-invoke.c' || echo '$(srcdir)/'`pygi-invoke.c - -_gi_la-pygi-cache.lo: pygi-cache.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(_gi_la_CPPFLAGS) $(CPPFLAGS) $(_gi_la_CFLAGS) $(CFLAGS) -MT _gi_la-pygi-cache.lo -MD -MP -MF $(DEPDIR)/_gi_la-pygi-cache.Tpo -c -o _gi_la-pygi-cache.lo `test -f 'pygi-cache.c' || echo '$(srcdir)/'`pygi-cache.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/_gi_la-pygi-cache.Tpo $(DEPDIR)/_gi_la-pygi-cache.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pygi-cache.c' object='_gi_la-pygi-cache.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(_gi_la_CPPFLAGS) $(CPPFLAGS) $(_gi_la_CFLAGS) $(CFLAGS) -c -o _gi_la-pygi-cache.lo `test -f 'pygi-cache.c' || echo '$(srcdir)/'`pygi-cache.c - -_gi_la-pygi-marshal-from-py.lo: pygi-marshal-from-py.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(_gi_la_CPPFLAGS) $(CPPFLAGS) $(_gi_la_CFLAGS) $(CFLAGS) -MT _gi_la-pygi-marshal-from-py.lo -MD -MP -MF $(DEPDIR)/_gi_la-pygi-marshal-from-py.Tpo -c -o _gi_la-pygi-marshal-from-py.lo `test -f 'pygi-marshal-from-py.c' || echo '$(srcdir)/'`pygi-marshal-from-py.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/_gi_la-pygi-marshal-from-py.Tpo $(DEPDIR)/_gi_la-pygi-marshal-from-py.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pygi-marshal-from-py.c' object='_gi_la-pygi-marshal-from-py.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(_gi_la_CPPFLAGS) $(CPPFLAGS) $(_gi_la_CFLAGS) $(CFLAGS) -c -o _gi_la-pygi-marshal-from-py.lo `test -f 'pygi-marshal-from-py.c' || echo '$(srcdir)/'`pygi-marshal-from-py.c - -_gi_la-pygi-marshal-to-py.lo: pygi-marshal-to-py.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(_gi_la_CPPFLAGS) $(CPPFLAGS) $(_gi_la_CFLAGS) $(CFLAGS) -MT _gi_la-pygi-marshal-to-py.lo -MD -MP -MF $(DEPDIR)/_gi_la-pygi-marshal-to-py.Tpo -c -o _gi_la-pygi-marshal-to-py.lo `test -f 'pygi-marshal-to-py.c' || echo '$(srcdir)/'`pygi-marshal-to-py.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/_gi_la-pygi-marshal-to-py.Tpo $(DEPDIR)/_gi_la-pygi-marshal-to-py.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pygi-marshal-to-py.c' object='_gi_la-pygi-marshal-to-py.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(_gi_la_CPPFLAGS) $(CPPFLAGS) $(_gi_la_CFLAGS) $(CFLAGS) -c -o _gi_la-pygi-marshal-to-py.lo `test -f 'pygi-marshal-to-py.c' || echo '$(srcdir)/'`pygi-marshal-to-py.c - -_gi_la-pygi-marshal-cleanup.lo: pygi-marshal-cleanup.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(_gi_la_CPPFLAGS) $(CPPFLAGS) $(_gi_la_CFLAGS) $(CFLAGS) -MT _gi_la-pygi-marshal-cleanup.lo -MD -MP -MF $(DEPDIR)/_gi_la-pygi-marshal-cleanup.Tpo -c -o _gi_la-pygi-marshal-cleanup.lo `test -f 'pygi-marshal-cleanup.c' || echo '$(srcdir)/'`pygi-marshal-cleanup.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/_gi_la-pygi-marshal-cleanup.Tpo $(DEPDIR)/_gi_la-pygi-marshal-cleanup.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pygi-marshal-cleanup.c' object='_gi_la-pygi-marshal-cleanup.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(_gi_la_CPPFLAGS) $(CPPFLAGS) $(_gi_la_CFLAGS) $(CFLAGS) -c -o _gi_la-pygi-marshal-cleanup.lo `test -f 'pygi-marshal-cleanup.c' || echo '$(srcdir)/'`pygi-marshal-cleanup.c - -_gi_cairo_la-pygi-foreign-cairo.lo: pygi-foreign-cairo.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(_gi_cairo_la_CPPFLAGS) $(CPPFLAGS) $(_gi_cairo_la_CFLAGS) $(CFLAGS) -MT _gi_cairo_la-pygi-foreign-cairo.lo -MD -MP -MF $(DEPDIR)/_gi_cairo_la-pygi-foreign-cairo.Tpo -c -o _gi_cairo_la-pygi-foreign-cairo.lo `test -f 'pygi-foreign-cairo.c' || echo '$(srcdir)/'`pygi-foreign-cairo.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/_gi_cairo_la-pygi-foreign-cairo.Tpo $(DEPDIR)/_gi_cairo_la-pygi-foreign-cairo.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pygi-foreign-cairo.c' object='_gi_cairo_la-pygi-foreign-cairo.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(_gi_cairo_la_CPPFLAGS) $(CPPFLAGS) $(_gi_cairo_la_CFLAGS) $(CFLAGS) -c -o _gi_cairo_la-pygi-foreign-cairo.lo `test -f 'pygi-foreign-cairo.c' || echo '$(srcdir)/'`pygi-foreign-cairo.c - -mostlyclean-libtool: - -rm -f *.lo - -clean-libtool: - -rm -rf .libs _libs -install-pygiPYTHON: $(pygi_PYTHON) - @$(NORMAL_INSTALL) - @list='$(pygi_PYTHON)'; dlist=; list2=; test -n "$(pygidir)" || list=; \ - if test -n "$$list"; then \ - echo " $(MKDIR_P) '$(DESTDIR)$(pygidir)'"; \ - $(MKDIR_P) "$(DESTDIR)$(pygidir)" || exit 1; \ - fi; \ - for p in $$list; do \ - if test -f "$$p"; then b=; else b="$(srcdir)/"; fi; \ - if test -f $$b$$p; then \ - $(am__strip_dir) \ - dlist="$$dlist $$f"; \ - list2="$$list2 $$b$$p"; \ - else :; fi; \ - done; \ - for file in $$list2; do echo $$file; done | $(am__base_list) | \ - while read files; do \ - echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pygidir)'"; \ - $(INSTALL_DATA) $$files "$(DESTDIR)$(pygidir)" || exit $$?; \ - done || exit $$?; \ - if test -n "$$dlist"; then \ - $(am__py_compile) --destdir "$(DESTDIR)" \ - --basedir "$(pygidir)" $$dlist; \ - else :; fi - -uninstall-pygiPYTHON: - @$(NORMAL_UNINSTALL) - @list='$(pygi_PYTHON)'; test -n "$(pygidir)" || list=; \ - py_files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ - test -n "$$py_files" || exit 0; \ - dir='$(DESTDIR)$(pygidir)'; \ - pyc_files=`echo "$$py_files" | sed 's|$$|c|'`; \ - pyo_files=`echo "$$py_files" | sed 's|$$|o|'`; \ - py_files_pep3147=`echo "$$py_files" | $(am__pep3147_tweak)`; \ - echo "$$py_files_pep3147";\ - pyc_files_pep3147=`echo "$$py_files_pep3147" | sed 's|$$|c|'`; \ - pyo_files_pep3147=`echo "$$py_files_pep3147" | sed 's|$$|o|'`; \ - st=0; \ - for files in \ - "$$py_files" \ - "$$pyc_files" \ - "$$pyo_files" \ - "$$pyc_files_pep3147" \ - "$$pyo_files_pep3147" \ - ; do \ - $(am__uninstall_files_from_dir) || st=$$?; \ - done; \ - exit $$st - -# This directory's subdirectories are mostly independent; you can cd -# into them and run 'make' without going through this Makefile. -# To change the values of 'make' variables: instead of editing Makefiles, -# (1) if the variable is set in 'config.status', edit 'config.status' -# (which will cause the Makefiles to be regenerated when you run 'make'); -# (2) otherwise, pass the desired values on the 'make' command line. -$(am__recursive_targets): - @fail=; \ - if $(am__make_keepgoing); then \ - failcom='fail=yes'; \ - else \ - failcom='exit 1'; \ - fi; \ - dot_seen=no; \ - target=`echo $@ | sed s/-recursive//`; \ - case "$@" in \ - distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \ - *) list='$(SUBDIRS)' ;; \ - esac; \ - for subdir in $$list; do \ - echo "Making $$target in $$subdir"; \ - if test "$$subdir" = "."; then \ - dot_seen=yes; \ - local_target="$$target-am"; \ - else \ - local_target="$$target"; \ - fi; \ - ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \ - || eval $$failcom; \ - done; \ - if test "$$dot_seen" = "no"; then \ - $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \ - fi; test -z "$$fail" - -ID: $(am__tagged_files) - $(am__define_uniq_tagged_files); mkid -fID $$unique -tags: tags-recursive -TAGS: tags - -tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) - set x; \ - here=`pwd`; \ - if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \ - include_option=--etags-include; \ - empty_fix=.; \ - else \ - include_option=--include; \ - empty_fix=; \ - fi; \ - list='$(SUBDIRS)'; for subdir in $$list; do \ - if test "$$subdir" = .; then :; else \ - test ! -f $$subdir/TAGS || \ - set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \ - fi; \ - done; \ - $(am__define_uniq_tagged_files); \ - shift; \ - if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ - test -n "$$unique" || unique=$$empty_fix; \ - if test $$# -gt 0; then \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - "$$@" $$unique; \ - else \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - $$unique; \ - fi; \ - fi -ctags: ctags-recursive - -CTAGS: ctags -ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) - $(am__define_uniq_tagged_files); \ - test -z "$(CTAGS_ARGS)$$unique" \ - || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ - $$unique - -GTAGS: - here=`$(am__cd) $(top_builddir) && pwd` \ - && $(am__cd) $(top_srcdir) \ - && gtags -i $(GTAGS_ARGS) "$$here" -cscopelist: cscopelist-recursive - -cscopelist-am: $(am__tagged_files) - list='$(am__tagged_files)'; \ - case "$(srcdir)" in \ - [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ - *) sdir=$(subdir)/$(srcdir) ;; \ - esac; \ - for i in $$list; do \ - if test -f "$$i"; then \ - echo "$(subdir)/$$i"; \ - else \ - echo "$$sdir/$$i"; \ - fi; \ - done >> $(top_builddir)/cscope.files - -distclean-tags: - -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags - -distdir: $(DISTFILES) - @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - list='$(DISTFILES)'; \ - dist_files=`for file in $$list; do echo $$file; done | \ - sed -e "s|^$$srcdirstrip/||;t" \ - -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ - case $$dist_files in \ - */*) $(MKDIR_P) `echo "$$dist_files" | \ - sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ - sort -u` ;; \ - esac; \ - for file in $$dist_files; do \ - if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ - if test -d $$d/$$file; then \ - dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ - if test -d "$(distdir)/$$file"; then \ - find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ - fi; \ - if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ - cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ - find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ - fi; \ - cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ - else \ - test -f "$(distdir)/$$file" \ - || cp -p $$d/$$file "$(distdir)/$$file" \ - || exit 1; \ - fi; \ - done - @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \ - if test "$$subdir" = .; then :; else \ - $(am__make_dryrun) \ - || test -d "$(distdir)/$$subdir" \ - || $(MKDIR_P) "$(distdir)/$$subdir" \ - || exit 1; \ - dir1=$$subdir; dir2="$(distdir)/$$subdir"; \ - $(am__relativize); \ - new_distdir=$$reldir; \ - dir1=$$subdir; dir2="$(top_distdir)"; \ - $(am__relativize); \ - new_top_distdir=$$reldir; \ - echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \ - echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \ - ($(am__cd) $$subdir && \ - $(MAKE) $(AM_MAKEFLAGS) \ - top_distdir="$$new_top_distdir" \ - distdir="$$new_distdir" \ - am__remove_distdir=: \ - am__skip_length_check=: \ - am__skip_mode_fix=: \ - distdir) \ - || exit 1; \ - fi; \ - done -check-am: all-am - $(MAKE) $(AM_MAKEFLAGS) check-local -check: check-recursive -all-am: Makefile $(LTLIBRARIES) all-local -installdirs: installdirs-recursive -installdirs-am: - for dir in "$(DESTDIR)$(pygidir)" "$(DESTDIR)$(pygidir)"; do \ - test -z "$$dir" || $(MKDIR_P) "$$dir"; \ - done -install: install-recursive -install-exec: install-exec-recursive -install-data: install-data-recursive -uninstall: uninstall-recursive - -install-am: all-am - @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am - -installcheck: installcheck-recursive -install-strip: - if test -z '$(STRIP)'; then \ - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ - install; \ - else \ - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ - "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ - fi -mostlyclean-generic: - -clean-generic: - -distclean-generic: - -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) - -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) - -maintainer-clean-generic: - @echo "This command is intended for maintainers to use" - @echo "it deletes files that may require special tools to rebuild." -clean: clean-recursive - -clean-am: clean-generic clean-libtool clean-local \ - clean-pygiLTLIBRARIES mostlyclean-am - -distclean: distclean-recursive - -rm -rf ./$(DEPDIR) - -rm -f Makefile -distclean-am: clean-am distclean-compile distclean-generic \ - distclean-tags - -dvi: dvi-recursive - -dvi-am: - -html: html-recursive - -html-am: - -info: info-recursive - -info-am: - -install-data-am: install-pygiLTLIBRARIES install-pygiPYTHON - -install-dvi: install-dvi-recursive - -install-dvi-am: - -install-exec-am: - -install-html: install-html-recursive - -install-html-am: - -install-info: install-info-recursive - -install-info-am: - -install-man: - -install-pdf: install-pdf-recursive - -install-pdf-am: - -install-ps: install-ps-recursive - -install-ps-am: - -installcheck-am: - -maintainer-clean: maintainer-clean-recursive - -rm -rf ./$(DEPDIR) - -rm -f Makefile -maintainer-clean-am: distclean-am maintainer-clean-generic - -mostlyclean: mostlyclean-recursive - -mostlyclean-am: mostlyclean-compile mostlyclean-generic \ - mostlyclean-libtool - -pdf: pdf-recursive - -pdf-am: - -ps: ps-recursive - -ps-am: - -uninstall-am: uninstall-pygiLTLIBRARIES uninstall-pygiPYTHON - -.MAKE: $(am__recursive_targets) check-am install-am install-strip - -.PHONY: $(am__recursive_targets) CTAGS GTAGS TAGS all all-am all-local \ - check check-am check-local clean clean-generic clean-libtool \ - clean-local clean-pygiLTLIBRARIES cscopelist-am ctags ctags-am \ - distclean distclean-compile distclean-generic \ - distclean-libtool distclean-tags distdir dvi dvi-am html \ - html-am info info-am install install-am install-data \ - install-data-am install-dvi install-dvi-am install-exec \ - install-exec-am install-html install-html-am install-info \ - install-info-am install-man install-pdf install-pdf-am \ - install-ps install-ps-am install-pygiLTLIBRARIES \ - install-pygiPYTHON install-strip installcheck installcheck-am \ - installdirs installdirs-am maintainer-clean \ - maintainer-clean-generic mostlyclean mostlyclean-compile \ - mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ - tags tags-am uninstall uninstall-am uninstall-pygiLTLIBRARIES \ - uninstall-pygiPYTHON - - -# This is to ensure we have a symlink to the .so in the -# build directory, which the Python interpreter can load -# directly without having to know how to parse .la files. -%$(PYTHON_SO): %.la - $(LN_S) -f .libs/$@ $@ - -# 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 $(pygi_PYTHON); do \ - [ -e $(builddir)/$$f ] || $(LN_S) $(srcdir)/$$f $(builddir)/$$f; \ - done - -all-local: $(LTLIBRARIES:.la=$(PYTHON_SO)) build_pylinks - -check-local: $(LTLIBRARIES:.la=$(PYTHON_SO)) build_pylinks -clean-local: - rm -f $(LTLIBRARIES:.la=$(PYTHON_SO)) - -# Tell versions [3.59,3.63) of GNU make to not export all variables. -# Otherwise a system limit (for SysV at least) may be exceeded. -.NOEXPORT: diff --git a/gi/__init__.py b/gi/__init__.py index 0645d44..3454790 100644 --- a/gi/__init__.py +++ b/gi/__init__.py @@ -18,32 +18,63 @@ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 # USA -from __future__ import absolute_import - # support overrides in different directories than our gi module from pkgutil import extend_path __path__ = extend_path(__path__, __name__) +import sys +import os +import importlib +import types + +_static_binding_error = ('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". ' + 'See: https://bugzilla.gnome.org/show_bug.cgi?id=709183') + +# we can't have pygobject 2 loaded at the same time we load the internal _gobject +if 'gobject' in sys.modules: + raise ImportError(_static_binding_error) + + +from . import _gi from ._gi import _API from ._gi import Repository from ._gi import PyGIDeprecationWarning - -# Force loading the GObject typelib so we have available the wrappers for -# base classes such as GInitiallyUnowned -import gi._gobject -gi # pyflakes +from ._gi import PyGIWarning _API = _API # pyflakes PyGIDeprecationWarning = PyGIDeprecationWarning - -import os +PyGIWarning = PyGIWarning _versions = {} _overridesdir = os.path.join(os.path.dirname(__file__), 'overrides') -version_info = gi._gobject.pygobject_version[:] +# Needed for compatibility with "pygobject.h"/pygobject_init() +_gobject = types.ModuleType("gi._gobject") +sys.modules[_gobject.__name__] = _gobject +_gobject._PyGObject_API = _gi._PyGObject_API +_gobject.pygobject_version = _gi.pygobject_version + +version_info = _gi.pygobject_version[:] __version__ = "{0}.{1}.{2}".format(*version_info) +_gi.register_foreign() + + +class _DummyStaticModule(types.ModuleType): + __path__ = None + + def __getattr__(self, name): + raise AttributeError(_static_binding_error) + + +sys.modules['glib'] = _DummyStaticModule('glib', _static_binding_error) +sys.modules['gobject'] = _DummyStaticModule('gobject', _static_binding_error) +sys.modules['gio'] = _DummyStaticModule('gio', _static_binding_error) +sys.modules['gtk'] = _DummyStaticModule('gtk', _static_binding_error) +sys.modules['gtk.gdk'] = _DummyStaticModule('gtk.gdk', _static_binding_error) + def check_version(version): if isinstance(version, str): @@ -59,8 +90,27 @@ def check_version(version): def require_version(namespace, version): + """ Ensures the correct versions are loaded when importing `gi` modules. + + :param namespace: The name of module to require. + :type namespace: str + :param version: The version of module to require. + :type version: str + :raises ValueError: If module/version is already loaded, already required, or unavailable. + + :Example: + + .. code-block:: python + + import gi + gi.require_version('Gtk', '3.0') + + """ repository = Repository.get_default() + if not isinstance(version, str): + raise ValueError('Namespace version needs to be a string.') + if namespace in repository.get_loaded_namespaces(): loaded_version = repository.get_version(namespace) if loaded_version != version: @@ -82,5 +132,48 @@ def require_version(namespace, version): _versions[namespace] = version +def require_versions(requires): + """ Utility function for consolidating multiple `gi.require_version()` calls. + + :param requires: The names and versions of modules to require. + :type requires: dict + + :Example: + + .. code-block:: python + + import gi + gi.require_versions({'Gtk': '3.0', 'GLib': '2.0', 'Gio': '2.0'}) + """ + for module_name, module_version in requires.items(): + require_version(module_name, module_version) + + def get_required_version(namespace): return _versions.get(namespace, None) + + +def require_foreign(namespace, symbol=None): + """Ensure the given foreign marshaling module is available and loaded. + + :param str namespace: + Introspection namespace of the foreign module (e.g. "cairo") + :param symbol: + Optional symbol typename to ensure a converter exists. + :type symbol: str or None + :raises: ImportError + + :Example: + + .. code-block:: python + + import gi + import cairo + gi.require_foreign('cairo') + + """ + try: + _gi.require_foreign(namespace, symbol) + except Exception as e: + raise ImportError(str(e)) + importlib.import_module('gi.repository', namespace) diff --git a/gi/_constants.py b/gi/_constants.py new file mode 100644 index 0000000..6fca96b --- /dev/null +++ b/gi/_constants.py @@ -0,0 +1,47 @@ +# -*- Mode: Python; py-indent-offset: 4 -*- +# pygobject - Python bindings for the GObject library +# Copyright (C) 2006-2007 Johan Dahlin +# +# gi/_constants.py: GObject type constants +# +# 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, see <http://www.gnu.org/licenses/>. + +from . import _gi + +TYPE_INVALID = _gi.TYPE_INVALID +TYPE_NONE = _gi.GType.from_name('void') +TYPE_INTERFACE = _gi.GType.from_name('GInterface') +TYPE_CHAR = _gi.GType.from_name('gchar') +TYPE_UCHAR = _gi.GType.from_name('guchar') +TYPE_BOOLEAN = _gi.GType.from_name('gboolean') +TYPE_INT = _gi.GType.from_name('gint') +TYPE_UINT = _gi.GType.from_name('guint') +TYPE_LONG = _gi.GType.from_name('glong') +TYPE_ULONG = _gi.GType.from_name('gulong') +TYPE_INT64 = _gi.GType.from_name('gint64') +TYPE_UINT64 = _gi.GType.from_name('guint64') +TYPE_ENUM = _gi.GType.from_name('GEnum') +TYPE_FLAGS = _gi.GType.from_name('GFlags') +TYPE_FLOAT = _gi.GType.from_name('gfloat') +TYPE_DOUBLE = _gi.GType.from_name('gdouble') +TYPE_STRING = _gi.GType.from_name('gchararray') +TYPE_POINTER = _gi.GType.from_name('gpointer') +TYPE_BOXED = _gi.GType.from_name('GBoxed') +TYPE_PARAM = _gi.GType.from_name('GParam') +TYPE_OBJECT = _gi.GType.from_name('GObject') +TYPE_PYOBJECT = _gi.GType.from_name('PyObject') +TYPE_GTYPE = _gi.GType.from_name('GType') +TYPE_STRV = _gi.GType.from_name('GStrv') +TYPE_VARIANT = _gi.GType.from_name('GVariant') +TYPE_UNICHAR = TYPE_UINT diff --git a/gi/_error.py b/gi/_error.py new file mode 100644 index 0000000..6440ef7 --- /dev/null +++ b/gi/_error.py @@ -0,0 +1,55 @@ +# -*- Mode: Python; py-indent-offset: 4 -*- +# vim: tabstop=4 shiftwidth=4 expandtab +# +# Copyright (C) 2014 Simon Feltman <sfeltman@gnome.org> +# +# _error.py: GError Python implementation +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +# USA + + +# NOTE: This file should not have any dependencies on introspection libs +# like gi.repository.GLib because it would cause a circular dependency. +# Developers wanting to use the GError class in their applications should +# use gi.repository.GLib.GError + + +class GError(RuntimeError): + def __init__(self, message='unknown error', domain='pygi-error', code=0): + super(GError, self).__init__(message) + self.message = message + self.domain = domain + self.code = code + + def __str__(self): + return "%s: %s (%d)" % (self.domain, self.message, self.code) + + def __repr__(self): + return "%s.%s('%s', '%s', %d)" % ( + GError.__module__.rsplit(".", 1)[-1], GError.__name__, + self.message, self.domain, self.code) + + def copy(self): + return GError(self.message, self.domain, self.code) + + def matches(self, domain, code): + """Placeholder that will be monkey patched in GLib overrides.""" + raise NotImplementedError + + @staticmethod + def new_literal(domain, message, code): + """Placeholder that will be monkey patched in GLib overrides.""" + raise NotImplementedError diff --git a/gi/_glib/Makefile.am b/gi/_glib/Makefile.am deleted file mode 100644 index 774b7e1..0000000 --- a/gi/_glib/Makefile.am +++ /dev/null @@ -1,91 +0,0 @@ -AUTOMAKE_OPTIONS = 1.7 - -extension_cppflags = \ - $(PYTHON_INCLUDES) \ - -DPY_SSIZE_T_CLEAN - -extension_ldflags = \ - -module \ - -avoid-version \ - -shrext $(PYTHON_SO) - -if OS_WIN32 -# Windows requires Python modules to be explicitly linked to libpython. -# Extension modules are shared libaries (.dll), but need to be -# called .pyd for Python to load it as an extension module. -extension_libadd = \ - $(PYTHON_LIBS) - -extension_ldflags += \ - -no-undefined -endif - - -pyglibdir = $(pyexecdir)/gi/_glib - -pyglib_PYTHON = \ - __init__.py \ - option.py - -lib_LTLIBRARIES = libpyglib-gi-2.0-@PYTHON_BASENAME@.la - -libpyglib_gi_2_0_@PYTHON_BASENAME@_la_SOURCES = \ - pyglib.c \ - pyglib.h \ - pyglib-private.h \ - pyglib-python-compat.h -libpyglib_gi_2_0_@PYTHON_BASENAME@_la_CPPFLAGS = \ - $(extension_cppflags) -libpyglib_gi_2_0_@PYTHON_BASENAME@_la_CFLAGS = \ - $(GLIB_CFLAGS) -libpyglib_gi_2_0_@PYTHON_BASENAME@_la_LIBADD = \ - $(extension_libadd) \ - $(FFI_LIBS) \ - $(GLIB_LIBS) - -if OS_WIN32 -libpyglib_gi_2_0_@PYTHON_BASENAME@_la_LDFLAGS = \ - -no-undefined -endif - -pyglib_LTLIBRARIES = _glib.la - -_glib_la_SOURCES = \ - glibmodule.c \ - pygoptioncontext.c \ - pygoptioncontext.h \ - pygoptiongroup.c \ - pygoptiongroup.h \ - pygspawn.c \ - pygspawn.h -_glib_la_CFLAGS = \ - $(GLIB_CFLAGS) -_glib_la_CPPFLAGS = \ - $(extension_cppflags) -_glib_la_LIBADD = \ - $(extension_libadd) \ - $(GLIB_LIBS) \ - libpyglib-gi-2.0-@PYTHON_BASENAME@.la -_glib_la_LDFLAGS = \ - $(extension_ldflags) \ - -export-symbols-regex "_glib|PyInit__glib" - -if PLATFORM_WIN32 -_glib_la_CFLAGS += -DPLATFORM_WIN32 -endif - -# 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 $(pyglib_PYTHON); do \ - [ -e $(builddir)/$$f ] || $(LN_S) $(srcdir)/$$f $(builddir)/$$f; \ - done - - -all: $(pyglib_LTLIBRARIES:.la=$(PYTHON_SO)) build_pylinks -check-local: $(pyglib_LTLIBRARIES:.la=$(PYTHON_SO)) build_pylinks -clean-local: - rm -f $(pyglib_LTLIBRARIES:.la=$(PYTHON_SO)) -%$(PYTHON_SO): %.la - $(LN_S) -f .libs/$@ $@ diff --git a/gi/_glib/Makefile.in b/gi/_glib/Makefile.in deleted file mode 100644 index b08e8f1..0000000 --- a/gi/_glib/Makefile.in +++ /dev/null @@ -1,915 +0,0 @@ -# Makefile.in generated by automake 1.13.3 from Makefile.am. -# @configure_input@ - -# Copyright (C) 1994-2013 Free Software Foundation, Inc. - -# This Makefile.in is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY, to the extent permitted by law; without -# even the implied warranty of MERCHANTABILITY or FITNESS FOR A -# PARTICULAR PURPOSE. - -@SET_MAKE@ - -VPATH = @srcdir@ -am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' -am__make_running_with_option = \ - case $${target_option-} in \ - ?) ;; \ - *) echo "am__make_running_with_option: internal error: invalid" \ - "target option '$${target_option-}' specified" >&2; \ - exit 1;; \ - esac; \ - has_opt=no; \ - sane_makeflags=$$MAKEFLAGS; \ - if $(am__is_gnu_make); then \ - sane_makeflags=$$MFLAGS; \ - else \ - case $$MAKEFLAGS in \ - *\\[\ \ ]*) \ - bs=\\; \ - sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ - | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ - esac; \ - fi; \ - skip_next=no; \ - strip_trailopt () \ - { \ - flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ - }; \ - for flg in $$sane_makeflags; do \ - test $$skip_next = yes && { skip_next=no; continue; }; \ - case $$flg in \ - *=*|--*) continue;; \ - -*I) strip_trailopt 'I'; skip_next=yes;; \ - -*I?*) strip_trailopt 'I';; \ - -*O) strip_trailopt 'O'; skip_next=yes;; \ - -*O?*) strip_trailopt 'O';; \ - -*l) strip_trailopt 'l'; skip_next=yes;; \ - -*l?*) strip_trailopt 'l';; \ - -[dEDm]) skip_next=yes;; \ - -[JT]) skip_next=yes;; \ - esac; \ - case $$flg in \ - *$$target_option*) has_opt=yes; break;; \ - esac; \ - done; \ - test $$has_opt = yes -am__make_dryrun = (target_option=n; $(am__make_running_with_option)) -am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) -pkgdatadir = $(datadir)/@PACKAGE@ -pkgincludedir = $(includedir)/@PACKAGE@ -pkglibdir = $(libdir)/@PACKAGE@ -pkglibexecdir = $(libexecdir)/@PACKAGE@ -am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd -install_sh_DATA = $(install_sh) -c -m 644 -install_sh_PROGRAM = $(install_sh) -c -install_sh_SCRIPT = $(install_sh) -c -INSTALL_HEADER = $(INSTALL_DATA) -transform = $(program_transform_name) -NORMAL_INSTALL = : -PRE_INSTALL = : -POST_INSTALL = : -NORMAL_UNINSTALL = : -PRE_UNINSTALL = : -POST_UNINSTALL = : -build_triplet = @build@ -host_triplet = @host@ -@OS_WIN32_TRUE@am__append_1 = \ -@OS_WIN32_TRUE@ -no-undefined - -@PLATFORM_WIN32_TRUE@am__append_2 = -DPLATFORM_WIN32 -subdir = gi/_glib -DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ - $(top_srcdir)/depcomp $(pyglib_PYTHON) \ - $(top_srcdir)/py-compile -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 -am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ - $(ACLOCAL_M4) -mkinstalldirs = $(install_sh) -d -CONFIG_HEADER = $(top_builddir)/config.h -CONFIG_CLEAN_FILES = -CONFIG_CLEAN_VPATH_FILES = -am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; -am__vpath_adj = case $$p in \ - $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ - *) f=$$p;; \ - esac; -am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; -am__install_max = 40 -am__nobase_strip_setup = \ - srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` -am__nobase_strip = \ - for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" -am__nobase_list = $(am__nobase_strip_setup); \ - for p in $$list; do echo "$$p $$p"; done | \ - sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ - $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ - if (++n[$$2] == $(am__install_max)) \ - { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ - END { for (dir in files) print dir, files[dir] }' -am__base_list = \ - sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ - sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' -am__uninstall_files_from_dir = { \ - test -z "$$files" \ - || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ - || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ - $(am__cd) "$$dir" && rm -f $$files; }; \ - } -am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(pyglibdir)" \ - "$(DESTDIR)$(pyglibdir)" -LTLIBRARIES = $(lib_LTLIBRARIES) $(pyglib_LTLIBRARIES) -am__DEPENDENCIES_1 = -@OS_WIN32_TRUE@am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1) -_glib_la_DEPENDENCIES = $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \ - libpyglib-gi-2.0-@PYTHON_BASENAME@.la -am__glib_la_OBJECTS = _glib_la-glibmodule.lo \ - _glib_la-pygoptioncontext.lo _glib_la-pygoptiongroup.lo \ - _glib_la-pygspawn.lo -_glib_la_OBJECTS = $(am__glib_la_OBJECTS) -AM_V_lt = $(am__v_lt_@AM_V@) -am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) -am__v_lt_0 = --silent -am__v_lt_1 = -_glib_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ - $(LIBTOOLFLAGS) --mode=link $(CCLD) $(_glib_la_CFLAGS) \ - $(CFLAGS) $(_glib_la_LDFLAGS) $(LDFLAGS) -o $@ -libpyglib_gi_2_0_@PYTHON_BASENAME@_la_DEPENDENCIES = \ - $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) -am_libpyglib_gi_2_0_@PYTHON_BASENAME@_la_OBJECTS = \ - libpyglib_gi_2_0_@PYTHON_BASENAME@_la-pyglib.lo -libpyglib_gi_2_0_@PYTHON_BASENAME@_la_OBJECTS = \ - $(am_libpyglib_gi_2_0_@PYTHON_BASENAME@_la_OBJECTS) -libpyglib_gi_2_0_@PYTHON_BASENAME@_la_LINK = $(LIBTOOL) $(AM_V_lt) \ - --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \ - $(CCLD) $(libpyglib_gi_2_0_@PYTHON_BASENAME@_la_CFLAGS) \ - $(CFLAGS) $(libpyglib_gi_2_0_@PYTHON_BASENAME@_la_LDFLAGS) \ - $(LDFLAGS) -o $@ -AM_V_P = $(am__v_P_@AM_V@) -am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) -am__v_P_0 = false -am__v_P_1 = : -AM_V_GEN = $(am__v_GEN_@AM_V@) -am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) -am__v_GEN_0 = @echo " GEN " $@; -am__v_GEN_1 = -AM_V_at = $(am__v_at_@AM_V@) -am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) -am__v_at_0 = @ -am__v_at_1 = -DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) -depcomp = $(SHELL) $(top_srcdir)/depcomp -am__depfiles_maybe = depfiles -am__mv = mv -f -COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ - $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ - $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ - $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ - $(AM_CFLAGS) $(CFLAGS) -AM_V_CC = $(am__v_CC_@AM_V@) -am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) -am__v_CC_0 = @echo " CC " $@; -am__v_CC_1 = -CCLD = $(CC) -LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ - $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ - $(AM_LDFLAGS) $(LDFLAGS) -o $@ -AM_V_CCLD = $(am__v_CCLD_@AM_V@) -am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) -am__v_CCLD_0 = @echo " CCLD " $@; -am__v_CCLD_1 = -SOURCES = $(_glib_la_SOURCES) \ - $(libpyglib_gi_2_0_@PYTHON_BASENAME@_la_SOURCES) -DIST_SOURCES = $(_glib_la_SOURCES) \ - $(libpyglib_gi_2_0_@PYTHON_BASENAME@_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) -am__pep3147_tweak = \ - sed -e 's|\.py$$||' -e 's|[^/]*$$|__pycache__/&.*.py|' -py_compile = $(top_srcdir)/py-compile -am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) -# Read a list of newline-separated strings from the standard input, -# and print each of them once, without duplicates. Input order is -# *not* preserved. -am__uniquify_input = $(AWK) '\ - BEGIN { nonempty = 0; } \ - { items[$$0] = 1; nonempty = 1; } \ - END { if (nonempty) { for (i in items) print i; }; } \ -' -# Make sure the list of sources is unique. This is necessary because, -# e.g., the same source file might be shared among _SOURCES variables -# for different programs/libraries. -am__define_uniq_tagged_files = \ - list='$(am__tagged_files)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | $(am__uniquify_input)` -ETAGS = etags -CTAGS = ctags -DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) -ACLOCAL = @ACLOCAL@ -ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@ -AMTAR = @AMTAR@ -AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ -AR = @AR@ -AS = @AS@ -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@ -DATADIR = @DATADIR@ -DEFS = @DEFS@ -DEPDIR = @DEPDIR@ -DLLTOOL = @DLLTOOL@ -DSYMUTIL = @DSYMUTIL@ -DUMPBIN = @DUMPBIN@ -ECHO_C = @ECHO_C@ -ECHO_N = @ECHO_N@ -ECHO_T = @ECHO_T@ -EGREP = @EGREP@ -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@ -GI_DATADIR = @GI_DATADIR@ -GI_LIBS = @GI_LIBS@ -GLIB_CFLAGS = @GLIB_CFLAGS@ -GLIB_COMPILE_RESOURCES = @GLIB_COMPILE_RESOURCES@ -GLIB_GENMARSHAL = @GLIB_GENMARSHAL@ -GLIB_LIBS = @GLIB_LIBS@ -GLIB_MKENUMS = @GLIB_MKENUMS@ -GOBJECT_QUERY = @GOBJECT_QUERY@ -GREP = @GREP@ -INSTALL = @INSTALL@ -INSTALL_DATA = @INSTALL_DATA@ -INSTALL_PROGRAM = @INSTALL_PROGRAM@ -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@ -LIBOBJS = @LIBOBJS@ -LIBS = @LIBS@ -LIBTOOL = @LIBTOOL@ -LIPO = @LIPO@ -LN_S = @LN_S@ -LTLIBOBJS = @LTLIBOBJS@ -MAKEINFO = @MAKEINFO@ -MANIFEST_TOOL = @MANIFEST_TOOL@ -MKDIR_P = @MKDIR_P@ -NM = @NM@ -NMEDIT = @NMEDIT@ -OBJDUMP = @OBJDUMP@ -OBJEXT = @OBJEXT@ -OTOOL = @OTOOL@ -OTOOL64 = @OTOOL64@ -PACKAGE = @PACKAGE@ -PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ -PACKAGE_NAME = @PACKAGE_NAME@ -PACKAGE_STRING = @PACKAGE_STRING@ -PACKAGE_TARNAME = @PACKAGE_TARNAME@ -PACKAGE_URL = @PACKAGE_URL@ -PACKAGE_VERSION = @PACKAGE_VERSION@ -PATH_SEPARATOR = @PATH_SEPARATOR@ -PKG_CONFIG = @PKG_CONFIG@ -PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ -PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ -PLATFORM = @PLATFORM@ -PYCAIRO_CFLAGS = @PYCAIRO_CFLAGS@ -PYCAIRO_LIBS = @PYCAIRO_LIBS@ -PYGOBJECT_MAJOR_VERSION = @PYGOBJECT_MAJOR_VERSION@ -PYGOBJECT_MICRO_VERSION = @PYGOBJECT_MICRO_VERSION@ -PYGOBJECT_MINOR_VERSION = @PYGOBJECT_MINOR_VERSION@ -PYTHON = @PYTHON@ -PYTHON_BASENAME = @PYTHON_BASENAME@ -PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ -PYTHON_INCLUDES = @PYTHON_INCLUDES@ -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@ -SET_MAKE = @SET_MAKE@ -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@ -abs_top_srcdir = @abs_top_srcdir@ -ac_ct_AR = @ac_ct_AR@ -ac_ct_CC = @ac_ct_CC@ -ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ -am__include = @am__include@ -am__leading_dot = @am__leading_dot@ -am__quote = @am__quote@ -am__tar = @am__tar@ -am__untar = @am__untar@ -bindir = @bindir@ -build = @build@ -build_alias = @build_alias@ -build_cpu = @build_cpu@ -build_os = @build_os@ -build_vendor = @build_vendor@ -builddir = @builddir@ -datadir = @datadir@ -datarootdir = @datarootdir@ -docdir = @docdir@ -dvidir = @dvidir@ -exec_prefix = @exec_prefix@ -host = @host@ -host_alias = @host_alias@ -host_cpu = @host_cpu@ -host_os = @host_os@ -host_vendor = @host_vendor@ -htmldir = @htmldir@ -includedir = @includedir@ -infodir = @infodir@ -install_sh = @install_sh@ -libdir = @libdir@ -libexecdir = @libexecdir@ -localedir = @localedir@ -localstatedir = @localstatedir@ -mandir = @mandir@ -mkdir_p = @mkdir_p@ -oldincludedir = @oldincludedir@ -pdfdir = @pdfdir@ -pkgpyexecdir = @pkgpyexecdir@ -pkgpythondir = @pkgpythondir@ -prefix = @prefix@ -program_transform_name = @program_transform_name@ -psdir = @psdir@ -pyexecdir = @pyexecdir@ -pythondir = @pythondir@ -sbindir = @sbindir@ -sharedstatedir = @sharedstatedir@ -srcdir = @srcdir@ -sysconfdir = @sysconfdir@ -target_alias = @target_alias@ -top_build_prefix = @top_build_prefix@ -top_builddir = @top_builddir@ -top_srcdir = @top_srcdir@ -AUTOMAKE_OPTIONS = 1.7 -extension_cppflags = \ - $(PYTHON_INCLUDES) \ - -DPY_SSIZE_T_CLEAN - -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 -# called .pyd for Python to load it as an extension module. -@OS_WIN32_TRUE@extension_libadd = \ -@OS_WIN32_TRUE@ $(PYTHON_LIBS) - -pyglibdir = $(pyexecdir)/gi/_glib -pyglib_PYTHON = \ - __init__.py \ - option.py - -lib_LTLIBRARIES = libpyglib-gi-2.0-@PYTHON_BASENAME@.la -libpyglib_gi_2_0_@PYTHON_BASENAME@_la_SOURCES = \ - pyglib.c \ - pyglib.h \ - pyglib-private.h \ - pyglib-python-compat.h - -libpyglib_gi_2_0_@PYTHON_BASENAME@_la_CPPFLAGS = \ - $(extension_cppflags) - -libpyglib_gi_2_0_@PYTHON_BASENAME@_la_CFLAGS = \ - $(GLIB_CFLAGS) - -libpyglib_gi_2_0_@PYTHON_BASENAME@_la_LIBADD = \ - $(extension_libadd) \ - $(FFI_LIBS) \ - $(GLIB_LIBS) - -@OS_WIN32_TRUE@libpyglib_gi_2_0_@PYTHON_BASENAME@_la_LDFLAGS = \ -@OS_WIN32_TRUE@ -no-undefined - -pyglib_LTLIBRARIES = _glib.la -_glib_la_SOURCES = \ - glibmodule.c \ - pygoptioncontext.c \ - pygoptioncontext.h \ - pygoptiongroup.c \ - pygoptiongroup.h \ - pygspawn.c \ - pygspawn.h - -_glib_la_CFLAGS = $(GLIB_CFLAGS) $(am__append_2) -_glib_la_CPPFLAGS = \ - $(extension_cppflags) - -_glib_la_LIBADD = \ - $(extension_libadd) \ - $(GLIB_LIBS) \ - libpyglib-gi-2.0-@PYTHON_BASENAME@.la - -_glib_la_LDFLAGS = \ - $(extension_ldflags) \ - -export-symbols-regex "_glib|PyInit__glib" - -all: all-am - -.SUFFIXES: -.SUFFIXES: .c .lo .o .obj -$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) - @for dep in $?; do \ - case '$(am__configure_deps)' in \ - *$$dep*) \ - ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ - && { if test -f $@; then exit 0; else break; fi; }; \ - exit 1;; \ - esac; \ - done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign gi/_glib/Makefile'; \ - $(am__cd) $(top_srcdir) && \ - $(AUTOMAKE) --foreign gi/_glib/Makefile -.PRECIOUS: Makefile -Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status - @case '$?' in \ - *config.status*) \ - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ - *) \ - echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ - cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ - esac; - -$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh - -$(top_srcdir)/configure: $(am__configure_deps) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh -$(ACLOCAL_M4): $(am__aclocal_m4_deps) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh -$(am__aclocal_m4_deps): - -install-libLTLIBRARIES: $(lib_LTLIBRARIES) - @$(NORMAL_INSTALL) - @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ - list2=; for p in $$list; do \ - if test -f $$p; then \ - list2="$$list2 $$p"; \ - else :; fi; \ - done; \ - test -z "$$list2" || { \ - echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \ - $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \ - echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \ - $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \ - } - -uninstall-libLTLIBRARIES: - @$(NORMAL_UNINSTALL) - @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \ - for p in $$list; do \ - $(am__strip_dir) \ - echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(libdir)/$$f'"; \ - $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(libdir)/$$f"; \ - done - -clean-libLTLIBRARIES: - -test -z "$(lib_LTLIBRARIES)" || rm -f $(lib_LTLIBRARIES) - @list='$(lib_LTLIBRARIES)'; \ - locs=`for p in $$list; do echo $$p; done | \ - sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ - sort -u`; \ - test -z "$$locs" || { \ - echo rm -f $${locs}; \ - rm -f $${locs}; \ - } - -install-pyglibLTLIBRARIES: $(pyglib_LTLIBRARIES) - @$(NORMAL_INSTALL) - @list='$(pyglib_LTLIBRARIES)'; test -n "$(pyglibdir)" || list=; \ - list2=; for p in $$list; do \ - if test -f $$p; then \ - list2="$$list2 $$p"; \ - else :; fi; \ - done; \ - test -z "$$list2" || { \ - echo " $(MKDIR_P) '$(DESTDIR)$(pyglibdir)'"; \ - $(MKDIR_P) "$(DESTDIR)$(pyglibdir)" || exit 1; \ - echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(pyglibdir)'"; \ - $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(pyglibdir)"; \ - } - -uninstall-pyglibLTLIBRARIES: - @$(NORMAL_UNINSTALL) - @list='$(pyglib_LTLIBRARIES)'; test -n "$(pyglibdir)" || list=; \ - for p in $$list; do \ - $(am__strip_dir) \ - echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(pyglibdir)/$$f'"; \ - $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(pyglibdir)/$$f"; \ - done - -clean-pyglibLTLIBRARIES: - -test -z "$(pyglib_LTLIBRARIES)" || rm -f $(pyglib_LTLIBRARIES) - @list='$(pyglib_LTLIBRARIES)'; \ - locs=`for p in $$list; do echo $$p; done | \ - sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ - sort -u`; \ - test -z "$$locs" || { \ - echo rm -f $${locs}; \ - rm -f $${locs}; \ - } - -_glib.la: $(_glib_la_OBJECTS) $(_glib_la_DEPENDENCIES) $(EXTRA__glib_la_DEPENDENCIES) - $(AM_V_CCLD)$(_glib_la_LINK) -rpath $(pyglibdir) $(_glib_la_OBJECTS) $(_glib_la_LIBADD) $(LIBS) - -libpyglib-gi-2.0-@PYTHON_BASENAME@.la: $(libpyglib_gi_2_0_@PYTHON_BASENAME@_la_OBJECTS) $(libpyglib_gi_2_0_@PYTHON_BASENAME@_la_DEPENDENCIES) $(EXTRA_libpyglib_gi_2_0_@PYTHON_BASENAME@_la_DEPENDENCIES) - $(AM_V_CCLD)$(libpyglib_gi_2_0_@PYTHON_BASENAME@_la_LINK) -rpath $(libdir) $(libpyglib_gi_2_0_@PYTHON_BASENAME@_la_OBJECTS) $(libpyglib_gi_2_0_@PYTHON_BASENAME@_la_LIBADD) $(LIBS) - -mostlyclean-compile: - -rm -f *.$(OBJEXT) - -distclean-compile: - -rm -f *.tab.c - -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/_glib_la-glibmodule.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/_glib_la-pygoptioncontext.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/_glib_la-pygoptiongroup.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/_glib_la-pygspawn.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libpyglib_gi_2_0_@PYTHON_BASENAME@_la-pyglib.Plo@am__quote@ - -.c.o: -@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $< - -.c.obj: -@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'` - -.c.lo: -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< - -_glib_la-glibmodule.lo: glibmodule.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(_glib_la_CPPFLAGS) $(CPPFLAGS) $(_glib_la_CFLAGS) $(CFLAGS) -MT _glib_la-glibmodule.lo -MD -MP -MF $(DEPDIR)/_glib_la-glibmodule.Tpo -c -o _glib_la-glibmodule.lo `test -f 'glibmodule.c' || echo '$(srcdir)/'`glibmodule.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/_glib_la-glibmodule.Tpo $(DEPDIR)/_glib_la-glibmodule.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='glibmodule.c' object='_glib_la-glibmodule.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(_glib_la_CPPFLAGS) $(CPPFLAGS) $(_glib_la_CFLAGS) $(CFLAGS) -c -o _glib_la-glibmodule.lo `test -f 'glibmodule.c' || echo '$(srcdir)/'`glibmodule.c - -_glib_la-pygoptioncontext.lo: pygoptioncontext.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(_glib_la_CPPFLAGS) $(CPPFLAGS) $(_glib_la_CFLAGS) $(CFLAGS) -MT _glib_la-pygoptioncontext.lo -MD -MP -MF $(DEPDIR)/_glib_la-pygoptioncontext.Tpo -c -o _glib_la-pygoptioncontext.lo `test -f 'pygoptioncontext.c' || echo '$(srcdir)/'`pygoptioncontext.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/_glib_la-pygoptioncontext.Tpo $(DEPDIR)/_glib_la-pygoptioncontext.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pygoptioncontext.c' object='_glib_la-pygoptioncontext.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(_glib_la_CPPFLAGS) $(CPPFLAGS) $(_glib_la_CFLAGS) $(CFLAGS) -c -o _glib_la-pygoptioncontext.lo `test -f 'pygoptioncontext.c' || echo '$(srcdir)/'`pygoptioncontext.c - -_glib_la-pygoptiongroup.lo: pygoptiongroup.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(_glib_la_CPPFLAGS) $(CPPFLAGS) $(_glib_la_CFLAGS) $(CFLAGS) -MT _glib_la-pygoptiongroup.lo -MD -MP -MF $(DEPDIR)/_glib_la-pygoptiongroup.Tpo -c -o _glib_la-pygoptiongroup.lo `test -f 'pygoptiongroup.c' || echo '$(srcdir)/'`pygoptiongroup.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/_glib_la-pygoptiongroup.Tpo $(DEPDIR)/_glib_la-pygoptiongroup.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pygoptiongroup.c' object='_glib_la-pygoptiongroup.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(_glib_la_CPPFLAGS) $(CPPFLAGS) $(_glib_la_CFLAGS) $(CFLAGS) -c -o _glib_la-pygoptiongroup.lo `test -f 'pygoptiongroup.c' || echo '$(srcdir)/'`pygoptiongroup.c - -_glib_la-pygspawn.lo: pygspawn.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(_glib_la_CPPFLAGS) $(CPPFLAGS) $(_glib_la_CFLAGS) $(CFLAGS) -MT _glib_la-pygspawn.lo -MD -MP -MF $(DEPDIR)/_glib_la-pygspawn.Tpo -c -o _glib_la-pygspawn.lo `test -f 'pygspawn.c' || echo '$(srcdir)/'`pygspawn.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/_glib_la-pygspawn.Tpo $(DEPDIR)/_glib_la-pygspawn.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pygspawn.c' object='_glib_la-pygspawn.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(_glib_la_CPPFLAGS) $(CPPFLAGS) $(_glib_la_CFLAGS) $(CFLAGS) -c -o _glib_la-pygspawn.lo `test -f 'pygspawn.c' || echo '$(srcdir)/'`pygspawn.c - -libpyglib_gi_2_0_@PYTHON_BASENAME@_la-pyglib.lo: pyglib.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpyglib_gi_2_0_@PYTHON_BASENAME@_la_CPPFLAGS) $(CPPFLAGS) $(libpyglib_gi_2_0_@PYTHON_BASENAME@_la_CFLAGS) $(CFLAGS) -MT libpyglib_gi_2_0_@PYTHON_BASENAME@_la-pyglib.lo -MD -MP -MF $(DEPDIR)/libpyglib_gi_2_0_@PYTHON_BASENAME@_la-pyglib.Tpo -c -o libpyglib_gi_2_0_@PYTHON_BASENAME@_la-pyglib.lo `test -f 'pyglib.c' || echo '$(srcdir)/'`pyglib.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libpyglib_gi_2_0_@PYTHON_BASENAME@_la-pyglib.Tpo $(DEPDIR)/libpyglib_gi_2_0_@PYTHON_BASENAME@_la-pyglib.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pyglib.c' object='libpyglib_gi_2_0_@PYTHON_BASENAME@_la-pyglib.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libpyglib_gi_2_0_@PYTHON_BASENAME@_la_CPPFLAGS) $(CPPFLAGS) $(libpyglib_gi_2_0_@PYTHON_BASENAME@_la_CFLAGS) $(CFLAGS) -c -o libpyglib_gi_2_0_@PYTHON_BASENAME@_la-pyglib.lo `test -f 'pyglib.c' || echo '$(srcdir)/'`pyglib.c - -mostlyclean-libtool: - -rm -f *.lo - -clean-libtool: - -rm -rf .libs _libs -install-pyglibPYTHON: $(pyglib_PYTHON) - @$(NORMAL_INSTALL) - @list='$(pyglib_PYTHON)'; dlist=; list2=; test -n "$(pyglibdir)" || list=; \ - if test -n "$$list"; then \ - echo " $(MKDIR_P) '$(DESTDIR)$(pyglibdir)'"; \ - $(MKDIR_P) "$(DESTDIR)$(pyglibdir)" || exit 1; \ - fi; \ - for p in $$list; do \ - if test -f "$$p"; then b=; else b="$(srcdir)/"; fi; \ - if test -f $$b$$p; then \ - $(am__strip_dir) \ - dlist="$$dlist $$f"; \ - list2="$$list2 $$b$$p"; \ - else :; fi; \ - done; \ - for file in $$list2; do echo $$file; done | $(am__base_list) | \ - while read files; do \ - echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pyglibdir)'"; \ - $(INSTALL_DATA) $$files "$(DESTDIR)$(pyglibdir)" || exit $$?; \ - done || exit $$?; \ - if test -n "$$dlist"; then \ - $(am__py_compile) --destdir "$(DESTDIR)" \ - --basedir "$(pyglibdir)" $$dlist; \ - else :; fi - -uninstall-pyglibPYTHON: - @$(NORMAL_UNINSTALL) - @list='$(pyglib_PYTHON)'; test -n "$(pyglibdir)" || list=; \ - py_files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ - test -n "$$py_files" || exit 0; \ - dir='$(DESTDIR)$(pyglibdir)'; \ - pyc_files=`echo "$$py_files" | sed 's|$$|c|'`; \ - pyo_files=`echo "$$py_files" | sed 's|$$|o|'`; \ - py_files_pep3147=`echo "$$py_files" | $(am__pep3147_tweak)`; \ - echo "$$py_files_pep3147";\ - pyc_files_pep3147=`echo "$$py_files_pep3147" | sed 's|$$|c|'`; \ - pyo_files_pep3147=`echo "$$py_files_pep3147" | sed 's|$$|o|'`; \ - st=0; \ - for files in \ - "$$py_files" \ - "$$pyc_files" \ - "$$pyo_files" \ - "$$pyc_files_pep3147" \ - "$$pyo_files_pep3147" \ - ; do \ - $(am__uninstall_files_from_dir) || st=$$?; \ - done; \ - exit $$st - -ID: $(am__tagged_files) - $(am__define_uniq_tagged_files); mkid -fID $$unique -tags: tags-am -TAGS: tags - -tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) - set x; \ - here=`pwd`; \ - $(am__define_uniq_tagged_files); \ - shift; \ - if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ - test -n "$$unique" || unique=$$empty_fix; \ - if test $$# -gt 0; then \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - "$$@" $$unique; \ - else \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - $$unique; \ - fi; \ - fi -ctags: ctags-am - -CTAGS: ctags -ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) - $(am__define_uniq_tagged_files); \ - test -z "$(CTAGS_ARGS)$$unique" \ - || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ - $$unique - -GTAGS: - here=`$(am__cd) $(top_builddir) && pwd` \ - && $(am__cd) $(top_srcdir) \ - && gtags -i $(GTAGS_ARGS) "$$here" -cscopelist: cscopelist-am - -cscopelist-am: $(am__tagged_files) - list='$(am__tagged_files)'; \ - case "$(srcdir)" in \ - [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ - *) sdir=$(subdir)/$(srcdir) ;; \ - esac; \ - for i in $$list; do \ - if test -f "$$i"; then \ - echo "$(subdir)/$$i"; \ - else \ - echo "$$sdir/$$i"; \ - fi; \ - done >> $(top_builddir)/cscope.files - -distclean-tags: - -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags - -distdir: $(DISTFILES) - @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - list='$(DISTFILES)'; \ - dist_files=`for file in $$list; do echo $$file; done | \ - sed -e "s|^$$srcdirstrip/||;t" \ - -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ - case $$dist_files in \ - */*) $(MKDIR_P) `echo "$$dist_files" | \ - sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ - sort -u` ;; \ - esac; \ - for file in $$dist_files; do \ - if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ - if test -d $$d/$$file; then \ - dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ - if test -d "$(distdir)/$$file"; then \ - find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ - fi; \ - if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ - cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ - find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ - fi; \ - cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ - else \ - test -f "$(distdir)/$$file" \ - || cp -p $$d/$$file "$(distdir)/$$file" \ - || exit 1; \ - fi; \ - done -check-am: all-am - $(MAKE) $(AM_MAKEFLAGS) check-local -check: check-am -all-am: Makefile $(LTLIBRARIES) -installdirs: - for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(pyglibdir)" "$(DESTDIR)$(pyglibdir)"; do \ - test -z "$$dir" || $(MKDIR_P) "$$dir"; \ - done -install: install-am -install-exec: install-exec-am -install-data: install-data-am -uninstall: uninstall-am - -install-am: all-am - @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am - -installcheck: installcheck-am -install-strip: - if test -z '$(STRIP)'; then \ - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ - install; \ - else \ - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ - "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ - fi -mostlyclean-generic: - -clean-generic: - -distclean-generic: - -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) - -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) - -maintainer-clean-generic: - @echo "This command is intended for maintainers to use" - @echo "it deletes files that may require special tools to rebuild." -clean: clean-am - -clean-am: clean-generic clean-libLTLIBRARIES clean-libtool clean-local \ - clean-pyglibLTLIBRARIES mostlyclean-am - -distclean: distclean-am - -rm -rf ./$(DEPDIR) - -rm -f Makefile -distclean-am: clean-am distclean-compile distclean-generic \ - distclean-tags - -dvi: dvi-am - -dvi-am: - -html: html-am - -html-am: - -info: info-am - -info-am: - -install-data-am: install-pyglibLTLIBRARIES install-pyglibPYTHON - -install-dvi: install-dvi-am - -install-dvi-am: - -install-exec-am: install-libLTLIBRARIES - -install-html: install-html-am - -install-html-am: - -install-info: install-info-am - -install-info-am: - -install-man: - -install-pdf: install-pdf-am - -install-pdf-am: - -install-ps: install-ps-am - -install-ps-am: - -installcheck-am: - -maintainer-clean: maintainer-clean-am - -rm -rf ./$(DEPDIR) - -rm -f Makefile -maintainer-clean-am: distclean-am maintainer-clean-generic - -mostlyclean: mostlyclean-am - -mostlyclean-am: mostlyclean-compile mostlyclean-generic \ - mostlyclean-libtool - -pdf: pdf-am - -pdf-am: - -ps: ps-am - -ps-am: - -uninstall-am: uninstall-libLTLIBRARIES uninstall-pyglibLTLIBRARIES \ - uninstall-pyglibPYTHON - -.MAKE: check-am install-am install-strip - -.PHONY: CTAGS GTAGS TAGS all all-am check check-am check-local clean \ - clean-generic clean-libLTLIBRARIES clean-libtool clean-local \ - clean-pyglibLTLIBRARIES cscopelist-am ctags ctags-am distclean \ - distclean-compile distclean-generic distclean-libtool \ - distclean-tags distdir dvi dvi-am html html-am info info-am \ - install install-am install-data install-data-am install-dvi \ - install-dvi-am install-exec install-exec-am install-html \ - install-html-am install-info install-info-am \ - install-libLTLIBRARIES install-man install-pdf install-pdf-am \ - install-ps install-ps-am install-pyglibLTLIBRARIES \ - install-pyglibPYTHON install-strip installcheck \ - installcheck-am installdirs maintainer-clean \ - maintainer-clean-generic mostlyclean mostlyclean-compile \ - mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ - tags tags-am uninstall uninstall-am uninstall-libLTLIBRARIES \ - uninstall-pyglibLTLIBRARIES uninstall-pyglibPYTHON - - -# 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 $(pyglib_PYTHON); do \ - [ -e $(builddir)/$$f ] || $(LN_S) $(srcdir)/$$f $(builddir)/$$f; \ - done - -all: $(pyglib_LTLIBRARIES:.la=$(PYTHON_SO)) build_pylinks -check-local: $(pyglib_LTLIBRARIES:.la=$(PYTHON_SO)) build_pylinks -clean-local: - rm -f $(pyglib_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. -.NOEXPORT: diff --git a/gi/_glib/__init__.py b/gi/_glib/__init__.py deleted file mode 100644 index 0b9df9a..0000000 --- a/gi/_glib/__init__.py +++ /dev/null @@ -1,25 +0,0 @@ -# -*- Mode: Python; py-indent-offset: 4 -*- -# pygobject - Python bindings for the GObject library -# Copyright (C) 2006-2012 Johan Dahlin -# -# glib/__init__.py: initialisation file for glib module -# -# 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 - -from . import _glib - -# Internal API -_PyGLib_API = _glib._PyGLib_API diff --git a/gi/_glib/glibmodule.c b/gi/_glib/glibmodule.c deleted file mode 100644 index d08d4fb..0000000 --- a/gi/_glib/glibmodule.c +++ /dev/null @@ -1,103 +0,0 @@ -/* -*- Mode: C; c-set-style: python; c-basic-offset: 4 -*- - * pyglib - Python bindings for GLib toolkit. - * Copyright (C) 1998-2003 James Henstridge - * 2004-2008 Johan Dahlin - * - * glibmodule.c: wrapper for the glib library. - * - * 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 - */ - -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif - -#include <Python.h> -#include <glib.h> -#include "pyglib.h" -#include "pyglib-private.h" -#include "pygoptioncontext.h" -#include "pygoptiongroup.h" -#include "pygspawn.h" - -/* ---------------- glib module functions -------------------- */ - -static PyMethodDef _glib_functions[] = { - { "spawn_async", - (PyCFunction)pyglib_spawn_async, METH_VARARGS|METH_KEYWORDS, - "spawn_async(argv, envp=None, working_directory=None,\n" - " flags=0, child_setup=None, user_data=None,\n" - " standard_input=None, standard_output=None,\n" - " standard_error=None) -> (pid, stdin, stdout, stderr)\n" - "Execute a child program asynchronously within a glib.MainLoop()\n" - "See the reference manual for a complete reference." }, - { NULL, NULL, 0 } -}; - -/* ----------------- glib module initialisation -------------- */ - -static struct _PyGLib_Functions pyglib_api = { - FALSE, /* threads_enabled */ - NULL, /* gerror_exception */ - NULL, /* block_threads */ - NULL, /* unblock_threads */ - NULL, /* pyg_main_context_new */ - pyg_option_context_new, - pyg_option_group_new, -}; - -static void -pyglib_register_api(PyObject *d) -{ - PyObject *o; - - /* for addon libraries ... */ - PyDict_SetItemString(d, "_PyGLib_API", - o=PYGLIB_CPointer_WrapPointer(&pyglib_api,"gi._glib._PyGLib_API")); - Py_DECREF(o); - - pyglib_init_internal(o); -} - -static void -pyglib_register_error(PyObject *d) -{ - PyObject *dict; - PyObject *gerror_class; - dict = PyDict_New(); - /* This is a hack to work around the deprecation warning of - * BaseException.message in Python 2.6+. - * GError has also an "message" attribute. - */ - PyDict_SetItemString(dict, "message", Py_None); - gerror_class = PyErr_NewException("gi._glib.GError", PyExc_RuntimeError, dict); - Py_DECREF(dict); - - PyDict_SetItemString(d, "GError", gerror_class); - pyglib_api.gerror_exception = gerror_class; -} - -PYGLIB_MODULE_START(_glib, "_glib") -{ - PyObject *d = PyModule_GetDict(module); - - pyglib_register_api(d); - pyglib_register_error(d); - pyglib_spawn_register_types(d); - pyglib_option_context_register_types(d); - pyglib_option_group_register_types(d); -} -PYGLIB_MODULE_END diff --git a/gi/_glib/pyglib-private.h b/gi/_glib/pyglib-private.h deleted file mode 100644 index 183184f..0000000 --- a/gi/_glib/pyglib-private.h +++ /dev/null @@ -1,49 +0,0 @@ -/* -*- Mode: C; c-basic-offset: 4 -*- - * pyglib - Python bindings for GLib toolkit. - * Copyright (C) 1998-2003 James Henstridge - * 2004-2008 Johan Dahlin - * - * 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 - */ - -#ifndef __PYGLIB_PRIVATE_H__ -#define __PYGLIB_PRIVATE_H__ - -#include <Python.h> -#include <glib.h> - -#include <pyglib-python-compat.h> - -G_BEGIN_DECLS - -struct _PyGLib_Functions { - gboolean threads_enabled; - PyObject *gerror_exception; - PyGLibThreadBlockFunc block_threads; - PyGLibThreadBlockFunc unblock_threads; - PyObject* (*main_context_new)(GMainContext *context); - PyObject* (*option_context_new)(GOptionContext *context); - PyObject* (*option_group_new)(GOptionGroup *group); -}; - -gboolean _pyglib_handler_marshal(gpointer user_data); -void _pyglib_destroy_notify(gpointer user_data); - -G_END_DECLS - -#endif /* __PYGLIB_PRIVATE_H__ */ - - diff --git a/gi/_glib/pyglib-python-compat.h b/gi/_glib/pyglib-python-compat.h deleted file mode 100644 index 7b4c595..0000000 --- a/gi/_glib/pyglib-python-compat.h +++ /dev/null @@ -1,220 +0,0 @@ -/* -*- Mode: C; c-basic-offset: 4 -*- - * pyglib - Python bindings for GLib toolkit. - * Copyright (C) 2008 Johan Dahlin - * - * 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 - */ - -#ifndef __PYGLIB_PYTHON_COMPAT_H__ -#define __PYGLIB_PYTHON_COMPAT_H__ - -# define PYGLIB_CPointer_Check PyCapsule_CheckExact -# define PYGLIB_CPointer_WrapPointer(ptr, typename) \ - PyCapsule_New(ptr, typename, NULL) -# define PYGLIB_CPointer_GetPointer(obj, typename) \ - PyCapsule_GetPointer(obj, typename) -# define PYGLIB_CPointer_Import(module, symbol) \ - PyCapsule_Import(##module##.##symbol##, FALSE) - -#if PY_VERSION_HEX < 0x03000000 - -#define PYGLIB_INIT_FUNCTION(modname, fullpkgname, functions) \ -static int _pyglib_init_##modname(PyObject *module); \ -void init##modname(void) \ -{ \ - PyObject *module = Py_InitModule(fullpkgname, functions); \ - _pyglib_init_##modname(module); \ -} \ -static int _pyglib_init_##modname(PyObject *module) - -#else - -#define PYGLIB_INIT_FUNCTION(modname, fullpkgname, functions) \ -static struct PyModuleDef _##modname##module = { \ - PyModuleDef_HEAD_INIT, \ - fullpkgname, \ - NULL, \ - -1, \ - functions, \ - NULL, \ - NULL, \ - NULL, \ - NULL \ -}; \ -static int _pyglib_init_##modname(PyObject *module); \ -PyObject *PyInit_##modname(void) \ -{ \ - PyObject *module = PyModule_Create(&_##modname##module); \ - if (module == NULL) \ - return NULL; \ - if (_pyglib_init_##modname(module) != 0 ) {\ - Py_DECREF(module); \ - return NULL; \ - } \ - return module; \ -} \ -static int _pyglib_init_##modname(PyObject *module) - -#endif - -/* Compilation on Python 2.x */ -#if PY_VERSION_HEX < 0x03000000 -#define PYGLIB_MODULE_ERROR_RETURN - -#define RO READONLY - -#define PYGLIB_PyBaseString_Check(ob) (PyString_Check(ob) || PyUnicode_Check(ob)) - -#define PYGLIB_PyUnicode_Check PyString_Check -#define PYGLIB_PyUnicode_AsString PyString_AsString -#define PYGLIB_PyUnicode_AsStringAndSize PyString_AsStringAndSize -#define PYGLIB_PyUnicode_FromString PyString_FromString -#define PYGLIB_PyUnicode_FromStringAndSize PyString_FromStringAndSize -#define PYGLIB_PyUnicode_FromFormat PyString_FromFormat -#define PYGLIB_PyUnicode_AS_STRING PyString_AS_STRING -#define PYGLIB_PyUnicode_GET_SIZE PyString_GET_SIZE -#define PYGLIB_PyUnicode_Type PyString_Type -#define PYGLIB_PyUnicode_InternFromString PyString_InternFromString -#define PYGLIB_PyUnicode_InternInPlace PyString_InternInPlace - -#define PYGLIB_PyBytes_FromString PyString_FromString -#define PYGLIB_PyBytes_FromStringAndSize PyString_FromStringAndSize -#define PYGLIB_PyBytes_Resize _PyString_Resize -#define PYGLIB_PyBytes_AsString PyString_AsString -#define PYGLIB_PyBytes_Size PyString_Size -#define PYGLIB_PyBytes_Check PyString_Check - -#define PYGLIB_PyLong_Check PyInt_Check -#define PYGLIB_PyLong_FromLong PyInt_FromLong -#define PYGLIB_PyLong_FromSsize_t PyInt_FromSsize_t -#define PYGLIB_PyLong_FromSize_t PyInt_FromSize_t -#define PYGLIB_PyLong_AsLong PyInt_AsLong -#define PYGLIB_PyLongObject PyIntObject -#define PYGLIB_PyLong_Type PyInt_Type -#define PYGLIB_PyLong_AS_LONG PyInt_AS_LONG -#define Py_TYPE(ob) (((PyObject*)(ob))->ob_type) - -/* Python 2.7 lacks a PyInt_FromUnsignedLong function; use signed longs, and - * rely on PyInt_AsUnsignedLong() to interpret them correctly */ -#define PYGLIB_PyLong_FromUnsignedLong PyInt_FromLong -#define PYGLIB_PyLong_AsUnsignedLong(o) PyInt_AsUnsignedLongMask((PyObject*)(o)) - -#define PYGLIB_PyNumber_Long PyNumber_Int - -#ifndef PyVarObject_HEAD_INIT -#define PyVarObject_HEAD_INIT(base, size) \ - PyObject_HEAD_INIT(base) \ - size, -#endif - -#define PYGLIB_MODULE_START(symbol, modname) \ -DL_EXPORT(void) init##symbol(void); \ -DL_EXPORT(void) init##symbol(void) \ -{ \ - PyObject *module; \ - module = Py_InitModule(modname, symbol##_functions); -#define PYGLIB_MODULE_END } -#define PYGLIB_DEFINE_TYPE(typename, symbol, csymbol) \ -PyTypeObject symbol = { \ - PyObject_HEAD_INIT(NULL) \ - 0, \ - typename, \ - sizeof(csymbol), \ - 0, \ -}; -#define PYGLIB_REGISTER_TYPE(d, type, name) \ - if (!type.tp_alloc) \ - type.tp_alloc = PyType_GenericAlloc; \ - if (!type.tp_new) \ - type.tp_new = PyType_GenericNew; \ - if (PyType_Ready(&type)) \ - return; \ - PyDict_SetItemString(d, name, (PyObject *)&type); - -#else - -#define PYGLIB_MODULE_ERROR_RETURN 0 - -#define PYGLIB_MODULE_START(symbol, modname) \ - static struct PyModuleDef _##symbol##module = { \ - PyModuleDef_HEAD_INIT, \ - modname, \ - NULL, \ - -1, \ - symbol##_functions, \ - NULL, \ - NULL, \ - NULL, \ - NULL \ -}; \ -PyMODINIT_FUNC PyInit_##symbol(void); \ -PyMODINIT_FUNC PyInit_##symbol(void) \ -{ \ - PyObject *module; \ - module = PyModule_Create(&_##symbol##module); -#define PYGLIB_MODULE_END return module; } -#define PYGLIB_DEFINE_TYPE(typename, symbol, csymbol) \ -PyTypeObject symbol = { \ - PyVarObject_HEAD_INIT(NULL, 0) \ - typename, \ - sizeof(csymbol) \ -}; -#define PYGLIB_REGISTER_TYPE(d, type, name) \ - if (!type.tp_alloc) \ - type.tp_alloc = PyType_GenericAlloc; \ - if (!type.tp_new) \ - type.tp_new = PyType_GenericNew; \ - if (PyType_Ready(&type)) \ - return; \ - PyDict_SetItemString(d, name, (PyObject *)&type); - -#define PYGLIB_PyBaseString_Check PyUnicode_Check - -#define PYGLIB_PyUnicode_Check PyUnicode_Check -#define PYGLIB_PyUnicode_AsString _PyUnicode_AsString -#define PYGLIB_PyUnicode_AsStringAndSize(obj, buf, size) \ - (((*(buf) = _PyUnicode_AsStringAndSize(obj, size)) != NULL) ? 0 : -1) -#define PYGLIB_PyUnicode_FromString PyUnicode_FromString -#define PYGLIB_PyUnicode_FromStringAndSize PyUnicode_FromStringAndSize -#define PYGLIB_PyUnicode_FromFormat PyUnicode_FromFormat -#define PYGLIB_PyUnicode_GET_SIZE PyUnicode_GET_SIZE -#define PYGLIB_PyUnicode_Resize PyUnicode_Resize -#define PYGLIB_PyUnicode_Type PyUnicode_Type -#define PYGLIB_PyUnicode_InternFromString PyUnicode_InternFromString -#define PYGLIB_PyUnicode_InternInPlace PyUnicode_InternInPlace - -#define PYGLIB_PyLong_Check PyLong_Check -#define PYGLIB_PyLong_FromLong PyLong_FromLong -#define PYGLIB_PyLong_AsLong PyLong_AsLong -#define PYGLIB_PyLong_AS_LONG(o) PyLong_AS_LONG((PyObject*)(o)) -#define PYGLIB_PyLongObject PyLongObject -#define PYGLIB_PyLong_Type PyLong_Type - -#define PYGLIB_PyLong_FromUnsignedLong PyLong_FromUnsignedLong -#define PYGLIB_PyLong_AsUnsignedLong(o) PyLong_AsUnsignedLongMask((PyObject*)(o)) - -#define PYGLIB_PyBytes_FromString PyBytes_FromString -#define PYGLIB_PyBytes_FromStringAndSize PyBytes_FromStringAndSize -#define PYGLIB_PyBytes_Resize(o, len) _PyBytes_Resize(o, len) -#define PYGLIB_PyBytes_AsString PyBytes_AsString -#define PYGLIB_PyBytes_Size PyBytes_Size -#define PYGLIB_PyBytes_Check PyBytes_Check - -#define PYGLIB_PyNumber_Long PyNumber_Long - -#endif - -#endif /* __PYGLIB_PYTHON_COMPAT_H__ */ diff --git a/gi/_glib/pyglib.c b/gi/_glib/pyglib.c deleted file mode 100644 index 9753a52..0000000 --- a/gi/_glib/pyglib.c +++ /dev/null @@ -1,475 +0,0 @@ -/* -*- Mode: C; c-set-style: python; c-basic-offset: 4 -*- - * pyglib - Python bindings for GLib toolkit. - * Copyright (C) 1998-2003 James Henstridge - * 2004-2008 Johan Dahlin - * - * 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 - */ - -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif - -#include <Python.h> -#include <pythread.h> -#include "pyglib.h" -#include "pyglib-private.h" -#include "pygoptioncontext.h" -#include "pygoptiongroup.h" - -static struct _PyGLib_Functions *_PyGLib_API; -static PyObject *exception_table = NULL; - -void -pyglib_init(void) -{ - PyObject *glib, *cobject; - - glib = PyImport_ImportModule("gi._glib"); - if (!glib) { - if (PyErr_Occurred()) { - PyObject *type, *value, *traceback; - PyObject *py_orig_exc; - PyErr_Fetch(&type, &value, &traceback); - py_orig_exc = PyObject_Repr(value); - Py_XDECREF(type); - Py_XDECREF(value); - Py_XDECREF(traceback); - PyErr_Format(PyExc_ImportError, - "could not import gi._glib (error was: %s)", - PYGLIB_PyUnicode_AsString(py_orig_exc)); - Py_DECREF(py_orig_exc); - } else { - PyErr_SetString(PyExc_ImportError, - "could not import gi._glib (no error given)"); - } - return; - } - - cobject = PyObject_GetAttrString(glib, "_PyGLib_API"); - if (cobject && PYGLIB_CPointer_Check(cobject)) - _PyGLib_API = (struct _PyGLib_Functions *) PYGLIB_CPointer_GetPointer(cobject, "gi._glib._PyGLib_API"); - else { - PyErr_SetString(PyExc_ImportError, - "could not import gi._glib (could not find _PyGLib_API object)"); - Py_DECREF(glib); - return; - } -} - -void -pyglib_init_internal(PyObject *api) -{ - _PyGLib_API = (struct _PyGLib_Functions *) PYGLIB_CPointer_GetPointer(api, "gi._glib._PyGLib_API"); -} - -/** - * pyglib_error_marshal: - * @error: a pointer to the GError. - * - * Checks to see if @error has been set. If @error has been set, then a - * GLib.GError Python exception object is returned (but not raised). - * - * Returns: a GLib.GError Python exception object, or NULL. - */ -PyObject * -pyglib_error_marshal (GError **error) -{ - PyGILState_STATE state; - PyObject *exc_type; - PyObject *exc_instance; - PyObject *d; - - g_return_val_if_fail(error != NULL, NULL); - - if (*error == NULL) - return NULL; - - state = pyglib_gil_state_ensure(); - - exc_type = _PyGLib_API->gerror_exception; - if (exception_table != NULL) - { - PyObject *item; - item = PyDict_GetItem(exception_table, PYGLIB_PyLong_FromLong((*error)->domain)); - if (item != NULL) - exc_type = item; - } - - exc_instance = PyObject_CallFunction(exc_type, "z", (*error)->message); - - if ((*error)->domain) { - PyObject_SetAttrString(exc_instance, "domain", - d=PYGLIB_PyUnicode_FromString(g_quark_to_string((*error)->domain))); - Py_DECREF(d); - } - else - PyObject_SetAttrString(exc_instance, "domain", Py_None); - - PyObject_SetAttrString(exc_instance, "code", - d=PYGLIB_PyLong_FromLong((*error)->code)); - Py_DECREF(d); - - if ((*error)->message) { - PyObject_SetAttrString(exc_instance, "message", - d=PYGLIB_PyUnicode_FromString((*error)->message)); - Py_DECREF(d); - } else { - PyObject_SetAttrString(exc_instance, "message", Py_None); - } - - pyglib_gil_state_release(state); - - return exc_instance; -} - -/** - * pyglib_error_check: - * @error: a pointer to the GError. - * - * Checks to see if the GError has been set. If the error has been - * set, then the glib.GError Python exception will be raised, and - * the GError cleared. - * - * Returns: True if an error was set. - */ -gboolean -pyglib_error_check(GError **error) -{ - PyGILState_STATE state; - PyObject *exc_instance; - - g_return_val_if_fail(error != NULL, FALSE); - if (*error == NULL) - return FALSE; - - state = pyglib_gil_state_ensure(); - - exc_instance = pyglib_error_marshal (error); - PyErr_SetObject(_PyGLib_API->gerror_exception, exc_instance); - Py_DECREF(exc_instance); - g_clear_error(error); - - pyglib_gil_state_release(state); - - return TRUE; -} - -/** - * pyglib_gerror_exception_check: - * @error: a standard GLib GError ** output parameter - * - * Checks to see if a GError exception has been raised, and if so - * translates the python exception to a standard GLib GError. If the - * raised exception is not a GError then PyErr_Print() is called. - * - * Returns: 0 if no exception has been raised, -1 if it is a - * valid glib.GError, -2 otherwise. - */ -gboolean -pyglib_gerror_exception_check(GError **error) -{ - PyObject *type, *value, *traceback; - PyObject *py_message, *py_domain, *py_code; - const char *bad_gerror_message; - - PyErr_Fetch(&type, &value, &traceback); - if (type == NULL) - return 0; - PyErr_NormalizeException(&type, &value, &traceback); - if (value == NULL) { - PyErr_Restore(type, value, traceback); - PyErr_Print(); - return -2; - } - if (!value || - !PyErr_GivenExceptionMatches(type, - (PyObject *) _PyGLib_API->gerror_exception)) { - PyErr_Restore(type, value, traceback); - PyErr_Print(); - return -2; - } - Py_DECREF(type); - Py_XDECREF(traceback); - - py_message = PyObject_GetAttrString(value, "message"); - if (!py_message || !PYGLIB_PyUnicode_Check(py_message)) { - bad_gerror_message = "gi._glib.GError instances must have a 'message' string attribute"; - Py_XDECREF(py_message); - goto bad_gerror; - } - - py_domain = PyObject_GetAttrString(value, "domain"); - if (!py_domain || !PYGLIB_PyUnicode_Check(py_domain)) { - bad_gerror_message = "gi._glib.GError instances must have a 'domain' string attribute"; - Py_DECREF(py_message); - Py_XDECREF(py_domain); - goto bad_gerror; - } - - py_code = PyObject_GetAttrString(value, "code"); - if (!py_code || !PYGLIB_PyLong_Check(py_code)) { - bad_gerror_message = "gi._glib.GError instances must have a 'code' int attribute"; - Py_DECREF(py_message); - Py_DECREF(py_domain); - Py_XDECREF(py_code); - goto bad_gerror; - } - - g_set_error(error, g_quark_from_string(PYGLIB_PyUnicode_AsString(py_domain)), - PYGLIB_PyLong_AsLong(py_code), "%s", PYGLIB_PyUnicode_AsString(py_message)); - - Py_DECREF(py_message); - Py_DECREF(py_code); - Py_DECREF(py_domain); - return -1; - -bad_gerror: - Py_DECREF(value); - g_set_error(error, g_quark_from_static_string("pyglib"), 0, "%s", bad_gerror_message); - PyErr_SetString(PyExc_ValueError, bad_gerror_message); - PyErr_Print(); - return -2; -} - -/** - * pyglib_register_exception_for_domain: - * @name: name of the exception - * @error_domain: error domain - * - * Registers a new glib.GError exception subclass called #name for - * a specific #domain. This exception will be raised when a GError - * of the same domain is passed in to pyglib_error_check(). - * - * Returns: the new exception - */ -PyObject * -pyglib_register_exception_for_domain(gchar *name, - gint error_domain) -{ - PyObject *exception; - - exception = PyErr_NewException(name, _PyGLib_API->gerror_exception, NULL); - - if (exception_table == NULL) - exception_table = PyDict_New(); - - PyDict_SetItem(exception_table, - PYGLIB_PyLong_FromLong(error_domain), - exception); - - return exception; -} - -/** - * pyg_option_group_transfer_group: - * @group: a GOptionGroup wrapper - * - * This is used to transfer the GOptionGroup to a GOptionContext. After this - * is called, the calle must handle the release of the GOptionGroup. - * - * When #NULL is returned, the GOptionGroup was already transfered. - * - * Returns: Either #NULL or the wrapped GOptionGroup. - */ -GOptionGroup * -pyglib_option_group_transfer_group(PyObject *obj) -{ - PyGOptionGroup *self = (PyGOptionGroup*)obj; - - if (self->is_in_context) - return NULL; - - self->is_in_context = TRUE; - - /* Here we increase the reference count of the PyGOptionGroup, because now - * the GOptionContext holds an reference to us (it is the userdata passed - * to g_option_group_new(). - * - * The GOptionGroup is freed with the GOptionContext. - * - * We set it here because if we would do this in the init method we would - * hold two references and the PyGOptionGroup would never be freed. - */ - Py_INCREF(self); - - return self->group; -} - -/** - * pyglib_option_group_new: - * @group: a GOptionGroup - * - * The returned GOptionGroup can't be used to set any hooks, translation domains - * or add entries. It's only intend is, to use for GOptionContext.add_group(). - * - * Returns: the GOptionGroup wrapper. - */ -PyObject * -pyglib_option_group_new (GOptionGroup *group) -{ - return _PyGLib_API->option_group_new(group); -} - -/** - * pyglib_option_context_new: - * @context: a GOptionContext - * - * Returns: A new GOptionContext wrapper. - */ -PyObject * -pyglib_option_context_new (GOptionContext *context) -{ - return _PyGLib_API->option_context_new(context); -} - - -/****** Private *****/ - -/** - * _pyglib_destroy_notify: - * @user_data: a PyObject pointer. - * - * A function that can be used as a GDestroyNotify callback that will - * call Py_DECREF on the data. - */ -void -_pyglib_destroy_notify(gpointer user_data) -{ - PyObject *obj = (PyObject *)user_data; - PyGILState_STATE state; - - g_return_if_fail (_PyGLib_API != NULL); - - state = pyglib_gil_state_ensure(); - Py_DECREF(obj); - pyglib_gil_state_release(state); -} - -gboolean -_pyglib_handler_marshal(gpointer user_data) -{ - PyObject *tuple, *ret; - gboolean res; - PyGILState_STATE state; - - g_return_val_if_fail(user_data != NULL, FALSE); - - state = pyglib_gil_state_ensure(); - - tuple = (PyObject *)user_data; - ret = PyObject_CallObject(PyTuple_GetItem(tuple, 0), - PyTuple_GetItem(tuple, 1)); - if (!ret) { - PyErr_Print(); - res = FALSE; - } else { - res = PyObject_IsTrue(ret); - Py_DECREF(ret); - } - - pyglib_gil_state_release(state); - - return res; -} - -PyObject* -_pyglib_generic_ptr_richcompare(void* a, void *b, int op) -{ - PyObject *res; - - switch (op) { - - case Py_EQ: - res = (a == b) ? Py_True : Py_False; - break; - - case Py_NE: - res = (a != b) ? Py_True : Py_False; - break; - - case Py_LT: - res = (a < b) ? Py_True : Py_False; - break; - - case Py_LE: - res = (a <= b) ? Py_True : Py_False; - break; - - case Py_GT: - res = (a > b) ? Py_True : Py_False; - break; - - case Py_GE: - res = (a >= b) ? Py_True : Py_False; - break; - - default: - res = Py_NotImplemented; - break; - } - - Py_INCREF(res); - return res; -} - -PyObject* -_pyglib_generic_long_richcompare(long a, long b, int op) -{ - PyObject *res; - - switch (op) { - - case Py_EQ: - res = (a == b) ? Py_True : Py_False; - Py_INCREF(res); - break; - - case Py_NE: - res = (a != b) ? Py_True : Py_False; - Py_INCREF(res); - break; - - - case Py_LT: - res = (a < b) ? Py_True : Py_False; - Py_INCREF(res); - break; - - case Py_LE: - res = (a <= b) ? Py_True : Py_False; - Py_INCREF(res); - break; - - case Py_GT: - res = (a > b) ? Py_True : Py_False; - Py_INCREF(res); - break; - - case Py_GE: - res = (a >= b) ? Py_True : Py_False; - Py_INCREF(res); - break; - - default: - res = Py_NotImplemented; - Py_INCREF(res); - break; - } - - return res; -} - diff --git a/gi/_glib/pyglib.h b/gi/_glib/pyglib.h deleted file mode 100644 index 1c62f1d..0000000 --- a/gi/_glib/pyglib.h +++ /dev/null @@ -1,77 +0,0 @@ -/* -*- Mode: C; c-basic-offset: 4 -*- - * pyglib - Python bindings for GLib toolkit. - * Copyright (C) 1998-2003 James Henstridge - * 2004-2008 Johan Dahlin - * - * 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 - */ - -#ifndef __PYGLIB_H__ -#define __PYGLIB_H__ - -#include <Python.h> - -#include <glib.h> - -G_BEGIN_DECLS - -typedef void (*PyGLibThreadsEnabledFunc) (void); -typedef void (*PyGLibThreadBlockFunc) (void); - -void pyglib_init(void); -void pyglib_init_internal(PyObject *api); - -#ifdef DISABLE_THREADING -# define pyglib_gil_state_ensure() PyGILState_LOCKED -# define pyglib_gil_state_release(state) state -#else -# define pyglib_gil_state_ensure PyGILState_Ensure -# define pyglib_gil_state_release PyGILState_Release -#endif - -/* Deprecated, only available for API compatibility. */ -#define pyg_set_thread_block_funcs(a, b) -#define pyglib_block_threads() -#define pyglib_unblock_threads() - -gboolean pyglib_error_check(GError **error); -PyObject *pyglib_error_marshal (GError **error); -gboolean pyglib_gerror_exception_check(GError **error); -PyObject *pyglib_register_exception_for_domain(gchar *name, - gint error_domain); -PyObject * pyglib_option_context_new(GOptionContext *context); -PyObject * pyglib_option_group_new(GOptionGroup *group); -GOptionGroup * pyglib_option_group_transfer_group(PyObject *self); - -/* Private: for gobject <-> glib interaction only. */ -PyObject* _pyglib_generic_ptr_richcompare(void* a, void *b, int op); -PyObject* _pyglib_generic_long_richcompare(long a, long b, int op); - - -#define PYGLIB_REGISTER_TYPE(d, type, name) \ - if (!type.tp_alloc) \ - type.tp_alloc = PyType_GenericAlloc; \ - if (!type.tp_new) \ - type.tp_new = PyType_GenericNew; \ - if (PyType_Ready(&type)) \ - return; \ - PyDict_SetItemString(d, name, (PyObject *)&type); - - -G_END_DECLS - -#endif /* __PYGLIB_H__ */ - diff --git a/gi/_gobject/Makefile.am b/gi/_gobject/Makefile.am deleted file mode 100644 index 5059ea7..0000000 --- a/gi/_gobject/Makefile.am +++ /dev/null @@ -1,87 +0,0 @@ -AUTOMAKE_OPTIONS = 1.7 -PLATFORM_VERSION = 3.0 - -pkgincludedir = $(includedir)/pygobject-$(PLATFORM_VERSION) -pkginclude_HEADERS = pygobject.h - -extension_cppflags = \ - $(PYTHON_INCLUDES) \ - -DPY_SSIZE_T_CLEAN - -extension_ldflags = \ - -module \ - -avoid-version \ - -shrext $(PYTHON_SO) - -if OS_WIN32 -# Windows requires Python modules to be explicitly linked to libpython. -# Extension modules are shared libaries (.dll), but need to be -# called .pyd for Python to load it as an extension module. -extension_libadd = \ - $(PYTHON_LIBS) - -extension_ldflags += \ - -no-undefined -endif - -pygobjectdir = $(pyexecdir)/gi/_gobject - -pygobject_PYTHON = \ - __init__.py \ - constants.py \ - propertyhelper.py \ - signalhelper.py - -pygobject_LTLIBRARIES = _gobject.la - -_gobject_la_SOURCES = \ - gobjectmodule.c \ - pygboxed.c \ - pygboxed.h \ - pygenum.c \ - pygenum.h \ - pygflags.c \ - pygflags.h \ - pyginterface.c \ - pyginterface.h \ - pygobject.c \ - pygobject.h \ - pygobject-private.h \ - pygparamspec.c \ - pygparamspec.h \ - pygpointer.c \ - pygpointer.h \ - pygtype.c \ - pygtype.h -_gobject_la_CFLAGS = \ - $(extension_cppflags) \ - -I$(top_srcdir)/gi/_glib \ - -I$(top_srcdir)/gi \ - $(GLIB_CFLAGS) \ - $(GI_CFLAGS) -_gi_la_CPPFLAGS = \ - $(extension_cppflags) -_gobject_la_LIBADD = \ - $(extension_libadd) \ - $(GLIB_LIBS) \ - $(GI_LIBS) \ - $(top_builddir)/gi/_glib/libpyglib-gi-2.0-@PYTHON_BASENAME@.la -_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=$(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 deleted file mode 100644 index b057108..0000000 --- a/gi/_gobject/Makefile.in +++ /dev/null @@ -1,923 +0,0 @@ -# Makefile.in generated by automake 1.13.3 from Makefile.am. -# @configure_input@ - -# Copyright (C) 1994-2013 Free Software Foundation, Inc. - -# This Makefile.in is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY, to the extent permitted by law; without -# even the implied warranty of MERCHANTABILITY or FITNESS FOR A -# PARTICULAR PURPOSE. - -@SET_MAKE@ - - -VPATH = @srcdir@ -am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' -am__make_running_with_option = \ - case $${target_option-} in \ - ?) ;; \ - *) echo "am__make_running_with_option: internal error: invalid" \ - "target option '$${target_option-}' specified" >&2; \ - exit 1;; \ - esac; \ - has_opt=no; \ - sane_makeflags=$$MAKEFLAGS; \ - if $(am__is_gnu_make); then \ - sane_makeflags=$$MFLAGS; \ - else \ - case $$MAKEFLAGS in \ - *\\[\ \ ]*) \ - bs=\\; \ - sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ - | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ - esac; \ - fi; \ - skip_next=no; \ - strip_trailopt () \ - { \ - flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ - }; \ - for flg in $$sane_makeflags; do \ - test $$skip_next = yes && { skip_next=no; continue; }; \ - case $$flg in \ - *=*|--*) continue;; \ - -*I) strip_trailopt 'I'; skip_next=yes;; \ - -*I?*) strip_trailopt 'I';; \ - -*O) strip_trailopt 'O'; skip_next=yes;; \ - -*O?*) strip_trailopt 'O';; \ - -*l) strip_trailopt 'l'; skip_next=yes;; \ - -*l?*) strip_trailopt 'l';; \ - -[dEDm]) skip_next=yes;; \ - -[JT]) skip_next=yes;; \ - esac; \ - case $$flg in \ - *$$target_option*) has_opt=yes; break;; \ - esac; \ - done; \ - test $$has_opt = yes -am__make_dryrun = (target_option=n; $(am__make_running_with_option)) -am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) -pkgdatadir = $(datadir)/@PACKAGE@ -pkglibdir = $(libdir)/@PACKAGE@ -pkglibexecdir = $(libexecdir)/@PACKAGE@ -am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd -install_sh_DATA = $(install_sh) -c -m 644 -install_sh_PROGRAM = $(install_sh) -c -install_sh_SCRIPT = $(install_sh) -c -INSTALL_HEADER = $(INSTALL_DATA) -transform = $(program_transform_name) -NORMAL_INSTALL = : -PRE_INSTALL = : -POST_INSTALL = : -NORMAL_UNINSTALL = : -PRE_UNINSTALL = : -POST_UNINSTALL = : -build_triplet = @build@ -host_triplet = @host@ -@OS_WIN32_TRUE@am__append_1 = \ -@OS_WIN32_TRUE@ -no-undefined - -subdir = gi/_gobject -DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ - $(top_srcdir)/depcomp $(pygobject_PYTHON) \ - $(top_srcdir)/py-compile $(pkginclude_HEADERS) -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 -am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ - $(ACLOCAL_M4) -mkinstalldirs = $(install_sh) -d -CONFIG_HEADER = $(top_builddir)/config.h -CONFIG_CLEAN_FILES = -CONFIG_CLEAN_VPATH_FILES = -am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; -am__vpath_adj = case $$p in \ - $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ - *) f=$$p;; \ - esac; -am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; -am__install_max = 40 -am__nobase_strip_setup = \ - srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` -am__nobase_strip = \ - for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" -am__nobase_list = $(am__nobase_strip_setup); \ - for p in $$list; do echo "$$p $$p"; done | \ - sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ - $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ - if (++n[$$2] == $(am__install_max)) \ - { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ - END { for (dir in files) print dir, files[dir] }' -am__base_list = \ - sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ - sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' -am__uninstall_files_from_dir = { \ - test -z "$$files" \ - || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ - || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ - $(am__cd) "$$dir" && rm -f $$files; }; \ - } -am__installdirs = "$(DESTDIR)$(pygobjectdir)" \ - "$(DESTDIR)$(pygobjectdir)" "$(DESTDIR)$(pkgincludedir)" -LTLIBRARIES = $(pygobject_LTLIBRARIES) -am__DEPENDENCIES_1 = -@OS_WIN32_TRUE@am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1) -_gobject_la_DEPENDENCIES = $(am__DEPENDENCIES_2) $(am__DEPENDENCIES_1) \ - $(am__DEPENDENCIES_1) \ - $(top_builddir)/gi/_glib/libpyglib-gi-2.0-@PYTHON_BASENAME@.la -am__gobject_la_OBJECTS = _gobject_la-gobjectmodule.lo \ - _gobject_la-pygboxed.lo _gobject_la-pygenum.lo \ - _gobject_la-pygflags.lo _gobject_la-pyginterface.lo \ - _gobject_la-pygobject.lo _gobject_la-pygparamspec.lo \ - _gobject_la-pygpointer.lo _gobject_la-pygtype.lo -_gobject_la_OBJECTS = $(am__gobject_la_OBJECTS) -AM_V_lt = $(am__v_lt_@AM_V@) -am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) -am__v_lt_0 = --silent -am__v_lt_1 = -_gobject_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ - $(LIBTOOLFLAGS) --mode=link $(CCLD) $(_gobject_la_CFLAGS) \ - $(CFLAGS) $(_gobject_la_LDFLAGS) $(LDFLAGS) -o $@ -AM_V_P = $(am__v_P_@AM_V@) -am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) -am__v_P_0 = false -am__v_P_1 = : -AM_V_GEN = $(am__v_GEN_@AM_V@) -am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) -am__v_GEN_0 = @echo " GEN " $@; -am__v_GEN_1 = -AM_V_at = $(am__v_at_@AM_V@) -am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) -am__v_at_0 = @ -am__v_at_1 = -DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) -depcomp = $(SHELL) $(top_srcdir)/depcomp -am__depfiles_maybe = depfiles -am__mv = mv -f -COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ - $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ - $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ - $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ - $(AM_CFLAGS) $(CFLAGS) -AM_V_CC = $(am__v_CC_@AM_V@) -am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) -am__v_CC_0 = @echo " CC " $@; -am__v_CC_1 = -CCLD = $(CC) -LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ - $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ - $(AM_LDFLAGS) $(LDFLAGS) -o $@ -AM_V_CCLD = $(am__v_CCLD_@AM_V@) -am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) -am__v_CCLD_0 = @echo " CCLD " $@; -am__v_CCLD_1 = -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) -am__pep3147_tweak = \ - sed -e 's|\.py$$||' -e 's|[^/]*$$|__pycache__/&.*.py|' -py_compile = $(top_srcdir)/py-compile -HEADERS = $(pkginclude_HEADERS) -am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) -# Read a list of newline-separated strings from the standard input, -# and print each of them once, without duplicates. Input order is -# *not* preserved. -am__uniquify_input = $(AWK) '\ - BEGIN { nonempty = 0; } \ - { items[$$0] = 1; nonempty = 1; } \ - END { if (nonempty) { for (i in items) print i; }; } \ -' -# Make sure the list of sources is unique. This is necessary because, -# e.g., the same source file might be shared among _SOURCES variables -# for different programs/libraries. -am__define_uniq_tagged_files = \ - list='$(am__tagged_files)'; \ - unique=`for i in $$list; do \ - if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ - done | $(am__uniquify_input)` -ETAGS = etags -CTAGS = ctags -DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) -pkgincludedir = $(includedir)/pygobject-$(PLATFORM_VERSION) -ACLOCAL = @ACLOCAL@ -ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@ -AMTAR = @AMTAR@ -AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ -AR = @AR@ -AS = @AS@ -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@ -DATADIR = @DATADIR@ -DEFS = @DEFS@ -DEPDIR = @DEPDIR@ -DLLTOOL = @DLLTOOL@ -DSYMUTIL = @DSYMUTIL@ -DUMPBIN = @DUMPBIN@ -ECHO_C = @ECHO_C@ -ECHO_N = @ECHO_N@ -ECHO_T = @ECHO_T@ -EGREP = @EGREP@ -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@ -GI_DATADIR = @GI_DATADIR@ -GI_LIBS = @GI_LIBS@ -GLIB_CFLAGS = @GLIB_CFLAGS@ -GLIB_COMPILE_RESOURCES = @GLIB_COMPILE_RESOURCES@ -GLIB_GENMARSHAL = @GLIB_GENMARSHAL@ -GLIB_LIBS = @GLIB_LIBS@ -GLIB_MKENUMS = @GLIB_MKENUMS@ -GOBJECT_QUERY = @GOBJECT_QUERY@ -GREP = @GREP@ -INSTALL = @INSTALL@ -INSTALL_DATA = @INSTALL_DATA@ -INSTALL_PROGRAM = @INSTALL_PROGRAM@ -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@ -LIBOBJS = @LIBOBJS@ -LIBS = @LIBS@ -LIBTOOL = @LIBTOOL@ -LIPO = @LIPO@ -LN_S = @LN_S@ -LTLIBOBJS = @LTLIBOBJS@ -MAKEINFO = @MAKEINFO@ -MANIFEST_TOOL = @MANIFEST_TOOL@ -MKDIR_P = @MKDIR_P@ -NM = @NM@ -NMEDIT = @NMEDIT@ -OBJDUMP = @OBJDUMP@ -OBJEXT = @OBJEXT@ -OTOOL = @OTOOL@ -OTOOL64 = @OTOOL64@ -PACKAGE = @PACKAGE@ -PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ -PACKAGE_NAME = @PACKAGE_NAME@ -PACKAGE_STRING = @PACKAGE_STRING@ -PACKAGE_TARNAME = @PACKAGE_TARNAME@ -PACKAGE_URL = @PACKAGE_URL@ -PACKAGE_VERSION = @PACKAGE_VERSION@ -PATH_SEPARATOR = @PATH_SEPARATOR@ -PKG_CONFIG = @PKG_CONFIG@ -PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ -PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ -PLATFORM = @PLATFORM@ -PYCAIRO_CFLAGS = @PYCAIRO_CFLAGS@ -PYCAIRO_LIBS = @PYCAIRO_LIBS@ -PYGOBJECT_MAJOR_VERSION = @PYGOBJECT_MAJOR_VERSION@ -PYGOBJECT_MICRO_VERSION = @PYGOBJECT_MICRO_VERSION@ -PYGOBJECT_MINOR_VERSION = @PYGOBJECT_MINOR_VERSION@ -PYTHON = @PYTHON@ -PYTHON_BASENAME = @PYTHON_BASENAME@ -PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ -PYTHON_INCLUDES = @PYTHON_INCLUDES@ -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@ -SET_MAKE = @SET_MAKE@ -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@ -abs_top_srcdir = @abs_top_srcdir@ -ac_ct_AR = @ac_ct_AR@ -ac_ct_CC = @ac_ct_CC@ -ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ -am__include = @am__include@ -am__leading_dot = @am__leading_dot@ -am__quote = @am__quote@ -am__tar = @am__tar@ -am__untar = @am__untar@ -bindir = @bindir@ -build = @build@ -build_alias = @build_alias@ -build_cpu = @build_cpu@ -build_os = @build_os@ -build_vendor = @build_vendor@ -builddir = @builddir@ -datadir = @datadir@ -datarootdir = @datarootdir@ -docdir = @docdir@ -dvidir = @dvidir@ -exec_prefix = @exec_prefix@ -host = @host@ -host_alias = @host_alias@ -host_cpu = @host_cpu@ -host_os = @host_os@ -host_vendor = @host_vendor@ -htmldir = @htmldir@ -includedir = @includedir@ -infodir = @infodir@ -install_sh = @install_sh@ -libdir = @libdir@ -libexecdir = @libexecdir@ -localedir = @localedir@ -localstatedir = @localstatedir@ -mandir = @mandir@ -mkdir_p = @mkdir_p@ -oldincludedir = @oldincludedir@ -pdfdir = @pdfdir@ -pkgpyexecdir = @pkgpyexecdir@ -pkgpythondir = @pkgpythondir@ -prefix = @prefix@ -program_transform_name = @program_transform_name@ -psdir = @psdir@ -pyexecdir = @pyexecdir@ -pythondir = @pythondir@ -sbindir = @sbindir@ -sharedstatedir = @sharedstatedir@ -srcdir = @srcdir@ -sysconfdir = @sysconfdir@ -target_alias = @target_alias@ -top_build_prefix = @top_build_prefix@ -top_builddir = @top_builddir@ -top_srcdir = @top_srcdir@ -AUTOMAKE_OPTIONS = 1.7 -PLATFORM_VERSION = 3.0 -pkginclude_HEADERS = pygobject.h -extension_cppflags = \ - $(PYTHON_INCLUDES) \ - -DPY_SSIZE_T_CLEAN - -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 -# called .pyd for Python to load it as an extension module. -@OS_WIN32_TRUE@extension_libadd = \ -@OS_WIN32_TRUE@ $(PYTHON_LIBS) - -pygobjectdir = $(pyexecdir)/gi/_gobject -pygobject_PYTHON = \ - __init__.py \ - constants.py \ - propertyhelper.py \ - signalhelper.py - -pygobject_LTLIBRARIES = _gobject.la -_gobject_la_SOURCES = \ - gobjectmodule.c \ - pygboxed.c \ - pygboxed.h \ - pygenum.c \ - pygenum.h \ - pygflags.c \ - pygflags.h \ - pyginterface.c \ - pyginterface.h \ - pygobject.c \ - pygobject.h \ - pygobject-private.h \ - pygparamspec.c \ - pygparamspec.h \ - pygpointer.c \ - pygpointer.h \ - pygtype.c \ - pygtype.h - -_gobject_la_CFLAGS = \ - $(extension_cppflags) \ - -I$(top_srcdir)/gi/_glib \ - -I$(top_srcdir)/gi \ - $(GLIB_CFLAGS) \ - $(GI_CFLAGS) - -_gi_la_CPPFLAGS = \ - $(extension_cppflags) - -_gobject_la_LIBADD = \ - $(extension_libadd) \ - $(GLIB_LIBS) \ - $(GI_LIBS) \ - $(top_builddir)/gi/_glib/libpyglib-gi-2.0-@PYTHON_BASENAME@.la - -_gobject_la_LDFLAGS = \ - $(extension_ldflags) \ - -export-symbols-regex "_gobject|PyInit__gobject" - -all: all-am - -.SUFFIXES: -.SUFFIXES: .c .lo .o .obj -$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) - @for dep in $?; do \ - case '$(am__configure_deps)' in \ - *$$dep*) \ - ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ - && { if test -f $@; then exit 0; else break; fi; }; \ - exit 1;; \ - esac; \ - done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign gi/_gobject/Makefile'; \ - $(am__cd) $(top_srcdir) && \ - $(AUTOMAKE) --foreign gi/_gobject/Makefile -.PRECIOUS: Makefile -Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status - @case '$?' in \ - *config.status*) \ - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ - *) \ - echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ - cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ - esac; - -$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh - -$(top_srcdir)/configure: $(am__configure_deps) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh -$(ACLOCAL_M4): $(am__aclocal_m4_deps) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh -$(am__aclocal_m4_deps): - -install-pygobjectLTLIBRARIES: $(pygobject_LTLIBRARIES) - @$(NORMAL_INSTALL) - @list='$(pygobject_LTLIBRARIES)'; test -n "$(pygobjectdir)" || list=; \ - list2=; for p in $$list; do \ - if test -f $$p; then \ - list2="$$list2 $$p"; \ - 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)"; \ - } - -uninstall-pygobjectLTLIBRARIES: - @$(NORMAL_UNINSTALL) - @list='$(pygobject_LTLIBRARIES)'; test -n "$(pygobjectdir)" || list=; \ - for p in $$list; do \ - $(am__strip_dir) \ - echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(pygobjectdir)/$$f'"; \ - $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(pygobjectdir)/$$f"; \ - done - -clean-pygobjectLTLIBRARIES: - -test -z "$(pygobject_LTLIBRARIES)" || rm -f $(pygobject_LTLIBRARIES) - @list='$(pygobject_LTLIBRARIES)'; \ - locs=`for p in $$list; do echo $$p; done | \ - sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ - sort -u`; \ - test -z "$$locs" || { \ - echo rm -f $${locs}; \ - rm -f $${locs}; \ - } - -_gobject.la: $(_gobject_la_OBJECTS) $(_gobject_la_DEPENDENCIES) $(EXTRA__gobject_la_DEPENDENCIES) - $(AM_V_CCLD)$(_gobject_la_LINK) -rpath $(pygobjectdir) $(_gobject_la_OBJECTS) $(_gobject_la_LIBADD) $(LIBS) - -mostlyclean-compile: - -rm -f *.$(OBJEXT) - -distclean-compile: - -rm -f *.tab.c - -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/_gobject_la-gobjectmodule.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/_gobject_la-pygboxed.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/_gobject_la-pygenum.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/_gobject_la-pygflags.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/_gobject_la-pyginterface.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/_gobject_la-pygobject.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/_gobject_la-pygparamspec.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/_gobject_la-pygpointer.Plo@am__quote@ -@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/_gobject_la-pygtype.Plo@am__quote@ - -.c.o: -@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c $< - -.c.obj: -@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c `$(CYGPATH_W) '$<'` - -.c.lo: -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< - -_gobject_la-gobjectmodule.lo: gobjectmodule.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(_gobject_la_CFLAGS) $(CFLAGS) -MT _gobject_la-gobjectmodule.lo -MD -MP -MF $(DEPDIR)/_gobject_la-gobjectmodule.Tpo -c -o _gobject_la-gobjectmodule.lo `test -f 'gobjectmodule.c' || echo '$(srcdir)/'`gobjectmodule.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/_gobject_la-gobjectmodule.Tpo $(DEPDIR)/_gobject_la-gobjectmodule.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='gobjectmodule.c' object='_gobject_la-gobjectmodule.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(_gobject_la_CFLAGS) $(CFLAGS) -c -o _gobject_la-gobjectmodule.lo `test -f 'gobjectmodule.c' || echo '$(srcdir)/'`gobjectmodule.c - -_gobject_la-pygboxed.lo: pygboxed.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(_gobject_la_CFLAGS) $(CFLAGS) -MT _gobject_la-pygboxed.lo -MD -MP -MF $(DEPDIR)/_gobject_la-pygboxed.Tpo -c -o _gobject_la-pygboxed.lo `test -f 'pygboxed.c' || echo '$(srcdir)/'`pygboxed.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/_gobject_la-pygboxed.Tpo $(DEPDIR)/_gobject_la-pygboxed.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pygboxed.c' object='_gobject_la-pygboxed.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(_gobject_la_CFLAGS) $(CFLAGS) -c -o _gobject_la-pygboxed.lo `test -f 'pygboxed.c' || echo '$(srcdir)/'`pygboxed.c - -_gobject_la-pygenum.lo: pygenum.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(_gobject_la_CFLAGS) $(CFLAGS) -MT _gobject_la-pygenum.lo -MD -MP -MF $(DEPDIR)/_gobject_la-pygenum.Tpo -c -o _gobject_la-pygenum.lo `test -f 'pygenum.c' || echo '$(srcdir)/'`pygenum.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/_gobject_la-pygenum.Tpo $(DEPDIR)/_gobject_la-pygenum.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pygenum.c' object='_gobject_la-pygenum.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(_gobject_la_CFLAGS) $(CFLAGS) -c -o _gobject_la-pygenum.lo `test -f 'pygenum.c' || echo '$(srcdir)/'`pygenum.c - -_gobject_la-pygflags.lo: pygflags.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(_gobject_la_CFLAGS) $(CFLAGS) -MT _gobject_la-pygflags.lo -MD -MP -MF $(DEPDIR)/_gobject_la-pygflags.Tpo -c -o _gobject_la-pygflags.lo `test -f 'pygflags.c' || echo '$(srcdir)/'`pygflags.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/_gobject_la-pygflags.Tpo $(DEPDIR)/_gobject_la-pygflags.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pygflags.c' object='_gobject_la-pygflags.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(_gobject_la_CFLAGS) $(CFLAGS) -c -o _gobject_la-pygflags.lo `test -f 'pygflags.c' || echo '$(srcdir)/'`pygflags.c - -_gobject_la-pyginterface.lo: pyginterface.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(_gobject_la_CFLAGS) $(CFLAGS) -MT _gobject_la-pyginterface.lo -MD -MP -MF $(DEPDIR)/_gobject_la-pyginterface.Tpo -c -o _gobject_la-pyginterface.lo `test -f 'pyginterface.c' || echo '$(srcdir)/'`pyginterface.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/_gobject_la-pyginterface.Tpo $(DEPDIR)/_gobject_la-pyginterface.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pyginterface.c' object='_gobject_la-pyginterface.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(_gobject_la_CFLAGS) $(CFLAGS) -c -o _gobject_la-pyginterface.lo `test -f 'pyginterface.c' || echo '$(srcdir)/'`pyginterface.c - -_gobject_la-pygobject.lo: pygobject.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(_gobject_la_CFLAGS) $(CFLAGS) -MT _gobject_la-pygobject.lo -MD -MP -MF $(DEPDIR)/_gobject_la-pygobject.Tpo -c -o _gobject_la-pygobject.lo `test -f 'pygobject.c' || echo '$(srcdir)/'`pygobject.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/_gobject_la-pygobject.Tpo $(DEPDIR)/_gobject_la-pygobject.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pygobject.c' object='_gobject_la-pygobject.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(_gobject_la_CFLAGS) $(CFLAGS) -c -o _gobject_la-pygobject.lo `test -f 'pygobject.c' || echo '$(srcdir)/'`pygobject.c - -_gobject_la-pygparamspec.lo: pygparamspec.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(_gobject_la_CFLAGS) $(CFLAGS) -MT _gobject_la-pygparamspec.lo -MD -MP -MF $(DEPDIR)/_gobject_la-pygparamspec.Tpo -c -o _gobject_la-pygparamspec.lo `test -f 'pygparamspec.c' || echo '$(srcdir)/'`pygparamspec.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/_gobject_la-pygparamspec.Tpo $(DEPDIR)/_gobject_la-pygparamspec.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pygparamspec.c' object='_gobject_la-pygparamspec.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(_gobject_la_CFLAGS) $(CFLAGS) -c -o _gobject_la-pygparamspec.lo `test -f 'pygparamspec.c' || echo '$(srcdir)/'`pygparamspec.c - -_gobject_la-pygpointer.lo: pygpointer.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(_gobject_la_CFLAGS) $(CFLAGS) -MT _gobject_la-pygpointer.lo -MD -MP -MF $(DEPDIR)/_gobject_la-pygpointer.Tpo -c -o _gobject_la-pygpointer.lo `test -f 'pygpointer.c' || echo '$(srcdir)/'`pygpointer.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/_gobject_la-pygpointer.Tpo $(DEPDIR)/_gobject_la-pygpointer.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pygpointer.c' object='_gobject_la-pygpointer.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(_gobject_la_CFLAGS) $(CFLAGS) -c -o _gobject_la-pygpointer.lo `test -f 'pygpointer.c' || echo '$(srcdir)/'`pygpointer.c - -_gobject_la-pygtype.lo: pygtype.c -@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(_gobject_la_CFLAGS) $(CFLAGS) -MT _gobject_la-pygtype.lo -MD -MP -MF $(DEPDIR)/_gobject_la-pygtype.Tpo -c -o _gobject_la-pygtype.lo `test -f 'pygtype.c' || echo '$(srcdir)/'`pygtype.c -@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/_gobject_la-pygtype.Tpo $(DEPDIR)/_gobject_la-pygtype.Plo -@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='pygtype.c' object='_gobject_la-pygtype.lo' libtool=yes @AMDEPBACKSLASH@ -@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ -@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(_gobject_la_CFLAGS) $(CFLAGS) -c -o _gobject_la-pygtype.lo `test -f 'pygtype.c' || echo '$(srcdir)/'`pygtype.c - -mostlyclean-libtool: - -rm -f *.lo - -clean-libtool: - -rm -rf .libs _libs -install-pygobjectPYTHON: $(pygobject_PYTHON) - @$(NORMAL_INSTALL) - @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 \ - $(am__strip_dir) \ - dlist="$$dlist $$f"; \ - list2="$$list2 $$b$$p"; \ - else :; fi; \ - done; \ - for file in $$list2; do echo $$file; done | $(am__base_list) | \ - while read files; do \ - echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pygobjectdir)'"; \ - $(INSTALL_DATA) $$files "$(DESTDIR)$(pygobjectdir)" || exit $$?; \ - done || exit $$?; \ - if test -n "$$dlist"; then \ - $(am__py_compile) --destdir "$(DESTDIR)" \ - --basedir "$(pygobjectdir)" $$dlist; \ - else :; fi - -uninstall-pygobjectPYTHON: - @$(NORMAL_UNINSTALL) - @list='$(pygobject_PYTHON)'; test -n "$(pygobjectdir)" || list=; \ - py_files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ - test -n "$$py_files" || exit 0; \ - dir='$(DESTDIR)$(pygobjectdir)'; \ - pyc_files=`echo "$$py_files" | sed 's|$$|c|'`; \ - pyo_files=`echo "$$py_files" | sed 's|$$|o|'`; \ - py_files_pep3147=`echo "$$py_files" | $(am__pep3147_tweak)`; \ - echo "$$py_files_pep3147";\ - pyc_files_pep3147=`echo "$$py_files_pep3147" | sed 's|$$|c|'`; \ - pyo_files_pep3147=`echo "$$py_files_pep3147" | sed 's|$$|o|'`; \ - st=0; \ - for files in \ - "$$py_files" \ - "$$pyc_files" \ - "$$pyo_files" \ - "$$pyc_files_pep3147" \ - "$$pyo_files_pep3147" \ - ; do \ - $(am__uninstall_files_from_dir) || st=$$?; \ - done; \ - exit $$st -install-pkgincludeHEADERS: $(pkginclude_HEADERS) - @$(NORMAL_INSTALL) - @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"; \ - done | $(am__base_list) | \ - while read files; do \ - echo " $(INSTALL_HEADER) $$files '$(DESTDIR)$(pkgincludedir)'"; \ - $(INSTALL_HEADER) $$files "$(DESTDIR)$(pkgincludedir)" || exit $$?; \ - done - -uninstall-pkgincludeHEADERS: - @$(NORMAL_UNINSTALL) - @list='$(pkginclude_HEADERS)'; test -n "$(pkgincludedir)" || list=; \ - files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ - dir='$(DESTDIR)$(pkgincludedir)'; $(am__uninstall_files_from_dir) - -ID: $(am__tagged_files) - $(am__define_uniq_tagged_files); mkid -fID $$unique -tags: tags-am -TAGS: tags - -tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) - set x; \ - here=`pwd`; \ - $(am__define_uniq_tagged_files); \ - shift; \ - if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ - test -n "$$unique" || unique=$$empty_fix; \ - if test $$# -gt 0; then \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - "$$@" $$unique; \ - else \ - $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ - $$unique; \ - fi; \ - fi -ctags: ctags-am - -CTAGS: ctags -ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) - $(am__define_uniq_tagged_files); \ - test -z "$(CTAGS_ARGS)$$unique" \ - || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ - $$unique - -GTAGS: - here=`$(am__cd) $(top_builddir) && pwd` \ - && $(am__cd) $(top_srcdir) \ - && gtags -i $(GTAGS_ARGS) "$$here" -cscopelist: cscopelist-am - -cscopelist-am: $(am__tagged_files) - list='$(am__tagged_files)'; \ - case "$(srcdir)" in \ - [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ - *) sdir=$(subdir)/$(srcdir) ;; \ - esac; \ - for i in $$list; do \ - if test -f "$$i"; then \ - echo "$(subdir)/$$i"; \ - else \ - echo "$$sdir/$$i"; \ - fi; \ - done >> $(top_builddir)/cscope.files - -distclean-tags: - -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags - -distdir: $(DISTFILES) - @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - list='$(DISTFILES)'; \ - dist_files=`for file in $$list; do echo $$file; done | \ - sed -e "s|^$$srcdirstrip/||;t" \ - -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ - case $$dist_files in \ - */*) $(MKDIR_P) `echo "$$dist_files" | \ - sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ - sort -u` ;; \ - esac; \ - for file in $$dist_files; do \ - if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ - if test -d $$d/$$file; then \ - dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ - if test -d "$(distdir)/$$file"; then \ - find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ - fi; \ - if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ - cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ - find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ - fi; \ - cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ - else \ - test -f "$(distdir)/$$file" \ - || cp -p $$d/$$file "$(distdir)/$$file" \ - || exit 1; \ - fi; \ - done -check-am: all-am - $(MAKE) $(AM_MAKEFLAGS) check-local -check: check-am -all-am: Makefile $(LTLIBRARIES) $(HEADERS) -installdirs: - for dir in "$(DESTDIR)$(pygobjectdir)" "$(DESTDIR)$(pygobjectdir)" "$(DESTDIR)$(pkgincludedir)"; do \ - test -z "$$dir" || $(MKDIR_P) "$$dir"; \ - done -install: install-am -install-exec: install-exec-am -install-data: install-data-am -uninstall: uninstall-am - -install-am: all-am - @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am - -installcheck: installcheck-am -install-strip: - if test -z '$(STRIP)'; then \ - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ - install; \ - else \ - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ - "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ - fi -mostlyclean-generic: - -clean-generic: - -distclean-generic: - -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) - -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) - -maintainer-clean-generic: - @echo "This command is intended for maintainers to use" - @echo "it deletes files that may require special tools to rebuild." -clean: clean-am - -clean-am: clean-generic clean-libtool clean-local \ - clean-pygobjectLTLIBRARIES mostlyclean-am - -distclean: distclean-am - -rm -rf ./$(DEPDIR) - -rm -f Makefile -distclean-am: clean-am distclean-compile distclean-generic \ - distclean-tags - -dvi: dvi-am - -dvi-am: - -html: html-am - -html-am: - -info: info-am - -info-am: - -install-data-am: install-pkgincludeHEADERS \ - install-pygobjectLTLIBRARIES install-pygobjectPYTHON - -install-dvi: install-dvi-am - -install-dvi-am: - -install-exec-am: - -install-html: install-html-am - -install-html-am: - -install-info: install-info-am - -install-info-am: - -install-man: - -install-pdf: install-pdf-am - -install-pdf-am: - -install-ps: install-ps-am - -install-ps-am: - -installcheck-am: - -maintainer-clean: maintainer-clean-am - -rm -rf ./$(DEPDIR) - -rm -f Makefile -maintainer-clean-am: distclean-am maintainer-clean-generic - -mostlyclean: mostlyclean-am - -mostlyclean-am: mostlyclean-compile mostlyclean-generic \ - mostlyclean-libtool - -pdf: pdf-am - -pdf-am: - -ps: ps-am - -ps-am: - -uninstall-am: uninstall-pkgincludeHEADERS \ - uninstall-pygobjectLTLIBRARIES uninstall-pygobjectPYTHON - -.MAKE: check-am install-am install-strip - -.PHONY: CTAGS GTAGS TAGS all all-am check check-am check-local clean \ - clean-generic clean-libtool clean-local \ - clean-pygobjectLTLIBRARIES cscopelist-am ctags ctags-am \ - distclean distclean-compile distclean-generic \ - distclean-libtool distclean-tags distdir dvi dvi-am html \ - html-am info info-am install install-am install-data \ - install-data-am install-dvi install-dvi-am install-exec \ - install-exec-am install-html install-html-am install-info \ - install-info-am install-man install-pdf install-pdf-am \ - install-pkgincludeHEADERS install-ps install-ps-am \ - install-pygobjectLTLIBRARIES install-pygobjectPYTHON \ - install-strip installcheck installcheck-am installdirs \ - maintainer-clean maintainer-clean-generic mostlyclean \ - mostlyclean-compile mostlyclean-generic mostlyclean-libtool \ - pdf pdf-am ps ps-am tags tags-am uninstall uninstall-am \ - uninstall-pkgincludeHEADERS uninstall-pygobjectLTLIBRARIES \ - uninstall-pygobjectPYTHON - - -# 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=$(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. -.NOEXPORT: diff --git a/gi/_gobject/__init__.py b/gi/_gobject/__init__.py deleted file mode 100644 index d3ea0e0..0000000 --- a/gi/_gobject/__init__.py +++ /dev/null @@ -1,60 +0,0 @@ -# -*- Mode: Python; py-indent-offset: 4 -*- -# pygobject - Python bindings for the GObject library -# Copyright (C) 2006-2012 Johan Dahlin -# -# gobject/__init__.py: initialisation file for gobject module -# -# 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 - -# this can go when things are a little further along - -import sys - -# we can't have pygobject 2 loaded at the same time we load the internal _gobject -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 . import _gobject -from . import propertyhelper -from . import signalhelper - -GObject = _gobject.GObject -GType = _gobject.GType -_PyGObject_API = _gobject._PyGObject_API -pygobject_version = _gobject.pygobject_version - - -class GObjectMeta(type): - "Metaclass for automatically registering GObject classes" - def __init__(cls, name, bases, dict_): - type.__init__(cls, name, bases, dict_) - propertyhelper.install_properties(cls) - signalhelper.install_signals(cls) - cls._type_register(cls.__dict__) - - def _type_register(cls, namespace): - ## don't register the class if already registered - if '__gtype__' in namespace: - return - - # Do not register a new GType for the overrides, as this would sort of - # defeat the purpose of overrides... - if cls.__module__.startswith('gi.overrides.'): - return - - _gobject.type_register(cls, namespace.get('__gtype_name__')) - -_gobject._install_metaclass(GObjectMeta) diff --git a/gi/_gobject/constants.py b/gi/_gobject/constants.py deleted file mode 100644 index 9565a66..0000000 --- a/gi/_gobject/constants.py +++ /dev/null @@ -1,49 +0,0 @@ -# -*- Mode: Python; py-indent-offset: 4 -*- -# pygobject - Python bindings for the GObject library -# Copyright (C) 2006-2007 Johan Dahlin -# -# gobject/constants.py: GObject type constants -# -# 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 - -from . import _gobject - -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') -TYPE_UCHAR = _gobject.type_from_name('guchar') -TYPE_BOOLEAN = _gobject.type_from_name('gboolean') -TYPE_INT = _gobject.type_from_name('gint') -TYPE_UINT = _gobject.type_from_name('guint') -TYPE_LONG = _gobject.type_from_name('glong') -TYPE_ULONG = _gobject.type_from_name('gulong') -TYPE_INT64 = _gobject.type_from_name('gint64') -TYPE_UINT64 = _gobject.type_from_name('guint64') -TYPE_ENUM = _gobject.type_from_name('GEnum') -TYPE_FLAGS = _gobject.type_from_name('GFlags') -TYPE_FLOAT = _gobject.type_from_name('gfloat') -TYPE_DOUBLE = _gobject.type_from_name('gdouble') -TYPE_STRING = _gobject.type_from_name('gchararray') -TYPE_POINTER = _gobject.type_from_name('gpointer') -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 diff --git a/gi/_gobject/gobjectmodule.c b/gi/_gobject/gobjectmodule.c deleted file mode 100644 index ac37904..0000000 --- a/gi/_gobject/gobjectmodule.c +++ /dev/null @@ -1,2220 +0,0 @@ -/* -*- Mode: C; c-basic-offset: 4 -*- - * pygtk- Python bindings for the GTK toolkit. - * Copyright (C) 1998-2003 James Henstridge - * - * gobjectmodule.c: wrapper for the gobject library. - * - * 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 - */ - -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif - -#include <gobject/gvaluecollector.h> -#include <girepository.h> -#include <pyglib.h> -#include <pythread.h> -#include "pygobject-private.h" -#include "pygboxed.h" -#include "pygenum.h" -#include "pygflags.h" -#include "pyginterface.h" -#include "pygparamspec.h" -#include "pygpointer.h" -#include "pygtype.h" - -static GHashTable *log_handlers = NULL; -static gboolean log_handlers_disabled = FALSE; - -static void pyg_flags_add_constants(PyObject *module, GType flags_type, - const gchar *strip_prefix); - - -/* -------------- GDK threading hooks ---------------------------- */ - -/** - * pyg_set_thread_block_funcs: - * Deprecated, only available for ABI compatibility. - */ -static void -_pyg_set_thread_block_funcs (PyGThreadBlockFunc block_threads_func, - PyGThreadBlockFunc 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); -} - -/** - * pyg_destroy_notify: - * @user_data: a PyObject pointer. - * - * A function that can be used as a GDestroyNotify callback that will - * call Py_DECREF on the data. - */ -void -pyg_destroy_notify(gpointer user_data) -{ - PyObject *obj = (PyObject *)user_data; - PyGILState_STATE state; - - state = pyglib_gil_state_ensure(); - Py_DECREF(obj); - pyglib_gil_state_release(state); -} - - -/* ---------------- gobject module functions -------------------- */ - -static PyObject * -pyg_type_name (PyObject *self, PyObject *args) -{ - PyObject *gtype; - GType type; - const gchar *name; - -#if 0 - if (PyErr_Warn(PyExc_DeprecationWarning, - "gobject.type_name is deprecated; " - "use GType.name instead")) - return NULL; -#endif - - if (!PyArg_ParseTuple(args, "O:gobject.type_name", >ype)) - return NULL; - if ((type = pyg_type_from_object(gtype)) == 0) - return NULL; - name = g_type_name(type); - if (name) - return PYGLIB_PyUnicode_FromString(name); - PyErr_SetString(PyExc_RuntimeError, "unknown typecode"); - return NULL; -} - -static PyObject * -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; " - "use GType.from_name instead")) - return NULL; -#endif - if (!PyArg_ParseTuple(args, "s:gobject.type_from_name", &name)) - return NULL; - 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(repr), - name); - Py_DECREF(repr); - return NULL; -} - -static PyObject * -pyg_type_is_a (PyObject *self, PyObject *args) -{ - PyObject *gtype, *gparent; - GType type, parent; -#if 0 - if (PyErr_Warn(PyExc_DeprecationWarning, - "gobject.type_is_a is deprecated; " - "use GType.is_a instead")) - return NULL; -#endif - if (!PyArg_ParseTuple(args, "OO:gobject.type_is_a", >ype, &gparent)) - return NULL; - if ((type = pyg_type_from_object(gtype)) == 0) - return NULL; - if ((parent = pyg_type_from_object(gparent)) == 0) - return NULL; - return PyBool_FromLong(g_type_is_a(type, parent)); -} - -static void -pyg_object_set_property (GObject *object, guint property_id, - const GValue *value, GParamSpec *pspec) -{ - PyObject *object_wrapper, *retval; - PyObject *py_pspec, *py_value; - PyGILState_STATE state; - - state = pyglib_gil_state_ensure(); - - object_wrapper = pygobject_new(object); - - if (object_wrapper == NULL) { - pyglib_gil_state_release(state); - return; - } - - py_pspec = pyg_param_spec_new(pspec); - py_value = pyg_value_as_pyobject (value, TRUE); - - retval = PyObject_CallMethod(object_wrapper, "do_set_property", - "OO", py_pspec, py_value); - if (retval) { - Py_DECREF(retval); - } else { - PyErr_Print(); - } - - Py_DECREF(object_wrapper); - Py_DECREF(py_pspec); - Py_DECREF(py_value); - - pyglib_gil_state_release(state); -} - -static void -pyg_object_get_property (GObject *object, guint property_id, - GValue *value, GParamSpec *pspec) -{ - PyObject *object_wrapper, *retval; - PyObject *py_pspec; - PyGILState_STATE state; - - state = pyglib_gil_state_ensure(); - - object_wrapper = pygobject_new(object); - - if (object_wrapper == NULL) { - pyglib_gil_state_release(state); - return; - } - - py_pspec = pyg_param_spec_new(pspec); - retval = PyObject_CallMethod(object_wrapper, "do_get_property", - "O", py_pspec); - if (retval == NULL || pyg_value_from_pyobject(value, retval) < 0) { - PyErr_Print(); - } - Py_DECREF(object_wrapper); - Py_DECREF(py_pspec); - Py_XDECREF(retval); - - pyglib_gil_state_release(state); -} - -typedef struct _PyGSignalAccumulatorData { - PyObject *callable; - PyObject *user_data; -} PyGSignalAccumulatorData; - -static gboolean -_pyg_signal_accumulator(GSignalInvocationHint *ihint, - GValue *return_accu, - const GValue *handler_return, - gpointer _data) -{ - PyObject *py_ihint, *py_return_accu, *py_handler_return, *py_detail; - PyObject *py_retval; - gboolean retval = FALSE; - PyGSignalAccumulatorData *data = _data; - PyGILState_STATE state; - - state = pyglib_gil_state_ensure(); - if (ihint->detail) - py_detail = PYGLIB_PyUnicode_FromString(g_quark_to_string(ihint->detail)); - else { - Py_INCREF(Py_None); - py_detail = Py_None; - } - - py_ihint = Py_BuildValue("lNi", (long int) ihint->signal_id, - py_detail, ihint->run_type); - py_handler_return = pyg_value_as_pyobject(handler_return, TRUE); - py_return_accu = pyg_value_as_pyobject(return_accu, FALSE); - if (data->user_data) - py_retval = PyObject_CallFunction(data->callable, "NNNO", py_ihint, - py_return_accu, py_handler_return, - data->user_data); - else - py_retval = PyObject_CallFunction(data->callable, "NNN", py_ihint, - py_return_accu, py_handler_return); - if (!py_retval) - PyErr_Print(); - else { - if (!PyTuple_Check(py_retval) || PyTuple_Size(py_retval) != 2) { - PyErr_SetString(PyExc_TypeError, "accumulator function must return" - " a (bool, object) tuple"); - PyErr_Print(); - } else { - retval = PyObject_IsTrue(PyTuple_GET_ITEM(py_retval, 0)); - if (pyg_value_from_pyobject(return_accu, PyTuple_GET_ITEM(py_retval, 1))) { - PyErr_Print(); - } - } - Py_DECREF(py_retval); - } - pyglib_gil_state_release(state); - return retval; -} - -static gboolean -create_signal (GType instance_type, const gchar *signal_name, PyObject *tuple) -{ - GSignalFlags signal_flags; - PyObject *py_return_type, *py_param_types; - GType return_type; - guint n_params, i; - GType *param_types; - guint signal_id; - GSignalAccumulator accumulator = NULL; - PyGSignalAccumulatorData *accum_data = NULL; - PyObject *py_accum = NULL, *py_accum_data = NULL; - - if (!PyArg_ParseTuple(tuple, "iOO|OO", &signal_flags, &py_return_type, - &py_param_types, &py_accum, &py_accum_data)) - { - gchar buf[128]; - - PyErr_Clear(); - g_snprintf(buf, sizeof(buf), - "value for __gsignals__['%s'] not in correct format", signal_name); - PyErr_SetString(PyExc_TypeError, buf); - return FALSE; - } - - if (py_accum && py_accum != Py_None && !PyCallable_Check(py_accum)) - { - gchar buf[128]; - - g_snprintf(buf, sizeof(buf), - "accumulator for __gsignals__['%s'] must be callable", signal_name); - PyErr_SetString(PyExc_TypeError, buf); - return FALSE; - } - - return_type = pyg_type_from_object(py_return_type); - if (!return_type) - return FALSE; - if (!PySequence_Check(py_param_types)) { - gchar buf[128]; - - g_snprintf(buf, sizeof(buf), - "third element of __gsignals__['%s'] tuple must be a sequence", signal_name); - PyErr_SetString(PyExc_TypeError, buf); - return FALSE; - } - n_params = PySequence_Length(py_param_types); - param_types = g_new(GType, n_params); - for (i = 0; i < n_params; i++) { - PyObject *item = PySequence_GetItem(py_param_types, i); - - param_types[i] = pyg_type_from_object(item); - if (param_types[i] == 0) { - Py_DECREF(item); - g_free(param_types); - return FALSE; - } - Py_DECREF(item); - } - - 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, - pyg_signal_class_closure_get(), - accumulator, accum_data, - gi_cclosure_marshal_generic, - return_type, n_params, param_types); - g_free(param_types); - - if (signal_id == 0) { - gchar buf[128]; - - g_snprintf(buf, sizeof(buf), "could not create signal for %s", - signal_name); - PyErr_SetString(PyExc_RuntimeError, buf); - return FALSE; - } - return TRUE; -} - -static gboolean -override_signal(GType instance_type, const gchar *signal_name) -{ - guint signal_id; - - signal_id = g_signal_lookup(signal_name, instance_type); - if (!signal_id) { - gchar buf[128]; - - g_snprintf(buf, sizeof(buf), "could not look up %s", signal_name); - PyErr_SetString(PyExc_TypeError, buf); - return FALSE; - } - g_signal_override_class_closure(signal_id, instance_type, - pyg_signal_class_closure_get()); - return TRUE; -} - -static PyObject * -add_signals (GObjectClass *klass, PyObject *signals) -{ - gboolean ret = TRUE; - Py_ssize_t pos = 0; - PyObject *key, *value, *overridden_signals = NULL; - GType instance_type = G_OBJECT_CLASS_TYPE (klass); - - overridden_signals = PyDict_New(); - while (PyDict_Next(signals, &pos, &key, &value)) { - const gchar *signal_name; - gchar *signal_name_canon, *c; - - if (!PYGLIB_PyUnicode_Check(key)) { - PyErr_SetString(PyExc_TypeError, - "__gsignals__ keys must be strings"); - ret = FALSE; - break; - } - signal_name = PYGLIB_PyUnicode_AsString (key); - - if (value == Py_None || - (PYGLIB_PyUnicode_Check(value) && - !strcmp(PYGLIB_PyUnicode_AsString(value), "override"))) - { - /* canonicalize signal name, replacing '-' with '_' */ - signal_name_canon = g_strdup(signal_name); - for (c = signal_name_canon; *c; ++c) - if (*c == '-') - *c = '_'; - if (PyDict_SetItemString(overridden_signals, - signal_name_canon, key)) { - g_free(signal_name_canon); - ret = FALSE; - break; - } - g_free(signal_name_canon); - - ret = override_signal(instance_type, signal_name); - } else { - ret = create_signal(instance_type, signal_name, value); - } - - if (!ret) - break; - } - if (ret) - return overridden_signals; - else { - Py_XDECREF(overridden_signals); - return NULL; - } -} - -static GParamSpec * -create_property (const gchar *prop_name, - GType prop_type, - const gchar *nick, - const gchar *blurb, - PyObject *args, - GParamFlags flags) -{ - GParamSpec *pspec = NULL; - - switch (G_TYPE_FUNDAMENTAL(prop_type)) { - case G_TYPE_CHAR: - { - gchar minimum, maximum, default_value; - - if (!PyArg_ParseTuple(args, "ccc", &minimum, &maximum, - &default_value)) - return NULL; - pspec = g_param_spec_char (prop_name, nick, blurb, minimum, - maximum, default_value, flags); - } - break; - case G_TYPE_UCHAR: - { - gchar minimum, maximum, default_value; - - if (!PyArg_ParseTuple(args, "ccc", &minimum, &maximum, - &default_value)) - return NULL; - pspec = g_param_spec_uchar (prop_name, nick, blurb, minimum, - maximum, default_value, flags); - } - break; - case G_TYPE_BOOLEAN: - { - gboolean default_value; - - if (!PyArg_ParseTuple(args, "i", &default_value)) - return NULL; - pspec = g_param_spec_boolean (prop_name, nick, blurb, - default_value, flags); - } - break; - case G_TYPE_INT: - { - gint minimum, maximum, default_value; - - if (!PyArg_ParseTuple(args, "iii", &minimum, &maximum, - &default_value)) - return NULL; - pspec = g_param_spec_int (prop_name, nick, blurb, minimum, - maximum, default_value, flags); - } - break; - case G_TYPE_UINT: - { - guint minimum, maximum, default_value; - - if (!PyArg_ParseTuple(args, "III", &minimum, &maximum, - &default_value)) - return NULL; - pspec = g_param_spec_uint (prop_name, nick, blurb, minimum, - maximum, default_value, flags); - } - break; - case G_TYPE_LONG: - { - glong minimum, maximum, default_value; - - if (!PyArg_ParseTuple(args, "lll", &minimum, &maximum, - &default_value)) - return NULL; - pspec = g_param_spec_long (prop_name, nick, blurb, minimum, - maximum, default_value, flags); - } - break; - case G_TYPE_ULONG: - { - gulong minimum, maximum, default_value; - - if (!PyArg_ParseTuple(args, "kkk", &minimum, &maximum, - &default_value)) - return NULL; - pspec = g_param_spec_ulong (prop_name, nick, blurb, minimum, - maximum, default_value, flags); - } - break; - case G_TYPE_INT64: - { - gint64 minimum, maximum, default_value; - - if (!PyArg_ParseTuple(args, "LLL", &minimum, &maximum, - &default_value)) - return NULL; - pspec = g_param_spec_int64 (prop_name, nick, blurb, minimum, - maximum, default_value, flags); - } - break; - case G_TYPE_UINT64: - { - guint64 minimum, maximum, default_value; - - if (!PyArg_ParseTuple(args, "KKK", &minimum, &maximum, - &default_value)) - return NULL; - pspec = g_param_spec_uint64 (prop_name, nick, blurb, minimum, - maximum, default_value, flags); - } - break; - case G_TYPE_ENUM: - { - gint default_value; - PyObject *pydefault; - - if (!PyArg_ParseTuple(args, "O", &pydefault)) - return NULL; - - if (pyg_enum_get_value(prop_type, pydefault, - (gint *)&default_value)) - return NULL; - - pspec = g_param_spec_enum (prop_name, nick, blurb, - prop_type, default_value, flags); - } - break; - case G_TYPE_FLAGS: - { - guint default_value; - PyObject *pydefault; - - if (!PyArg_ParseTuple(args, "O", &pydefault)) - return NULL; - - if (pyg_flags_get_value(prop_type, pydefault, - &default_value)) - return NULL; - - pspec = g_param_spec_flags (prop_name, nick, blurb, - prop_type, default_value, flags); - } - break; - case G_TYPE_FLOAT: - { - gfloat minimum, maximum, default_value; - - if (!PyArg_ParseTuple(args, "fff", &minimum, &maximum, - &default_value)) - return NULL; - pspec = g_param_spec_float (prop_name, nick, blurb, minimum, - maximum, default_value, flags); - } - break; - case G_TYPE_DOUBLE: - { - gdouble minimum, maximum, default_value; - - if (!PyArg_ParseTuple(args, "ddd", &minimum, &maximum, - &default_value)) - return NULL; - pspec = g_param_spec_double (prop_name, nick, blurb, minimum, - maximum, default_value, flags); - } - break; - case G_TYPE_STRING: - { - const gchar *default_value; - - if (!PyArg_ParseTuple(args, "z", &default_value)) - return NULL; - pspec = g_param_spec_string (prop_name, nick, blurb, - default_value, flags); - } - break; - case G_TYPE_PARAM: - if (!PyArg_ParseTuple(args, "")) - return NULL; - pspec = g_param_spec_param (prop_name, nick, blurb, prop_type, flags); - break; - case G_TYPE_BOXED: - if (!PyArg_ParseTuple(args, "")) - return NULL; - pspec = g_param_spec_boxed (prop_name, nick, blurb, prop_type, flags); - break; - case G_TYPE_POINTER: - if (!PyArg_ParseTuple(args, "")) - return NULL; - 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; - } - - if (!pspec) { - char buf[128]; - - g_snprintf(buf, sizeof(buf), "could not create param spec for type %s", - g_type_name(prop_type)); - PyErr_SetString(PyExc_TypeError, buf); - return NULL; - } - - return pspec; -} - -static GParamSpec * -pyg_param_spec_from_object (PyObject *tuple) -{ - gint val_length; - const gchar *prop_name; - GType prop_type; - const gchar *nick, *blurb; - PyObject *slice, *item, *py_prop_type; - GParamSpec *pspec; - - val_length = PyTuple_Size(tuple); - if (val_length < 4) { - PyErr_SetString(PyExc_TypeError, - "paramspec tuples must be at least 4 elements long"); - return NULL; - } - - slice = PySequence_GetSlice(tuple, 0, 4); - if (!slice) { - return NULL; - } - - if (!PyArg_ParseTuple(slice, "sOzz", &prop_name, &py_prop_type, &nick, &blurb)) { - Py_DECREF(slice); - return NULL; - } - - Py_DECREF(slice); - - prop_type = pyg_type_from_object(py_prop_type); - if (!prop_type) { - return NULL; - } - - item = PyTuple_GetItem(tuple, val_length-1); - if (!PYGLIB_PyLong_Check(item)) { - PyErr_SetString(PyExc_TypeError, - "last element in tuple must be an int"); - return NULL; - } - - /* slice is the extra items in the tuple */ - slice = PySequence_GetSlice(tuple, 4, val_length-1); - pspec = create_property(prop_name, prop_type, - nick, blurb, slice, - PYGLIB_PyLong_AsLong(item)); - - return pspec; -} - -static gboolean -add_properties (GObjectClass *klass, PyObject *properties) -{ - gboolean ret = TRUE; - Py_ssize_t pos = 0; - PyObject *key, *value; - - while (PyDict_Next(properties, &pos, &key, &value)) { - const gchar *prop_name; - GType prop_type; - const gchar *nick, *blurb; - GParamFlags flags; - gint val_length; - PyObject *slice, *item, *py_prop_type; - GParamSpec *pspec; - - /* values are of format (type,nick,blurb, type_specific_args, flags) */ - - if (!PYGLIB_PyUnicode_Check(key)) { - PyErr_SetString(PyExc_TypeError, - "__gproperties__ keys must be strings"); - ret = FALSE; - break; - } - prop_name = PYGLIB_PyUnicode_AsString (key); - - if (!PyTuple_Check(value)) { - PyErr_SetString(PyExc_TypeError, - "__gproperties__ values must be tuples"); - ret = FALSE; - break; - } - val_length = PyTuple_Size(value); - if (val_length < 4) { - PyErr_SetString(PyExc_TypeError, - "__gproperties__ values must be at least 4 elements long"); - ret = FALSE; - break; - } - - slice = PySequence_GetSlice(value, 0, 3); - if (!slice) { - ret = FALSE; - break; - } - if (!PyArg_ParseTuple(slice, "Ozz", &py_prop_type, &nick, &blurb)) { - Py_DECREF(slice); - ret = FALSE; - break; - } - Py_DECREF(slice); - prop_type = pyg_type_from_object(py_prop_type); - if (!prop_type) { - ret = FALSE; - break; - } - item = PyTuple_GetItem(value, val_length-1); - if (!PYGLIB_PyLong_Check(item)) { - PyErr_SetString(PyExc_TypeError, - "last element in __gproperties__ value tuple must be an int"); - ret = FALSE; - break; - } - flags = PYGLIB_PyLong_AsLong(item); - - /* slice is the extra items in the tuple */ - slice = PySequence_GetSlice(value, 3, val_length-1); - pspec = create_property(prop_name, prop_type, nick, blurb, - slice, flags); - Py_DECREF(slice); - - if (pspec) { - g_object_class_install_property(klass, 1, pspec); - } else { - PyObject *type, *value, *traceback; - ret = FALSE; - PyErr_Fetch(&type, &value, &traceback); - if (PYGLIB_PyUnicode_Check(value)) { - char msg[256]; - g_snprintf(msg, 256, - "%s (while registering property '%s' for GType '%s')", - PYGLIB_PyUnicode_AsString(value), - prop_name, G_OBJECT_CLASS_NAME(klass)); - Py_DECREF(value); - value = PYGLIB_PyUnicode_FromString(msg); - } - PyErr_Restore(type, value, traceback); - break; - } - } - - 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; - - list = g_type_get_qdata(gtype, pygobject_class_init_key); - list = g_slist_prepend(list, class_init); - g_type_set_qdata(gtype, pygobject_class_init_key, list); -} - -static int -pyg_run_class_init(GType gtype, gpointer gclass, PyTypeObject *pyclass) -{ - GSList *list; - PyGClassInitFunc class_init; - GType parent_type; - int rv; - - parent_type = g_type_parent(gtype); - if (parent_type) { - rv = pyg_run_class_init(parent_type, gclass, pyclass); - if (rv) - return rv; - } - - list = g_type_get_qdata(gtype, pygobject_class_init_key); - for (; list; list = list->next) { - class_init = list->data; - rv = class_init(gclass, pyclass); - if (rv) - return rv; - } - - return 0; -} - -static PyObject * -_wrap_pyg_type_register(PyObject *self, PyObject *args) -{ - PyTypeObject *class; - char *type_name = NULL; - - if (!PyArg_ParseTuple(args, "O!|z:gobject.type_register", - &PyType_Type, &class, &type_name)) - return NULL; - if (!PyType_IsSubtype(class, &PyGObject_Type)) { - PyErr_SetString(PyExc_TypeError, - "argument must be a GObject subclass"); - return NULL; - } - - /* Check if type already registered */ - if (pyg_type_from_object((PyObject *) class) == - pyg_type_from_object((PyObject *) class->tp_base)) - { - if (pyg_type_register(class, type_name)) - return NULL; - } - - Py_INCREF(class); - return (PyObject *) class; -} - -static char * -get_type_name_for_class(PyTypeObject *class) -{ - gint i, name_serial; - char name_serial_str[16]; - PyObject *module; - char *type_name = NULL; - - /* make name for new GType */ - name_serial = 1; - /* give up after 1000 tries, just in case.. */ - while (name_serial < 1000) - { - g_free(type_name); - 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), ".", - class->tp_name, - name_serial > 1 ? name_serial_str : NULL, - NULL); - Py_DECREF(module); - } else { - if (module) - Py_DECREF(module); - else - PyErr_Clear(); - type_name = g_strconcat(class->tp_name, - name_serial > 1 ? name_serial_str : NULL, - NULL); - } - /* convert '.' in type name to '+', which isn't banned (grumble) */ - for (i = 0; type_name[i] != '\0'; i++) - if (type_name[i] == '.') - type_name[i] = '+'; - if (g_type_from_name(type_name) == 0) - break; /* we now have a unique name */ - ++name_serial; - } - - return type_name; -} - - -static GPrivate pygobject_construction_wrapper; - -static inline void -pygobject_init_wrapper_set(PyObject *wrapper) -{ - g_private_set(&pygobject_construction_wrapper, wrapper); -} - -static inline PyObject * -pygobject_init_wrapper_get(void) -{ - return (PyObject *) g_private_get(&pygobject_construction_wrapper); -} - -int -pygobject_constructv(PyGObject *self, - guint n_parameters, - GParameter *parameters) -{ - if (self->obj == NULL) { - GObject *obj; - 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; - pygobject_register_wrapper((PyObject *) self); - } - } else { - int i; - for (i = 0; i < n_parameters; ++i) - g_object_set_property(self->obj, - parameters[i].name, - ¶meters[i].value); - } - return 0; -} - -static void -pygobject__g_instance_init(GTypeInstance *instance, - gpointer g_class) -{ - GObject *object = (GObject *) instance; - PyObject *wrapper, *args, *kwargs; - - wrapper = g_object_get_qdata(object, pygobject_wrapper_key); - if (wrapper == NULL) { - wrapper = pygobject_init_wrapper_get(); - if (wrapper && ((PyGObject *) wrapper)->obj == NULL) { - ((PyGObject *) wrapper)->obj = object; - pygobject_register_wrapper(wrapper); - } - } - pygobject_init_wrapper_set(NULL); - if (wrapper == NULL) { - /* this looks like a python object created through - * g_object_new -> we have no python wrapper, so create it - * now */ - PyGILState_STATE state; - state = pyglib_gil_state_ensure(); - 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 - * will take the ref */ - pygobject_ref_float ((PyGObject *) wrapper); - args = PyTuple_New(0); - kwargs = PyDict_New(); - if (Py_TYPE(wrapper)->tp_init(wrapper, args, kwargs)) - PyErr_Print(); - - Py_DECREF(args); - Py_DECREF(kwargs); - pyglib_gil_state_release(state); - } -} - - -/* This implementation is bad, see bug 566571 for an example why. - * Instead of scanning explicitly declared bases for interfaces, we - * should automatically initialize all implemented interfaces to - * prevent bugs like that one. However, this will lead to - * performance degradation as each virtual method in derived classes - * will round-trip through do_*() stuff, *even* if it is not - * overriden. We need to teach codegen to retain parent method - * instead of setting virtual to *_proxy_do_*() if corresponding - * do_*() is not overriden. Ok, that was a messy explanation. - */ -static void -pyg_type_add_interfaces(PyTypeObject *class, GType instance_type, - PyObject *bases, - GType *parent_interfaces, guint n_parent_interfaces) -{ - int i; - - if (!bases) { - g_warning("type has no bases"); - return; - } - - for (i = 0; i < PyTuple_GET_SIZE(bases); ++i) { - PyObject *base = PyTuple_GET_ITEM(bases, i); - GType itype; - const GInterfaceInfo *iinfo; - GInterfaceInfo iinfo_copy; - - /* 'base' can also be a PyClassObject, see bug #566571. */ - if (!PyType_Check(base)) - continue; - - if (!PyType_IsSubtype((PyTypeObject*) base, &PyGInterface_Type)) - continue; - - itype = pyg_type_from_object(base); - - /* Happens for _implementations_ of an interface. */ - if (!G_TYPE_IS_INTERFACE(itype)) - continue; - - iinfo = pyg_lookup_interface_info(itype); - if (!iinfo) { - gchar *error; - error = g_strdup_printf("Interface type %s " - "has no Python implementation support", - ((PyTypeObject *) base)->tp_name); - PyErr_Warn(PyExc_RuntimeWarning, error); - g_free(error); - continue; - } - - iinfo_copy = *iinfo; - iinfo_copy.interface_data = class; - g_type_add_interface_static(instance_type, itype, &iinfo_copy); - } -} - -int -pyg_type_register(PyTypeObject *class, const char *type_name) -{ - PyObject *gtype; - GType parent_type, instance_type; - GType *parent_interfaces; - guint n_parent_interfaces; - GTypeQuery query; - gpointer gclass; - GTypeInfo type_info = { - 0, /* class_size */ - - (GBaseInitFunc) NULL, - (GBaseFinalizeFunc) NULL, - - (GClassInitFunc) pyg_object_class_init, - (GClassFinalizeFunc) NULL, - NULL, /* class_data */ - - 0, /* instance_size */ - 0, /* n_preallocs */ - (GInstanceInitFunc) pygobject__g_instance_init - }; - gchar *new_type_name; - - /* find the GType of the parent */ - parent_type = pyg_type_from_object((PyObject *)class); - if (!parent_type) - return -1; - - parent_interfaces = g_type_interfaces(parent_type, &n_parent_interfaces); - - if (type_name) - /* care is taken below not to free this */ - new_type_name = (gchar *) type_name; - else - new_type_name = get_type_name_for_class(class); - - /* set class_data that will be passed to the class_init function. */ - type_info.class_data = class; - - /* fill in missing values of GTypeInfo struct */ - g_type_query(parent_type, &query); - type_info.class_size = query.class_size; - type_info.instance_size = query.instance_size; - - /* create new typecode */ - instance_type = g_type_register_static(parent_type, new_type_name, - &type_info, 0); - if (instance_type == 0) { - PyErr_Format(PyExc_RuntimeError, - "could not create new GType: %s (subclass of %s)", - new_type_name, - g_type_name(parent_type)); - - if (type_name == NULL) - g_free(new_type_name); - - return -1; - } - - if (type_name == NULL) - g_free(new_type_name); - - /* store pointer to the class with the GType */ - Py_INCREF(class); - 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); - Py_DECREF(gtype); - - /* if no __doc__, set it to the auto doc descriptor */ - if (PyDict_GetItemString(class->tp_dict, "__doc__") == NULL) { - PyDict_SetItemString(class->tp_dict, "__doc__", - pyg_object_descr_doc_get()); - } - - /* - * 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, - parent_interfaces, n_parent_interfaces); - - - gclass = g_type_class_ref(instance_type); - if (PyErr_Occurred() != NULL) { - g_type_class_unref(gclass); - g_free(parent_interfaces); - return -1; - } - - if (pyg_run_class_init(instance_type, gclass, class)) { - g_type_class_unref(gclass); - g_free(parent_interfaces); - return -1; - } - g_type_class_unref(gclass); - g_free(parent_interfaces); - - if (PyErr_Occurred() != NULL) - return -1; - return 0; -} - -static PyObject * -pyg_signal_new(PyObject *self, PyObject *args) -{ - gchar *signal_name; - PyObject *py_type; - GSignalFlags signal_flags; - GType return_type; - PyObject *py_return_type, *py_param_types; - - GType instance_type = 0; - Py_ssize_t n_params, i; - GType *param_types; - - guint signal_id; - - if (!PyArg_ParseTuple(args, "sOiOO:gobject.signal_new", &signal_name, - &py_type, &signal_flags, &py_return_type, - &py_param_types)) - return NULL; - - instance_type = pyg_type_from_object(py_type); - if (!instance_type) - return NULL; - if (!(G_TYPE_IS_INSTANTIATABLE(instance_type) || G_TYPE_IS_INTERFACE(instance_type))) { - PyErr_SetString(PyExc_TypeError, - "argument 2 must be an object type or interface type"); - return NULL; - } - - return_type = pyg_type_from_object(py_return_type); - if (!return_type) - return NULL; - - if (!PySequence_Check(py_param_types)) { - PyErr_SetString(PyExc_TypeError, - "argument 5 must be a sequence of GType codes"); - return NULL; - } - n_params = PySequence_Length(py_param_types); - param_types = g_new(GType, n_params); - for (i = 0; i < n_params; i++) { - PyObject *item = PySequence_GetItem(py_param_types, i); - - param_types[i] = pyg_type_from_object(item); - if (param_types[i] == 0) { - PyErr_Clear(); - Py_DECREF(item); - PyErr_SetString(PyExc_TypeError, - "argument 5 must be a sequence of GType codes"); - g_free(param_types); - return NULL; - } - Py_DECREF(item); - } - - signal_id = g_signal_newv(signal_name, instance_type, signal_flags, - pyg_signal_class_closure_get(), - (GSignalAccumulator)0, NULL, - (GSignalCMarshaller)0, - return_type, n_params, param_types); - g_free(param_types); - if (signal_id != 0) - return PYGLIB_PyLong_FromLong(signal_id); - PyErr_SetString(PyExc_RuntimeError, "could not create signal"); - return NULL; -} - -static PyObject * -pyg_signal_query (PyObject *self, PyObject *args, PyObject *kwargs) -{ - static char *kwlist1[] = { "name", "type", NULL }; - static char *kwlist2[] = { "signal_id", NULL }; - PyObject *py_query, *params_list, *py_itype; - GObjectClass *class = NULL; - GType itype; - gchar *signal_name; - guint i; - GSignalQuery query; - guint id; - gpointer iface = NULL; - - if (PyArg_ParseTupleAndKeywords(args, kwargs, "sO:gobject.signal_query", - kwlist1, &signal_name, &py_itype)) { - 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); - } else { - PyErr_Clear(); - if (!PyArg_ParseTupleAndKeywords(args, kwargs, - "i:gobject.signal_query", - kwlist2, &id)) { - PyErr_Clear(); - PyErr_SetString(PyExc_TypeError, - "Usage: one of:\n" - " gobject.signal_query(name, type)\n" - " gobject.signal_query(signal_id)"); - - return NULL; - } - } - - g_signal_query(id, &query); - - if (query.signal_id == 0) { - Py_INCREF(Py_None); - py_query = Py_None; - goto done; - } - py_query = PyTuple_New(6); - if (py_query == NULL) { - goto done; - } - params_list = PyTuple_New(query.n_params); - if (params_list == NULL) { - Py_DECREF(py_query); - py_query = NULL; - goto done; - } - - PyTuple_SET_ITEM(py_query, 0, PYGLIB_PyLong_FromLong(query.signal_id)); - PyTuple_SET_ITEM(py_query, 1, PYGLIB_PyUnicode_FromString(query.signal_name)); - PyTuple_SET_ITEM(py_query, 2, pyg_type_wrapper_new(query.itype)); - PyTuple_SET_ITEM(py_query, 3, PYGLIB_PyLong_FromLong(query.signal_flags)); - PyTuple_SET_ITEM(py_query, 4, pyg_type_wrapper_new(query.return_type)); - for (i = 0; i < query.n_params; i++) { - PyTuple_SET_ITEM(params_list, i, - pyg_type_wrapper_new(query.param_types[i])); - } - PyTuple_SET_ITEM(py_query, 5, params_list); - - done: - if (class) - g_type_class_unref(class); - if (iface) - g_type_default_interface_unref(iface); - - return py_query; -} - -static PyObject * -pyg_object_class_list_properties (PyObject *self, PyObject *args) -{ - GParamSpec **specs; - PyObject *py_itype, *list; - GType itype; - GObjectClass *class = NULL; - gpointer iface = NULL; - guint nprops; - guint i; - - if (!PyArg_ParseTuple(args, "O:gobject.list_properties", - &py_itype)) - return NULL; - if ((itype = pyg_type_from_object(py_itype)) == 0) - return NULL; - - if (G_TYPE_IS_INTERFACE(itype)) { - iface = g_type_default_interface_ref(itype); - if (!iface) { - PyErr_SetString(PyExc_RuntimeError, - "could not get a reference to interface type"); - return NULL; - } - specs = g_object_interface_list_properties(iface, &nprops); - } else if (g_type_is_a(itype, G_TYPE_OBJECT)) { - class = g_type_class_ref(itype); - if (!class) { - PyErr_SetString(PyExc_RuntimeError, - "could not get a reference to type class"); - return NULL; - } - specs = g_object_class_list_properties(class, &nprops); - } else { - PyErr_SetString(PyExc_TypeError, - "type must be derived from GObject or an interface"); - return NULL; - } - - list = PyTuple_New(nprops); - if (list == NULL) { - g_free(specs); - g_type_class_unref(class); - return NULL; - } - for (i = 0; i < nprops; i++) { - PyTuple_SetItem(list, i, pyg_param_spec_new(specs[i])); - } - g_free(specs); - if (class) - g_type_class_unref(class); - else - g_type_default_interface_unref(iface); - - return list; -} - -static PyObject * -pyg_object_new (PyGObject *self, PyObject *args, PyObject *kwargs) -{ - PyObject *pytype; - GType type; - GObject *obj = NULL; - GObjectClass *class; - guint n_params = 0, i; - GParameter *params = NULL; - - if (!PyArg_ParseTuple (args, "O:gobject.new", &pytype)) { - return NULL; - } - - if ((type = pyg_type_from_object (pytype)) == 0) - return NULL; - - if (G_TYPE_IS_ABSTRACT(type)) { - PyErr_Format(PyExc_TypeError, "cannot create instance of abstract " - "(non-instantiable) type `%s'", g_type_name(type)); - return NULL; - } - - if ((class = g_type_class_ref (type)) == NULL) { - PyErr_SetString(PyExc_TypeError, - "could not get a reference to type class"); - return NULL; - } - - if (!pygobject_prepare_construct_properties (class, kwargs, &n_params, ¶ms)) - goto cleanup; - - obj = g_object_newv(type, n_params, params); - if (!obj) - PyErr_SetString (PyExc_RuntimeError, "could not create object"); - - cleanup: - for (i = 0; i < n_params; i++) { - g_free((gchar *) params[i].name); - g_value_unset(¶ms[i].value); - } - g_free(params); - g_type_class_unref(class); - - if (obj) { - pygobject_sink (obj); - self = (PyGObject *) pygobject_new((GObject *)obj); - g_object_unref(obj); - } else - self = NULL; - - return (PyObject *) self; -} - -gboolean -pyg_handler_marshal(gpointer user_data) -{ - PyObject *tuple, *ret; - gboolean res; - PyGILState_STATE state; - - g_return_val_if_fail(user_data != NULL, FALSE); - - state = pyglib_gil_state_ensure(); - - tuple = (PyObject *)user_data; - ret = PyObject_CallObject(PyTuple_GetItem(tuple, 0), - PyTuple_GetItem(tuple, 1)); - if (!ret) { - PyErr_Print(); - res = FALSE; - } else { - res = PyObject_IsTrue(ret); - Py_DECREF(ret); - } - - pyglib_gil_state_release(state); - - return res; -} - -static int -pygobject_gil_state_ensure (void) -{ - return pyglib_gil_state_ensure (); -} - -static void -pygobject_gil_state_release (int flag) -{ - pyglib_gil_state_release(flag); -} - -/* Only for backwards compatibility */ -static int -pygobject_enable_threads(void) -{ - return 0; -} - -static PyObject * -pyg_signal_accumulator_true_handled(PyObject *unused, PyObject *args) -{ - PyErr_SetString(PyExc_TypeError, - "signal_accumulator_true_handled can only" - " be used as accumulator argument when registering signals"); - return NULL; -} - -static gboolean -marshal_emission_hook(GSignalInvocationHint *ihint, - guint n_param_values, - const GValue *param_values, - gpointer user_data) -{ - PyGILState_STATE state; - gboolean retval = FALSE; - PyObject *func, *args; - PyObject *retobj; - PyObject *params; - guint i; - - state = pyglib_gil_state_ensure(); - - /* construct Python tuple for the parameter values */ - params = PyTuple_New(n_param_values); - - for (i = 0; i < n_param_values; i++) { - PyObject *item = pyg_value_as_pyobject(¶m_values[i], FALSE); - - /* error condition */ - if (!item) { - goto out; - } - PyTuple_SetItem(params, i, item); - } - - args = (PyObject *)user_data; - func = PyTuple_GetItem(args, 0); - args = PySequence_Concat(params, PyTuple_GetItem(args, 1)); - Py_DECREF(params); - - /* params passed to function may have extra arguments */ - - retobj = PyObject_CallObject(func, args); - Py_DECREF(args); - if (retobj == NULL) { - PyErr_Print(); - } - - retval = (retobj == Py_True ? TRUE : FALSE); - Py_XDECREF(retobj); -out: - pyglib_gil_state_release(state); - return retval; -} - -static PyObject * -pyg_add_emission_hook(PyGObject *self, PyObject *args) -{ - PyObject *first, *callback, *extra_args, *data, *repr; - gchar *name; - gulong hook_id; - guint sigid; - Py_ssize_t len; - GQuark detail = 0; - GType gtype; - PyObject *pygtype; - - len = PyTuple_Size(args); - if (len < 3) { - PyErr_SetString(PyExc_TypeError, - "gobject.add_emission_hook requires at least 3 arguments"); - return NULL; - } - first = PySequence_GetSlice(args, 0, 3); - if (!PyArg_ParseTuple(first, "OsO:add_emission_hook", - &pygtype, &name, &callback)) { - Py_DECREF(first); - return NULL; - } - Py_DECREF(first); - - if ((gtype = pyg_type_from_object(pygtype)) == 0) { - return NULL; - } - if (!PyCallable_Check(callback)) { - PyErr_SetString(PyExc_TypeError, "third argument must be callable"); - return NULL; - } - - 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(repr), - name); - Py_DECREF(repr); - return NULL; - } - extra_args = PySequence_GetSlice(args, 3, len); - if (extra_args == NULL) - return NULL; - - data = Py_BuildValue("(ON)", callback, extra_args); - if (data == NULL) - return NULL; - - hook_id = g_signal_add_emission_hook(sigid, detail, - marshal_emission_hook, - data, - (GDestroyNotify)pyg_destroy_notify); - - return PyLong_FromUnsignedLong(hook_id); -} - -static PyObject * -pyg__install_metaclass(PyObject *dummy, PyTypeObject *metaclass) -{ - Py_INCREF(metaclass); - PyGObject_MetaType = metaclass; - Py_INCREF(metaclass); - - Py_TYPE(&PyGObject_Type) = metaclass; - - Py_INCREF(Py_None); - return Py_None; -} - -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; - } - - return pyg_value_as_pyobject (pyg_boxed_get(pygvalue, GValue), - /*copy_boxed=*/ TRUE); -} - -static PyObject * -pyg__gvalue_set(PyObject *module, PyObject *args) -{ - PyObject *pygvalue; - PyObject *pyobject; - - if (!PyArg_ParseTuple (args, "OO:_gobject._gvalue_set", - &pygvalue, &pyobject)) - return NULL; - - 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_is_a", pyg_type_is_a, METH_VARARGS }, - { "type_register", _wrap_pyg_type_register, METH_VARARGS }, - { "signal_new", pyg_signal_new, METH_VARARGS }, - { "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 }, - { "signal_accumulator_true_handled", - (PyCFunction)pyg_signal_accumulator_true_handled, METH_VARARGS }, - { "add_emission_hook", - (PyCFunction)pyg_add_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 } -}; - - -/* ----------------- Constant extraction ------------------------ */ - -/** - * pyg_constant_strip_prefix: - * @name: the constant name. - * @strip_prefix: the prefix to strip. - * - * Advances the pointer @name by strlen(@strip_prefix) characters. If - * the resulting name does not start with a letter or underscore, the - * @name pointer will be rewound. This is to ensure that the - * resulting name is a valid identifier. Hence the returned string is - * a pointer into the string @name. - * - * Returns: the stripped constant name. - */ -const gchar * -pyg_constant_strip_prefix(const gchar *name, const gchar *strip_prefix) -{ - gint prefix_len; - guint i; - - prefix_len = strlen(strip_prefix); - - /* Check so name starts with strip_prefix, if it doesn't: - * return the rest of the part which doesn't match - */ - for (i = 0; i < prefix_len; i++) { - if (name[i] != strip_prefix[i] && name[i] != '_') { - return &name[i]; - } - } - - /* strip off prefix from value name, while keeping it a valid - * identifier */ - for (i = prefix_len; i >= 0; i--) { - if (g_ascii_isalpha(name[i]) || name[i] == '_') { - return &name[i]; - } - } - return name; -} - -/** - * pyg_enum_add_constants: - * @module: a Python module - * @enum_type: the GType of the enumeration. - * @strip_prefix: the prefix to strip from the constant names. - * - * Adds constants to the given Python module for each value name of - * the enumeration. A prefix will be stripped from each enum name. - */ -static void -pyg_enum_add_constants(PyObject *module, GType enum_type, - const gchar *strip_prefix) -{ - GEnumClass *eclass; - guint i; - - if (!G_TYPE_IS_ENUM(enum_type)) { - if (G_TYPE_IS_FLAGS(enum_type)) /* See bug #136204 */ - pyg_flags_add_constants(module, enum_type, strip_prefix); - else - g_warning("`%s' is not an enum type", g_type_name(enum_type)); - return; - } - g_return_if_fail (strip_prefix != NULL); - - eclass = G_ENUM_CLASS(g_type_class_ref(enum_type)); - - for (i = 0; i < eclass->n_values; i++) { - const gchar *name = eclass->values[i].value_name; - gint value = eclass->values[i].value; - - PyModule_AddIntConstant(module, - (char*) pyg_constant_strip_prefix(name, strip_prefix), - (long) value); - } - - g_type_class_unref(eclass); -} - -/** - * pyg_flags_add_constants: - * @module: a Python module - * @flags_type: the GType of the flags type. - * @strip_prefix: the prefix to strip from the constant names. - * - * Adds constants to the given Python module for each value name of - * the flags set. A prefix will be stripped from each flag name. - */ -static void -pyg_flags_add_constants(PyObject *module, GType flags_type, - const gchar *strip_prefix) -{ - GFlagsClass *fclass; - guint i; - - if (!G_TYPE_IS_FLAGS(flags_type)) { - if (G_TYPE_IS_ENUM(flags_type)) /* See bug #136204 */ - pyg_enum_add_constants(module, flags_type, strip_prefix); - else - g_warning("`%s' is not an flags type", g_type_name(flags_type)); - return; - } - g_return_if_fail (strip_prefix != NULL); - - fclass = G_FLAGS_CLASS(g_type_class_ref(flags_type)); - - for (i = 0; i < fclass->n_values; i++) { - const gchar *name = fclass->values[i].value_name; - guint value = fclass->values[i].value; - - PyModule_AddIntConstant(module, - (char*) pyg_constant_strip_prefix(name, strip_prefix), - (long) value); - } - - g_type_class_unref(fclass); -} - -/** - * pyg_error_check: - * @error: a pointer to the GError. - * - * Checks to see if the GError has been set. If the error has been - * set, then the gobject.GError Python exception will be raised, and - * the GError cleared. - * - * Returns: True if an error was set. - * - * Deprecated: Since 2.16, use pyglib_error_check instead. - */ -gboolean -pyg_error_check(GError **error) -{ -#if 0 - if (PyErr_Warn(PyExc_DeprecationWarning, - "pyg_error_check is deprecated, use " - "pyglib_error_check instead")) - return NULL; -#endif - return pyglib_error_check(error); -} - -/** - * pyg_gerror_exception_check: - * @error: a standard GLib GError ** output parameter - * - * Checks to see if a GError exception has been raised, and if so - * translates the python exception to a standard GLib GError. If the - * raised exception is not a GError then PyErr_Print() is called. - * - * Returns: 0 if no exception has been raised, -1 if it is a - * valid gobject.GError, -2 otherwise. - * - * Deprecated: Since 2.16, use pyglib_gerror_exception_check instead. - */ -gboolean -pyg_gerror_exception_check(GError **error) -{ -#if 0 - if (PyErr_Warn(PyExc_DeprecationWarning, - "pyg_gerror_exception_check is deprecated, use " - "pyglib_gerror_exception_check instead")) - return NULL; -#endif - return pyglib_gerror_exception_check(error); -} - -/** - * pyg_parse_constructor_args: helper function for PyGObject constructors - * @obj_type: GType of the GObject, for parameter introspection - * @arg_names: %NULL-terminated array of constructor argument names - * @prop_names: %NULL-terminated array of property names, with direct - * correspondence to @arg_names - * @params: GParameter array where parameters will be placed; length - * of this array must be at least equal to the number of - * arguments/properties - * @nparams: output parameter to contain actual number of arguments found - * @py_args: array of PyObject* containing the actual constructor arguments - * - * Parses an array of PyObject's and creates a GParameter array - * - * Return value: %TRUE if all is successful, otherwise %FALSE and - * python exception set. - **/ -static gboolean -pyg_parse_constructor_args(GType obj_type, - char **arg_names, - char **prop_names, - GParameter *params, - guint *nparams, - PyObject **py_args) -{ - guint arg_i, param_i; - GObjectClass *oclass; - - oclass = g_type_class_ref(obj_type); - g_return_val_if_fail(oclass, FALSE); - - for (param_i = arg_i = 0; arg_names[arg_i]; ++arg_i) { - GParamSpec *spec; - if (!py_args[arg_i]) - continue; - spec = g_object_class_find_property(oclass, prop_names[arg_i]); - params[param_i].name = prop_names[arg_i]; - g_value_init(¶ms[param_i].value, spec->value_type); - if (pyg_value_from_pyobject(¶ms[param_i].value, py_args[arg_i]) == -1) { - int i; - PyErr_Format(PyExc_TypeError, "could not convert parameter '%s' of type '%s'", - arg_names[arg_i], g_type_name(spec->value_type)); - g_type_class_unref(oclass); - for (i = 0; i < param_i; ++i) - g_value_unset(¶ms[i].value); - return FALSE; - } - ++param_i; - } - g_type_class_unref(oclass); - *nparams = param_i; - return TRUE; -} - -PyObject * -pyg_integer_richcompare(PyObject *v, PyObject *w, int op) -{ - PyObject *result; - gboolean t; - - switch (op) { - case Py_EQ: t = PYGLIB_PyLong_AS_LONG(v) == PYGLIB_PyLong_AS_LONG(w); break; - case Py_NE: t = PYGLIB_PyLong_AS_LONG(v) != PYGLIB_PyLong_AS_LONG(w); break; - case Py_LE: t = PYGLIB_PyLong_AS_LONG(v) <= PYGLIB_PyLong_AS_LONG(w); break; - case Py_GE: t = PYGLIB_PyLong_AS_LONG(v) >= PYGLIB_PyLong_AS_LONG(w); break; - case Py_LT: t = PYGLIB_PyLong_AS_LONG(v) < PYGLIB_PyLong_AS_LONG(w); break; - case Py_GT: t = PYGLIB_PyLong_AS_LONG(v) > PYGLIB_PyLong_AS_LONG(w); break; - default: g_assert_not_reached(); - } - - result = t ? Py_True : Py_False; - Py_INCREF(result); - return result; -} - -static void -_log_func(const gchar *log_domain, - GLogLevelFlags log_level, - const gchar *message, - gpointer user_data) -{ - if (G_LIKELY(Py_IsInitialized())) - { - PyGILState_STATE state; - PyObject* warning = user_data; - - state = pyglib_gil_state_ensure(); - PyErr_Warn(warning, (char *) message); - pyglib_gil_state_release(state); - } else - g_log_default_handler(log_domain, log_level, message, user_data); -} - -static void -add_warning_redirection(const char *domain, - PyObject *warning) -{ - g_return_if_fail(domain != NULL); - g_return_if_fail(warning != NULL); - - if (!log_handlers_disabled) - { - guint handler; - gpointer old_handler; - - if (!log_handlers) - log_handlers = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL); - - if ((old_handler = g_hash_table_lookup(log_handlers, domain))) - g_log_remove_handler(domain, GPOINTER_TO_UINT(old_handler)); - - handler = g_log_set_handler(domain, G_LOG_LEVEL_CRITICAL|G_LOG_LEVEL_WARNING, - _log_func, warning); - g_hash_table_insert(log_handlers, g_strdup(domain), GUINT_TO_POINTER(handler)); - } -} - -static void -remove_handler(gpointer domain, - gpointer handler, - gpointer unused) -{ - g_log_remove_handler(domain, GPOINTER_TO_UINT(handler)); -} - -static void -disable_warning_redirections(void) -{ - log_handlers_disabled = TRUE; - - if (log_handlers) - { - g_hash_table_foreach(log_handlers, remove_handler, NULL); - g_hash_table_destroy(log_handlers); - log_handlers = NULL; - } -} - -/* ----------------- gobject module initialisation -------------- */ - -struct _PyGObject_Functions pygobject_api_functions = { - pygobject_register_class, - pygobject_register_wrapper, - pygobject_lookup_class, - pygobject_new, - - pyg_closure_new, - pygobject_watch_closure, - pyg_destroy_notify, - - pyg_type_from_object, - pyg_type_wrapper_new, - pyg_enum_get_value, - pyg_flags_get_value, - pyg_register_gtype_custom, - pyg_value_from_pyobject, - pyg_value_as_pyobject, - - pyg_register_interface, - - &PyGBoxed_Type, - pyg_register_boxed, - pyg_boxed_new, - - &PyGPointer_Type, - pyg_register_pointer, - pyg_pointer_new, - - pyg_enum_add_constants, - pyg_flags_add_constants, - - pyg_constant_strip_prefix, - - pyg_error_check, - - _pyg_set_thread_block_funcs, - (PyGThreadBlockFunc)0, /* block_threads */ - (PyGThreadBlockFunc)0, /* unblock_threads */ - - &PyGParamSpec_Type, - pyg_param_spec_new, - pyg_param_spec_from_object, - - pyg_pyobj_to_unichar_conv, - pyg_parse_constructor_args, - pyg_param_gvalue_as_pyobject, - pyg_param_gvalue_from_pyobject, - - &PyGEnum_Type, - pyg_enum_add, - pyg_enum_from_gtype, - - &PyGFlags_Type, - pyg_flags_add, - pyg_flags_from_gtype, - - /* threads_enabled */ -#ifdef DISABLE_THREADING - FALSE, -#else - TRUE, -#endif - - pygobject_enable_threads, - pygobject_gil_state_ensure, - pygobject_gil_state_release, - pyg_register_class_init, - pyg_register_interface_info, - - pyg_closure_set_exception_handler, - - add_warning_redirection, - disable_warning_redirections, - - NULL, /* previously type_register_custom */ - - pyg_gerror_exception_check, - - pyglib_option_group_new, - pyg_type_from_object_strict, - - pygobject_new_full, - &PyGObject_Type, - - pyg_value_from_pyobject_with_error -}; - -/* for addon libraries ... */ -static void -pygobject_register_api(PyObject *d) -{ - PyObject *api; - - api = PYGLIB_CPointer_WrapPointer(&pygobject_api_functions, "gobject._PyGObject_API"); - PyDict_SetItemString(d, "_PyGObject_API", api); - Py_DECREF(api); -} - -/* some constants */ -static void -pygobject_register_constants(PyObject *m) -{ - /* PyFloat_ return a new ref, and add object takes the ref */ - PyModule_AddObject(m, "G_MINFLOAT", PyFloat_FromDouble(G_MINFLOAT)); - PyModule_AddObject(m, "G_MAXFLOAT", PyFloat_FromDouble(G_MAXFLOAT)); - PyModule_AddObject(m, "G_MINDOUBLE", PyFloat_FromDouble(G_MINDOUBLE)); - PyModule_AddObject(m, "G_MAXDOUBLE", PyFloat_FromDouble(G_MAXDOUBLE)); - PyModule_AddIntConstant(m, "G_MINSHORT", G_MINSHORT); - PyModule_AddIntConstant(m, "G_MAXSHORT", G_MAXSHORT); - 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_AddObject(m, "G_MAXSIZE", PyLong_FromSize_t(G_MAXSIZE)); - PyModule_AddObject(m, "G_MAXSSIZE", PyLong_FromSsize_t(G_MAXSSIZE)); - 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)); - - PyModule_AddIntConstant(m, "SIGNAL_RUN_FIRST", G_SIGNAL_RUN_FIRST); - PyModule_AddIntConstant(m, "PARAM_READWRITE", G_PARAM_READWRITE); - - /* The rest of the types are set in __init__.py */ - PyModule_AddObject(m, "TYPE_INVALID", pyg_type_wrapper_new(G_TYPE_INVALID)); - PyModule_AddObject(m, "TYPE_GSTRING", pyg_type_wrapper_new(G_TYPE_GSTRING)); -} - -/* features */ -static void -pygobject_register_features(PyObject *d) -{ - PyObject *features; - - features = PyDict_New(); - PyDict_SetItemString(features, "generic-c-marshaller", Py_True); - PyDict_SetItemString(d, "features", features); - Py_DECREF(features); -} - -static void -pygobject_register_version_tuples(PyObject *d) -{ - PyObject *tuple; - - /* pygobject version */ - tuple = Py_BuildValue ("(iii)", - PYGOBJECT_MAJOR_VERSION, - PYGOBJECT_MINOR_VERSION, - PYGOBJECT_MICRO_VERSION); - PyDict_SetItemString(d, "pygobject_version", tuple); -} - -static void -pygobject_register_warnings(PyObject *d) -{ - PyObject *warning; - - warning = PyErr_NewException("gobject.Warning", PyExc_Warning, NULL); - PyDict_SetItemString(d, "Warning", warning); - add_warning_redirection("GLib", warning); - add_warning_redirection("GLib-GObject", warning); - add_warning_redirection("GThread", warning); -} - - -PYGLIB_MODULE_START(_gobject, "_gobject") -{ - PyObject *d; - - pyglib_init(); - - d = PyModule_GetDict(module); - pygobject_register_api(d); - pygobject_register_constants(module); - pygobject_register_features(d); - pygobject_register_version_tuples(d); - pygobject_register_warnings(d); - pygobject_type_register_types(d); - pygobject_object_register_types(d); - pygobject_interface_register_types(d); - pygobject_paramspec_register_types(d); - pygobject_boxed_register_types(d); - pygobject_pointer_register_types(d); - pygobject_enum_register_types(d); - pygobject_flags_register_types(d); -} -PYGLIB_MODULE_END diff --git a/gi/_gobject/pygflags.h b/gi/_gobject/pygflags.h deleted file mode 100644 index e93265c..0000000 --- a/gi/_gobject/pygflags.h +++ /dev/null @@ -1,27 +0,0 @@ -/* -*- Mode: C; c-basic-offset: 4 -*- - * pygtk- Python bindings for the GTK toolkit. - * Copyright (C) 1998-2003 James Henstridge - * 2004-2008 Johan Dahlin - * - * 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 - */ - -#ifndef __PYGOBJECT_FLAGS_H__ -#define __PYGOBJECT_FLAGS_H__ - -void pygobject_flags_register_types(PyObject *d); - -#endif /* __PYGOBJECT_FLAGS_H__ */ diff --git a/gi/_gobject/pygobject-private.h b/gi/_gobject/pygobject-private.h deleted file mode 100644 index 294b0f6..0000000 --- a/gi/_gobject/pygobject-private.h +++ /dev/null @@ -1,204 +0,0 @@ -#ifndef _PYGOBJECT_PRIVATE_H_ -#define _PYGOBJECT_PRIVATE_H_ - -#ifdef _PYGOBJECT_H_ -# error "include pygobject.h or pygobject-private.h, but not both" -#endif - -#define _INSIDE_PYGOBJECT_ -#include "pygobject.h" - -#include "pyglib-python-compat.h" - -#define PYGOBJECT_REGISTER_GTYPE(d, type, name, gtype) \ - { \ - PyObject *o; \ - PYGLIB_REGISTER_TYPE(d, type, name); \ - PyDict_SetItemString(type.tp_dict, "__gtype__", \ - o=pyg_type_wrapper_new(gtype)); \ - Py_DECREF(o); \ -} - -/* from gobjectmodule.c */ -extern struct _PyGObject_Functions pygobject_api_functions; - - -#ifndef Py_CLEAR /* since Python 2.4 */ -# define Py_CLEAR(op) \ - do { \ - if (op) { \ - PyObject *tmp = (PyObject *)(op); \ - (op) = NULL; \ - Py_DECREF(tmp); \ - } \ - } while (0) -#endif - -extern GType PY_TYPE_OBJECT; - -extern GQuark pygboxed_type_key; -extern GQuark pygboxed_marshal_key; -extern GQuark pygenum_class_key; -extern GQuark pygflags_class_key; -extern GQuark pyginterface_type_key; -extern GQuark pyginterface_info_key; -extern GQuark pygobject_class_init_key; -extern GQuark pygobject_class_key; -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); -gboolean pyg_handler_marshal (gpointer user_data); -gboolean pyg_error_check (GError **error); -int pygobject_constructv (PyGObject *self, - guint n_parameters, - GParameter *parameters); - -PyObject *pyg_integer_richcompare(PyObject *v, - PyObject *w, - int op); - -gboolean pyg_gerror_exception_check(GError **error); - -void pygobject_ref_float(PyGObject *self); -void pygobject_ref_sink(PyGObject *self); - -/* from pygtype.h */ -extern PyTypeObject PyGTypeWrapper_Type; - -PyObject *pyg_type_wrapper_new (GType type); -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, guint *val); -int pyg_pyobj_to_unichar_conv (PyObject* py_obj, void* ptr); - -typedef PyObject *(* fromvaluefunc)(const GValue *value); -typedef int (*tovaluefunc)(GValue *value, PyObject *obj); - -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, - const GParamSpec* pspec); -PyObject *pyg_param_gvalue_as_pyobject(const GValue* gvalue, - gboolean copy_boxed, - const GParamSpec* pspec); - -GClosure *pyg_closure_new(PyObject *callback, PyObject *extra_args, PyObject *swap_data); -void pyg_closure_set_exception_handler(GClosure *closure, - PyClosureExceptionHandler handler); -GClosure *pyg_signal_class_closure_get(void); -GClosure *gclosure_from_pyfunc(PyGObject *object, PyObject *func); - -PyObject *pyg_object_descr_doc_get(void); -void pygobject_object_register_types(PyObject *d); - -extern PyTypeObject *PyGObject_MetaType; - -/* from pygobject.h */ -extern PyTypeObject PyGObject_Type; -extern PyTypeObject PyGProps_Type; -extern PyTypeObject PyGPropsDescr_Type; -extern PyTypeObject PyGPropsIter_Type; - - /* Data that belongs to the GObject instance, not the Python wrapper */ -struct _PyGObjectData { - PyTypeObject *type; /* wrapper type for this instance */ - GSList *closures; -}; - -void pygobject_register_class (PyObject *dict, - const gchar *type_name, - GType gtype, PyTypeObject *type, - PyObject *bases); -void pygobject_register_wrapper (PyObject *self); -PyObject * pygobject_new (GObject *obj); -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); -int pyg_type_register (PyTypeObject *class, - const gchar *type_name); - -/* from pygboxed.c */ -extern PyTypeObject PyGBoxed_Type; - -void pyg_register_boxed (PyObject *dict, const gchar *class_name, - GType boxed_type, PyTypeObject *type); -PyObject * pyg_boxed_new (GType boxed_type, gpointer boxed, - gboolean copy_boxed, gboolean own_ref); - -extern PyTypeObject PyGPointer_Type; - -void pyg_register_pointer (PyObject *dict, const gchar *class_name, - GType pointer_type, PyTypeObject *type); -PyObject * pyg_pointer_new (GType pointer_type, gpointer pointer); - -const gchar * pyg_constant_strip_prefix(const gchar *name, const gchar *strip_prefix); - -/* pygflags */ -typedef struct { - PYGLIB_PyLongObject parent; - int zero_pad; /* must always be 0 */ - GType gtype; -} PyGFlags; - -extern PyTypeObject PyGFlags_Type; - -#define PyGFlags_Check(x) (PyObject_IsInstance((PyObject *)x, (PyObject *)&PyGFlags_Type) && g_type_is_a(((PyGFlags*)x)->gtype, G_TYPE_FLAGS)) - -extern PyObject * pyg_flags_add (PyObject * module, - const char * type_name, - const char * strip_prefix, - GType gtype); -extern PyObject * pyg_flags_from_gtype (GType gtype, - 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; - int zero_pad; /* must always be 0 */ - GType gtype; -} PyGEnum; - -extern PyTypeObject PyGEnum_Type; - -extern PyObject * pyg_enum_add (PyObject * module, - const char * type_name, - const char * strip_prefix, - GType gtype); -extern PyObject * pyg_enum_from_gtype (GType gtype, - int value); - -/* pygtype.c */ -extern gboolean pyg_gtype_is_custom (GType gtype); - -/* pygobject.c */ -extern PyTypeObject PyGObjectWeakRef_Type; - -static inline PyGObjectData * -pyg_object_peek_inst_data(GObject *obj) -{ - return ((PyGObjectData *) - g_object_get_qdata(obj, pygobject_instance_data_key)); -} - -gboolean pygobject_prepare_construct_properties (GObjectClass *class, - PyObject *kwargs, - guint *n_params, - GParameter **params); - - -#endif diff --git a/gi/_gobject/pygparamspec.c b/gi/_gobject/pygparamspec.c deleted file mode 100644 index 94f1dbb..0000000 --- a/gi/_gobject/pygparamspec.c +++ /dev/null @@ -1,404 +0,0 @@ -/* -*- Mode: C; c-basic-offset: 4 -*- - * pygtk- Python bindings for the GTK toolkit. - * Copyright (C) 1998-2003 James Henstridge - * Copyright (C) 2004 Johan Dahlin - * - * pygenum.c: GEnum and GFlag wrappers - * - * 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 - */ - -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif - -#include <pyglib.h> - -#include "pygobject-private.h" -#include "pygparamspec.h" - -PYGLIB_DEFINE_TYPE("gobject.GParamSpec", PyGParamSpec_Type, PyGParamSpec); - -static PyObject* -pyg_param_spec_richcompare(PyObject *self, PyObject *other, int op) -{ - if (Py_TYPE(self) == Py_TYPE(other) && Py_TYPE(self) == &PyGParamSpec_Type) - return _pyglib_generic_ptr_richcompare(((PyGParamSpec*)self)->pspec, - ((PyGParamSpec*)other)->pspec, - op); - else { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } -} - -static long -pyg_param_spec_hash(PyGParamSpec *self) -{ - return (long)self->pspec; -} - -static PyObject * -pyg_param_spec_repr(PyGParamSpec *self) -{ - char buf[80]; - - g_snprintf(buf, sizeof(buf), "<%s '%s'>", - G_PARAM_SPEC_TYPE_NAME(self->pspec), - g_param_spec_get_name(self->pspec)); - return PYGLIB_PyUnicode_FromString(buf); -} - -static void -pyg_param_spec_dealloc(PyGParamSpec *self) -{ - g_param_spec_unref(self->pspec); - PyObject_DEL(self); -} - - -static PyObject * -pygenum_from_pspec(GParamSpec *pspec) -{ - PyObject *pyclass; - GParamSpecEnum *enum_pspec; - GType enum_type; - - enum_pspec = G_PARAM_SPEC_ENUM(pspec); - enum_type = G_ENUM_CLASS_TYPE(enum_pspec->enum_class); - pyclass = (PyObject*)g_type_get_qdata(enum_type, pygenum_class_key); - if (pyclass == NULL) { - pyclass = pyg_enum_add(NULL, g_type_name(enum_type), NULL, enum_type); - if (pyclass == NULL) - pyclass = Py_None; - } - - Py_INCREF(pyclass); - return pyclass; -} - -static PyObject * -pygflags_from_pspec(GParamSpec *pspec) -{ - PyObject *pyclass; - GParamSpecFlags *flag_pspec; - GType flag_type; - - flag_pspec = G_PARAM_SPEC_FLAGS(pspec); - flag_type = G_FLAGS_CLASS_TYPE(flag_pspec->flags_class); - pyclass = (PyObject*)g_type_get_qdata(flag_type, pygflags_class_key); - if (pyclass == NULL) { - pyclass = pyg_flags_add(NULL, g_type_name(flag_type), NULL, flag_type); - if (pyclass == NULL) - pyclass = Py_None; - } - Py_INCREF(pyclass); - return pyclass; -} - -static PyObject * -pyg_param_spec_getattr(PyGParamSpec *self, const gchar *attr) -{ - GParamSpec *pspec; - - pspec = self->pspec; - - /* common attributes */ - if (!strcmp(attr, "__gtype__")) { - return pyg_type_wrapper_new(G_PARAM_SPEC_TYPE(pspec)); - } else if (!strcmp(attr, "name")) { - return Py_BuildValue("s", g_param_spec_get_name(pspec)); - } else if (!strcmp(attr, "nick")) { - return Py_BuildValue("s", g_param_spec_get_nick(pspec)); - } else if (!strcmp(attr, "blurb") || !strcmp(attr, "__doc__")) { - return Py_BuildValue("s", g_param_spec_get_blurb(pspec)); - } else if (!strcmp(attr, "flags")) { - return PYGLIB_PyLong_FromLong(pspec->flags); - } else if (!strcmp(attr, "value_type")) { - return pyg_type_wrapper_new(pspec->value_type); - } else if (!strcmp(attr, "owner_type")) { - return pyg_type_wrapper_new(pspec->owner_type); - } - - if (G_IS_PARAM_SPEC_CHAR(pspec)) { - if (!strcmp(attr, "__members__")) { - return Py_BuildValue("[sssssssssss]", "__doc__", "__gtype__", - "blurb", "default_value", "flags", - "maximum", "minimum", "name", "nick", - "owner_type", "value_type"); - } else if (!strcmp(attr, "default_value")) { - return PYGLIB_PyUnicode_FromFormat( - "%c", G_PARAM_SPEC_CHAR(pspec)->default_value); - } else if (!strcmp(attr, "minimum")) { - return PYGLIB_PyLong_FromLong(G_PARAM_SPEC_CHAR(pspec)->minimum); - } else if (!strcmp(attr, "maximum")) { - return PYGLIB_PyLong_FromLong(G_PARAM_SPEC_CHAR(pspec)->maximum); - } - } else if (G_IS_PARAM_SPEC_UCHAR(pspec)) { - if (!strcmp(attr, "__members__")) { - return Py_BuildValue("[sssssssssss]", "__doc__", "__gtype__", - "blurb", "default_value", - "flags", "maximum", "minimum", - "name", "nick", "owner_type", - "value_type"); - } else if (!strcmp(attr, "default_value")) { - return PYGLIB_PyUnicode_FromFormat( - "%c", G_PARAM_SPEC_UCHAR(pspec)->default_value); - } else if (!strcmp(attr, "minimum")) { - return PYGLIB_PyLong_FromLong(G_PARAM_SPEC_UCHAR(pspec)->minimum); - } else if (!strcmp(attr, "maximum")) { - return PYGLIB_PyLong_FromLong(G_PARAM_SPEC_UCHAR(pspec)->maximum); - } - } else if (G_IS_PARAM_SPEC_BOOLEAN(pspec)) { - if (!strcmp(attr, "__members__")) { - return Py_BuildValue("[sssssssss]", "__doc__", "__gtype__", - "blurb", "default_value", - "flags", "name", "nick", "owner_type", - "value_type"); - } else if (!strcmp(attr, "default_value")) { - return PyBool_FromLong(G_PARAM_SPEC_BOOLEAN(pspec)->default_value); - } - } else if (G_IS_PARAM_SPEC_INT(pspec)) { - if (!strcmp(attr, "__members__")) { - return Py_BuildValue("[sssssssssss]", "__doc__", "__gtype__", - "blurb", "default_value", - "flags", "maximum", "minimum", "name", - "nick", "owner_type", "value_type"); - } else if (!strcmp(attr, "default_value")) { - return PYGLIB_PyLong_FromLong(G_PARAM_SPEC_INT(pspec)->default_value); - } else if (!strcmp(attr, "minimum")) { - return PYGLIB_PyLong_FromLong(G_PARAM_SPEC_INT(pspec)->minimum); - } else if (!strcmp(attr, "maximum")) { - return PYGLIB_PyLong_FromLong(G_PARAM_SPEC_INT(pspec)->maximum); - } - } else if (G_IS_PARAM_SPEC_UINT(pspec)) { - if (!strcmp(attr, "__members__")) { - return Py_BuildValue("[sssssssssss]", "__doc__", "__gtype__", - "blurb", "default_value", - "flags", "maximum", "minimum", - "name", "nick", "owner_type", - "value_type"); - } else if (!strcmp(attr, "default_value")) { - return PyLong_FromUnsignedLong(G_PARAM_SPEC_UINT(pspec)->default_value); - } else if (!strcmp(attr, "minimum")) { - return PyLong_FromUnsignedLong(G_PARAM_SPEC_UINT(pspec)->minimum); - } else if (!strcmp(attr, "maximum")) { - return PyLong_FromUnsignedLong(G_PARAM_SPEC_UINT(pspec)->maximum); - } - } else if (G_IS_PARAM_SPEC_LONG(pspec)) { - if (!strcmp(attr, "__members__")) { - return Py_BuildValue("[sssssssssss]", "__doc__", "__gtype__", - "blurb", "default_value", - "flags", "maximum", "minimum", "name", - "nick", "owner_type", "value_type"); - } else if (!strcmp(attr, "default_value")) { - return PyLong_FromLong(G_PARAM_SPEC_LONG(pspec)->default_value); - } else if (!strcmp(attr, "minimum")) { - return PyLong_FromLong(G_PARAM_SPEC_LONG(pspec)->minimum); - } else if (!strcmp(attr, "maximum")) { - return PyLong_FromLong(G_PARAM_SPEC_LONG(pspec)->maximum); - } - } else if (G_IS_PARAM_SPEC_ULONG(pspec)) { - if (!strcmp(attr, "__members__")) { - return Py_BuildValue("[sssssssssss]", "__doc__", "__gtype__", - "blurb", "default_value", - "flags", "maximum", "minimum", "name", - "nick", "owner_type", "value_type"); - } else if (!strcmp(attr, "default_value")) { - return PyLong_FromUnsignedLong(G_PARAM_SPEC_ULONG(pspec)->default_value); - } else if (!strcmp(attr, "minimum")) { - return PyLong_FromUnsignedLong(G_PARAM_SPEC_ULONG(pspec)->minimum); - } else if (!strcmp(attr, "maximum")) { - return PyLong_FromUnsignedLong(G_PARAM_SPEC_ULONG(pspec)->maximum); - } - } else if (G_IS_PARAM_SPEC_INT64(pspec)) { - if (!strcmp(attr, "__members__")) { - return Py_BuildValue("[sssssssssss]", "__doc__", "__gtype__", - "blurb", "default_value", - "flags", "maximum", "minimum", "name", - "nick", "owner_type", "value_type"); - } else if (!strcmp(attr, "default_value")) { - return PyLong_FromLongLong(G_PARAM_SPEC_INT64(pspec)->default_value); - } else if (!strcmp(attr, "minimum")) { - return PyLong_FromLongLong(G_PARAM_SPEC_INT64(pspec)->minimum); - } else if (!strcmp(attr, "maximum")) { - return PyLong_FromLongLong(G_PARAM_SPEC_INT64(pspec)->maximum); - } - } else if (G_IS_PARAM_SPEC_UINT64(pspec)) { - if (!strcmp(attr, "__members__")) { - return Py_BuildValue("[sssssssssss]", "__doc__", "__gtype__", - "blurb", "default_value", - "flags", "maximum", "minimum", - "name", "nick", "owner_type", - "value_type"); - } else if (!strcmp(attr, "default_value")) { - return PyLong_FromUnsignedLongLong(G_PARAM_SPEC_UINT64(pspec)->default_value); - } else if (!strcmp(attr, "minimum")) { - return PyLong_FromUnsignedLongLong(G_PARAM_SPEC_UINT64(pspec)->minimum); - } else if (!strcmp(attr, "maximum")) { - return PyLong_FromUnsignedLongLong(G_PARAM_SPEC_UINT64(pspec)->maximum); - } - } else if (G_IS_PARAM_SPEC_UNICHAR(pspec)) { - if (!strcmp(attr, "__members__")) { - return Py_BuildValue("[sssssssss]", "__doc__", "__gtype__", - "blurb", "default_value", - "flags", "name", "nick", "owner_type", - "value_type"); - } else if (!strcmp(attr, "default_value")) { - return PYGLIB_PyUnicode_FromFormat( - "%c", G_PARAM_SPEC_UNICHAR(pspec)->default_value); - } - } else if (G_IS_PARAM_SPEC_ENUM(pspec)) { - if (!strcmp(attr, "__members__")) { - return Py_BuildValue("[ssssssssss]", "__doc__", "__gtype__", - "blurb", "default_value", "enum_class", - "flags", "name", "nick", "owner_type", - "value_type"); - } else if (!strcmp(attr, "default_value")) { - return pyg_enum_from_gtype( - pspec->value_type, G_PARAM_SPEC_ENUM(pspec)->default_value); - } else if (!strcmp(attr, "enum_class")) { - return pygenum_from_pspec(pspec); - } - } else if (G_IS_PARAM_SPEC_FLAGS(pspec)) { - if (!strcmp(attr, "__members__")) { - return Py_BuildValue("[ssssssssss]", "__doc__", "__gtype__", - "blurb", "default_value", - "flags", "flags_class", "name", "nick", - "owner_type", "value_type"); - } else if (!strcmp(attr, "default_value")) { - return pyg_flags_from_gtype( - pspec->value_type, G_PARAM_SPEC_FLAGS(pspec)->default_value); - } else if (!strcmp(attr, "flags_class")) { - return pygflags_from_pspec(pspec); - } - } else if (G_IS_PARAM_SPEC_FLOAT(pspec)) { - if (!strcmp(attr, "__members__")) { - return Py_BuildValue("[ssssssssssss]", "__doc__", "__gtype__", - "blurb", "epsilon", - "flags", "maximum", "minimum", "name", "nick", "owner_type", - "value_type", - "default_value"); - } else if (!strcmp(attr, "default_value")) { - return PyFloat_FromDouble(G_PARAM_SPEC_FLOAT(pspec)->default_value); - } else if (!strcmp(attr, "minimum")) { - return PyFloat_FromDouble(G_PARAM_SPEC_FLOAT(pspec)->minimum); - } else if (!strcmp(attr, "maximum")) { - return PyFloat_FromDouble(G_PARAM_SPEC_FLOAT(pspec)->maximum); - } else if (!strcmp(attr, "epsilon")) { - return PyFloat_FromDouble(G_PARAM_SPEC_FLOAT(pspec)->epsilon); - } - } else if (G_IS_PARAM_SPEC_DOUBLE(pspec)) { - if (!strcmp(attr, "__members__")) { - return Py_BuildValue("[ssssssssssss]", "__doc__", "__gtype__", - "blurb", "default_value", "epsilon", - "flags", "maximum", "minimum", "name", "nick", - "owner_type", "value_type"); - } else if (!strcmp(attr, "default_value")) { - return PyFloat_FromDouble( - G_PARAM_SPEC_DOUBLE(pspec)->default_value); - } else if (!strcmp(attr, "minimum")) { - return PyFloat_FromDouble(G_PARAM_SPEC_DOUBLE(pspec)->minimum); - } else if (!strcmp(attr, "maximum")) { - return PyFloat_FromDouble(G_PARAM_SPEC_DOUBLE(pspec)->maximum); - } else if (!strcmp(attr, "epsilon")) { - return PyFloat_FromDouble(G_PARAM_SPEC_DOUBLE(pspec)->epsilon); - } - } else if (G_IS_PARAM_SPEC_STRING(pspec)) { - if (!strcmp(attr, "__members__")) { - return Py_BuildValue("[ssssssssssssss]", "__doc__", "__gtype__", - "blurb", "cset_first", "cset_nth", "default_value", - "ensure_non_null", "flags", "name", "nick", - "null_fold_if_empty", "owner_type", "substitutor", - "value_type"); - } else if (!strcmp(attr, "default_value")) { - return Py_BuildValue( - "s", G_PARAM_SPEC_STRING(pspec)->default_value); - } else if (!strcmp(attr, "cset_first")) { - return Py_BuildValue( - "s", G_PARAM_SPEC_STRING(pspec)->cset_first); - } else if (!strcmp(attr, "cset_nth")) { - return Py_BuildValue( - "s", G_PARAM_SPEC_STRING(pspec)->cset_nth); - } else if (!strcmp(attr, "substitutor")) { - return Py_BuildValue( - "c", G_PARAM_SPEC_STRING(pspec)->substitutor); - } else if (!strcmp(attr, "null_fold_if_empty")) { - return PyBool_FromLong( - G_PARAM_SPEC_STRING(pspec)->null_fold_if_empty); - } else if (!strcmp(attr, "ensure_non_null")) { - return PyBool_FromLong( - G_PARAM_SPEC_STRING(pspec)->ensure_non_null); - } - } else { - if (!strcmp(attr, "__members__")) { - return Py_BuildValue("[ssssssss]", "__doc__", "__gtype__", "blurb", - "flags", "name", "nick", - "owner_type", "value_type"); - - /* This is actually not what's exported by GObjects paramspecs, - * But we exported this in earlier versions, so it's better to keep it here - * compatibility. But don't add it in __members__, to "hide" it. - */ - } else if (!strcmp(attr, "default_value")) { - /* XXX: Raise deprecation warning */ - Py_INCREF(Py_None); - return Py_None; - } - } - - PyErr_SetString(PyExc_AttributeError, attr); - return NULL; -} - -/** - * pyg_param_spec_new: - * @pspec: a GParamSpec. - * - * Creates a wrapper for a GParamSpec. - * - * Returns: the GParamSpec wrapper. - */ -PyObject * -pyg_param_spec_new(GParamSpec *pspec) -{ - PyGParamSpec *self; - - self = (PyGParamSpec *)PyObject_NEW(PyGParamSpec, - &PyGParamSpec_Type); - if (self == NULL) - return NULL; - - self->pspec = g_param_spec_ref(pspec); - return (PyObject *)self; -} - -void -pygobject_paramspec_register_types(PyObject *d) -{ - Py_TYPE(&PyGParamSpec_Type) = &PyType_Type; - PyGParamSpec_Type.tp_dealloc = (destructor)pyg_param_spec_dealloc; - PyGParamSpec_Type.tp_getattr = (getattrfunc)pyg_param_spec_getattr; - PyGParamSpec_Type.tp_richcompare = pyg_param_spec_richcompare; - PyGParamSpec_Type.tp_flags = Py_TPFLAGS_DEFAULT; - PyGParamSpec_Type.tp_repr = (reprfunc)pyg_param_spec_repr; - PyGParamSpec_Type.tp_hash = (hashfunc)pyg_param_spec_hash; - - - if (PyType_Ready(&PyGParamSpec_Type)) - return; - PyDict_SetItemString(d, "GParamSpec", (PyObject *)&PyGParamSpec_Type); -} diff --git a/gi/_gobject/pygtype.c b/gi/_gobject/pygtype.c deleted file mode 100644 index 9dc1153..0000000 --- a/gi/_gobject/pygtype.c +++ /dev/null @@ -1,1927 +0,0 @@ -/* -*- Mode: C; c-basic-offset: 4 -*- - * pygtk- Python bindings for the GTK toolkit. - * Copyright (C) 1998-2003 James Henstridge - * - * pygtype.c: glue code to wrap the GType code. - * - * 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 - */ - -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif - -#include <pyglib.h> - -#include "pygobject-private.h" -#include "pygparamspec.h" -#include "pygtype.h" - -/* -------------- __gtype__ objects ---------------------------- */ - -typedef struct { - PyObject_HEAD - GType type; -} PyGTypeWrapper; - -PYGLIB_DEFINE_TYPE("gobject.GType", PyGTypeWrapper_Type, PyGTypeWrapper); - -static PyObject* -pyg_type_wrapper_richcompare(PyObject *self, PyObject *other, int op) -{ - if (Py_TYPE(self) == Py_TYPE(other) && Py_TYPE(self) == &PyGTypeWrapper_Type) - return _pyglib_generic_long_richcompare(((PyGTypeWrapper*)self)->type, - ((PyGTypeWrapper*)other)->type, - op); - else { - Py_INCREF(Py_NotImplemented); - return Py_NotImplemented; - } -} - -static long -pyg_type_wrapper_hash(PyGTypeWrapper *self) -{ - return (long)self->type; -} - -static PyObject * -pyg_type_wrapper_repr(PyGTypeWrapper *self) -{ - char buf[80]; - const gchar *name = g_type_name(self->type); - - g_snprintf(buf, sizeof(buf), "<GType %s (%lu)>", - name?name:"invalid", (unsigned long int) self->type); - return PYGLIB_PyUnicode_FromString(buf); -} - -static void -pyg_type_wrapper_dealloc(PyGTypeWrapper *self) -{ - PyObject_DEL(self); -} - -static GQuark -_pyg_type_key(GType type) { - GQuark key; - - if (g_type_is_a(type, G_TYPE_INTERFACE)) { - key = pyginterface_type_key; - } else if (g_type_is_a(type, G_TYPE_ENUM)) { - key = pygenum_class_key; - } else if (g_type_is_a(type, G_TYPE_FLAGS)) { - key = pygflags_class_key; - } else if (g_type_is_a(type, G_TYPE_POINTER)) { - key = pygpointer_class_key; - } else if (g_type_is_a(type, G_TYPE_BOXED)) { - key = pygboxed_type_key; - } else { - key = pygobject_class_key; - } - - return key; -} - -static PyObject * -_wrap_g_type_wrapper__get_pytype(PyGTypeWrapper *self, void *closure) -{ - GQuark key; - PyObject *py_type; - - key = _pyg_type_key(self->type); - - py_type = g_type_get_qdata(self->type, key); - if (!py_type) - py_type = Py_None; - - Py_INCREF(py_type); - return py_type; -} - -static int -_wrap_g_type_wrapper__set_pytype(PyGTypeWrapper *self, PyObject* value, void *closure) -{ - GQuark key; - PyObject *py_type; - - key = _pyg_type_key(self->type); - - py_type = g_type_get_qdata(self->type, key); - Py_CLEAR(py_type); - if (value == Py_None) - g_type_set_qdata(self->type, key, NULL); - else if (PyType_Check(value)) { - Py_INCREF(value); - g_type_set_qdata(self->type, key, value); - } else { - PyErr_SetString(PyExc_TypeError, "Value must be None or a type object"); - return -1; - } - - return 0; -} - -static PyObject * -_wrap_g_type_wrapper__get_name(PyGTypeWrapper *self, void *closure) -{ - const char *name = g_type_name(self->type); - return PYGLIB_PyUnicode_FromString(name ? name : "invalid"); -} - -static PyObject * -_wrap_g_type_wrapper__get_parent(PyGTypeWrapper *self, void *closure) -{ - return pyg_type_wrapper_new(g_type_parent(self->type)); -} - -static PyObject * -_wrap_g_type_wrapper__get_fundamental(PyGTypeWrapper *self, void *closure) -{ - return pyg_type_wrapper_new(g_type_fundamental(self->type)); -} - -static PyObject * -_wrap_g_type_wrapper__get_children(PyGTypeWrapper *self, void *closure) -{ - guint n_children, i; - GType *children; - PyObject *retval; - - children = g_type_children(self->type, &n_children); - - retval = PyList_New(n_children); - for (i = 0; i < n_children; i++) - PyList_SetItem(retval, i, pyg_type_wrapper_new(children[i])); - g_free(children); - - return retval; -} - -static PyObject * -_wrap_g_type_wrapper__get_interfaces(PyGTypeWrapper *self, void *closure) -{ - guint n_interfaces, i; - GType *interfaces; - PyObject *retval; - - interfaces = g_type_interfaces(self->type, &n_interfaces); - - retval = PyList_New(n_interfaces); - for (i = 0; i < n_interfaces; i++) - PyList_SetItem(retval, i, pyg_type_wrapper_new(interfaces[i])); - g_free(interfaces); - - return retval; -} - -static PyObject * -_wrap_g_type_wrapper__get_depth(PyGTypeWrapper *self, void *closure) -{ - return PYGLIB_PyLong_FromLong(g_type_depth(self->type)); -} - -static PyGetSetDef _PyGTypeWrapper_getsets[] = { - { "pytype", (getter)_wrap_g_type_wrapper__get_pytype, (setter)_wrap_g_type_wrapper__set_pytype }, - { "name", (getter)_wrap_g_type_wrapper__get_name, (setter)0 }, - { "fundamental", (getter)_wrap_g_type_wrapper__get_fundamental, (setter)0 }, - { "parent", (getter)_wrap_g_type_wrapper__get_parent, (setter)0 }, - { "children", (getter)_wrap_g_type_wrapper__get_children, (setter)0 }, - { "interfaces", (getter)_wrap_g_type_wrapper__get_interfaces, (setter)0 }, - { "depth", (getter)_wrap_g_type_wrapper__get_depth, (setter)0 }, - { NULL, (getter)0, (setter)0 } -}; - -static PyObject* -_wrap_g_type_is_interface(PyGTypeWrapper *self) -{ - return PyBool_FromLong(G_TYPE_IS_INTERFACE(self->type)); -} - -static PyObject* -_wrap_g_type_is_classed(PyGTypeWrapper *self) -{ - return PyBool_FromLong(G_TYPE_IS_CLASSED(self->type)); -} - -static PyObject* -_wrap_g_type_is_instantiatable(PyGTypeWrapper *self) -{ - return PyBool_FromLong(G_TYPE_IS_INSTANTIATABLE(self->type)); -} - -static PyObject* -_wrap_g_type_is_derivable(PyGTypeWrapper *self) -{ - return PyBool_FromLong(G_TYPE_IS_DERIVABLE(self->type)); -} - -static PyObject* -_wrap_g_type_is_deep_derivable(PyGTypeWrapper *self) -{ - return PyBool_FromLong(G_TYPE_IS_DEEP_DERIVABLE(self->type)); -} - -static PyObject* -_wrap_g_type_is_abstract(PyGTypeWrapper *self) -{ - return PyBool_FromLong(G_TYPE_IS_ABSTRACT(self->type)); -} - -static PyObject* -_wrap_g_type_is_value_abstract(PyGTypeWrapper *self) -{ - return PyBool_FromLong(G_TYPE_IS_VALUE_ABSTRACT(self->type)); -} - -static PyObject* -_wrap_g_type_is_value_type(PyGTypeWrapper *self) -{ - return PyBool_FromLong(G_TYPE_IS_VALUE_TYPE(self->type)); -} - -static PyObject* -_wrap_g_type_has_value_table(PyGTypeWrapper *self) -{ - return PyBool_FromLong(G_TYPE_HAS_VALUE_TABLE(self->type)); -} - -static PyObject* -_wrap_g_type_from_name(PyGTypeWrapper *_, PyObject *args) -{ - char *type_name; - GType type; - - if (!PyArg_ParseTuple(args, "s:GType.from_name", &type_name)) - return NULL; - - type = g_type_from_name(type_name); - if (type == 0) { - PyErr_SetString(PyExc_RuntimeError, "unknown type name"); - return NULL; - } - - return pyg_type_wrapper_new(type); -} - -static PyObject* -_wrap_g_type_is_a(PyGTypeWrapper *self, PyObject *args) -{ - PyObject *gparent; - GType parent; - - if (!PyArg_ParseTuple(args, "O:GType.is_a", &gparent)) - return NULL; - else if ((parent = pyg_type_from_object(gparent)) == 0) - return NULL; - - return PyBool_FromLong(g_type_is_a(self->type, parent)); -} - -static PyMethodDef _PyGTypeWrapper_methods[] = { - { "is_interface", (PyCFunction)_wrap_g_type_is_interface, METH_NOARGS }, - { "is_classed", (PyCFunction)_wrap_g_type_is_classed, METH_NOARGS }, - { "is_instantiatable", (PyCFunction)_wrap_g_type_is_instantiatable, METH_NOARGS }, - { "is_derivable", (PyCFunction)_wrap_g_type_is_derivable, METH_NOARGS }, - { "is_deep_derivable", (PyCFunction)_wrap_g_type_is_deep_derivable, METH_NOARGS }, - { "is_abstract", (PyCFunction)_wrap_g_type_is_abstract, METH_NOARGS }, - { "is_value_abstract", (PyCFunction)_wrap_g_type_is_value_abstract, METH_NOARGS }, - { "is_value_type", (PyCFunction)_wrap_g_type_is_value_type, METH_NOARGS }, - { "has_value_table", (PyCFunction)_wrap_g_type_has_value_table, METH_NOARGS }, - { "from_name", (PyCFunction)_wrap_g_type_from_name, METH_VARARGS | METH_STATIC }, - { "is_a", (PyCFunction)_wrap_g_type_is_a, METH_VARARGS }, - { NULL, 0, 0 } -}; - -static int -pyg_type_wrapper_init(PyGTypeWrapper *self, PyObject *args, PyObject *kwargs) -{ - static char *kwlist[] = { "object", NULL }; - PyObject *py_object; - GType type; - - if (!PyArg_ParseTupleAndKeywords(args, kwargs, - "O:GType.__init__", - kwlist, &py_object)) - return -1; - - if (!(type = pyg_type_from_object(py_object))) - return -1; - - self->type = type; - - return 0; -} - -/** - * pyg_type_wrapper_new: - * type: a GType - * - * Creates a Python wrapper for a GType. - * - * Returns: the Python wrapper. - */ -PyObject * -pyg_type_wrapper_new(GType type) -{ - PyGTypeWrapper *self; - - self = (PyGTypeWrapper *)PyObject_NEW(PyGTypeWrapper, - &PyGTypeWrapper_Type); - if (self == NULL) - return NULL; - - self->type = type; - return (PyObject *)self; -} - -/** - * pyg_type_from_object_strict: - * obj: a Python object - * strict: if set to TRUE, raises an exception if it can't perform the - * conversion - * - * converts a python object to a GType. If strict is set, raises an - * exception if it can't perform the conversion, otherwise returns - * PY_TYPE_OBJECT. - * - * Returns: the corresponding GType, or 0 on error. - */ - -GType -pyg_type_from_object_strict(PyObject *obj, gboolean strict) -{ - PyObject *gtype; - GType type; - - /* NULL check */ - if (!obj) { - PyErr_SetString(PyExc_TypeError, "can't get type from NULL object"); - return 0; - } - - /* map some standard types to primitive GTypes ... */ - if (obj == Py_None) - return G_TYPE_NONE; - if (PyType_Check(obj)) { - PyTypeObject *tp = (PyTypeObject *)obj; - - if (tp == &PYGLIB_PyLong_Type) - return G_TYPE_INT; - else if (tp == &PyBool_Type) - return G_TYPE_BOOLEAN; - else if (tp == &PyLong_Type) - return G_TYPE_LONG; - else if (tp == &PyFloat_Type) - return G_TYPE_DOUBLE; - else if (tp == &PYGLIB_PyUnicode_Type) - return G_TYPE_STRING; - else if (tp == &PyBaseObject_Type) - return PY_TYPE_OBJECT; - } - - if (Py_TYPE(obj) == &PyGTypeWrapper_Type) { - return ((PyGTypeWrapper *)obj)->type; - } - - /* handle strings */ - if (PYGLIB_PyUnicode_Check(obj)) { - gchar *name = PYGLIB_PyUnicode_AsString(obj); - - type = g_type_from_name(name); - if (type != 0) { - return type; - } - } - - /* finally, look for a __gtype__ attribute on the object */ - gtype = PyObject_GetAttrString(obj, "__gtype__"); - - if (gtype) { - if (Py_TYPE(gtype) == &PyGTypeWrapper_Type) { - type = ((PyGTypeWrapper *)gtype)->type; - Py_DECREF(gtype); - return type; - } - Py_DECREF(gtype); - } - - PyErr_Clear(); - - /* Some API like those that take GValues can hold a python object as - * a pointer. This is potentially dangerous becuase everything is - * passed in as a PyObject so we can't actually type check it. Only - * fallback to PY_TYPE_OBJECT if strict checking is disabled - */ - if (!strict) - return PY_TYPE_OBJECT; - - PyErr_SetString(PyExc_TypeError, "could not get typecode from object"); - return 0; -} - -/** - * pyg_type_from_object: - * obj: a Python object - * - * converts a python object to a GType. Raises an exception if it - * can't perform the conversion. - * - * Returns: the corresponding GType, or 0 on error. - */ -GType -pyg_type_from_object(PyObject *obj) -{ - /* Legacy call always defaults to strict type checking */ - return pyg_type_from_object_strict(obj, TRUE); -} - -/* -------------- GValue marshalling ------------------ */ - -/** - * pyg_enum_get_value: - * @enum_type: the GType of the flag. - * @obj: a Python object representing the flag value - * @val: a pointer to the location to store the integer representation of the flag. - * - * Converts a Python object to the integer equivalent. The conversion - * will depend on the type of the Python object. If the object is an - * integer, it is passed through directly. If it is a string, it will - * be treated as a full or short enum name as defined in the GType. - * - * Returns: 0 on success or -1 on failure - */ -gint -pyg_enum_get_value(GType enum_type, PyObject *obj, gint *val) -{ - GEnumClass *eclass = NULL; - gint res = -1; - - g_return_val_if_fail(val != NULL, -1); - if (!obj) { - *val = 0; - res = 0; - } else if (PYGLIB_PyLong_Check(obj)) { - *val = PYGLIB_PyLong_AsLong(obj); - res = 0; - - if (PyObject_TypeCheck(obj, &PyGEnum_Type) && ((PyGEnum *) obj)->gtype != enum_type) { - g_warning("expected enumeration type %s, but got %s instead", - g_type_name(enum_type), - g_type_name(((PyGEnum *) obj)->gtype)); - } - /* Dumb code duplication, but probably not worth it to have yet another macro. */ - } else if (PyLong_Check(obj)) { - *val = PyLong_AsLong(obj); - res = 0; - - if (PyObject_TypeCheck(obj, &PyGEnum_Type) && ((PyGEnum *) obj)->gtype != enum_type) { - g_warning("expected enumeration type %s, but got %s instead", - g_type_name(enum_type), - g_type_name(((PyGEnum *) obj)->gtype)); - } - } else if (PYGLIB_PyUnicode_Check(obj)) { - GEnumValue *info; - char *str = PYGLIB_PyUnicode_AsString(obj); - - if (enum_type != G_TYPE_NONE) - eclass = G_ENUM_CLASS(g_type_class_ref(enum_type)); - else { - PyErr_SetString(PyExc_TypeError, "could not convert string to enum because there is no GType associated to look up the value"); - res = -1; - } - info = g_enum_get_value_by_name(eclass, str); - g_type_class_unref(eclass); - - if (!info) - info = g_enum_get_value_by_nick(eclass, str); - if (info) { - *val = info->value; - res = 0; - } else { - PyErr_SetString(PyExc_TypeError, "could not convert string"); - res = -1; - } - } else { - PyErr_SetString(PyExc_TypeError,"enum values must be strings or ints"); - res = -1; - } - return res; -} - -/** - * pyg_flags_get_value: - * @flag_type: the GType of the flag. - * @obj: a Python object representing the flag value - * @val: a pointer to the location to store the integer representation of the flag. - * - * Converts a Python object to the integer equivalent. The conversion - * will depend on the type of the Python object. If the object is an - * integer, it is passed through directly. If it is a string, it will - * be treated as a full or short flag name as defined in the GType. - * If it is a tuple, then the items are treated as strings and ORed - * together. - * - * Returns: 0 on success or -1 on failure - */ -gint -pyg_flags_get_value(GType flag_type, PyObject *obj, guint *val) -{ - GFlagsClass *fclass = NULL; - gint res = -1; - - g_return_val_if_fail(val != NULL, -1); - if (!obj) { - *val = 0; - res = 0; - } else if (PYGLIB_PyLong_Check(obj)) { - *val = PYGLIB_PyLong_AsUnsignedLong(obj); - res = 0; - } else if (PyLong_Check(obj)) { - *val = PyLong_AsLongLong(obj); - res = 0; - } else if (PYGLIB_PyUnicode_Check(obj)) { - GFlagsValue *info; - char *str = PYGLIB_PyUnicode_AsString(obj); - - if (flag_type != G_TYPE_NONE) - fclass = G_FLAGS_CLASS(g_type_class_ref(flag_type)); - else { - PyErr_SetString(PyExc_TypeError, "could not convert string to flag because there is no GType associated to look up the value"); - res = -1; - } - info = g_flags_get_value_by_name(fclass, str); - g_type_class_unref(fclass); - - if (!info) - info = g_flags_get_value_by_nick(fclass, str); - if (info) { - *val = info->value; - res = 0; - } else { - PyErr_SetString(PyExc_TypeError, "could not convert string"); - res = -1; - } - } else if (PyTuple_Check(obj)) { - int i, len; - - len = PyTuple_Size(obj); - *val = 0; - res = 0; - - if (flag_type != G_TYPE_NONE) - fclass = G_FLAGS_CLASS(g_type_class_ref(flag_type)); - else { - PyErr_SetString(PyExc_TypeError, "could not convert string to flag because there is no GType associated to look up the value"); - res = -1; - } - - for (i = 0; i < len; i++) { - PyObject *item = PyTuple_GetItem(obj, i); - char *str = PYGLIB_PyUnicode_AsString(item); - GFlagsValue *info = g_flags_get_value_by_name(fclass, str); - - if (!info) - info = g_flags_get_value_by_nick(fclass, str); - if (info) { - *val |= info->value; - } else { - PyErr_SetString(PyExc_TypeError, "could not convert string"); - res = -1; - break; - } - } - g_type_class_unref(fclass); - } else { - PyErr_SetString(PyExc_TypeError, - "flag values must be strings, ints, longs, or tuples"); - res = -1; - } - return res; -} - -typedef struct { - fromvaluefunc fromvalue; - tovaluefunc tovalue; -} PyGTypeMarshal; -static GQuark pyg_type_marshal_key = 0; - -static PyGTypeMarshal * -pyg_type_lookup(GType type) -{ - GType ptype = type; - PyGTypeMarshal *tm = NULL; - - /* recursively lookup types */ - while (ptype) { - if ((tm = g_type_get_qdata(ptype, pyg_type_marshal_key)) != NULL) - break; - ptype = g_type_parent(ptype); - } - return tm; -} - -/** - * pyg_register_gtype_custom: - * @gtype: the GType for the new type - * @from_func: a function to convert GValues to Python objects - * @to_func: a function to convert Python objects to GValues - * - * In order to handle specific conversion of gboxed types or new - * fundamental types, you may use this function to register conversion - * handlers. - */ - -void -pyg_register_gtype_custom(GType gtype, - fromvaluefunc from_func, - tovaluefunc to_func) -{ - PyGTypeMarshal *tm; - - if (!pyg_type_marshal_key) - pyg_type_marshal_key = g_quark_from_static_string("PyGType::marshal"); - - tm = g_new(PyGTypeMarshal, 1); - tm->fromvalue = from_func; - tm->tovalue = to_func; - g_type_set_qdata(gtype, pyg_type_marshal_key, tm); -} - -static int -pyg_value_array_from_pyobject(GValue *value, - PyObject *obj, - const GParamSpecValueArray *pspec) -{ - int len; - GValueArray *value_array; - int i; - - len = PySequence_Length(obj); - if (len == -1) { - PyErr_Clear(); - return -1; - } - - if (pspec && pspec->fixed_n_elements > 0 && len != pspec->fixed_n_elements) - 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; - } - - 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); - - 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_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_with_error: - * @value: the GValue object to store the converted value in. - * @obj: the Python object to convert. - * - * This function converts a Python object and stores the result in a - * GValue. The GValue must be initialised in advance with - * g_value_init(). If the Python object can't be converted to the - * type of the GValue, then an error is returned. - * - * Returns: 0 on success, -1 on error. - */ -int -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)) { - 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 - else if (PyString_Check(obj)) { - g_value_set_schar(value, PyString_AsString(obj)[0]); - } -#endif - 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; - 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) val); - else - return -1; -#if PY_VERSION_HEX < 0x03000000 - } 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; - case G_TYPE_BOOLEAN: - g_value_set_boolean(value, PyObject_IsTrue(obj)); - break; - case G_TYPE_INT: - g_value_set_int(value, PYGLIB_PyLong_AsLong(obj)); - break; - case G_TYPE_UINT: - { - 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; - case G_TYPE_ULONG: -#if PY_VERSION_HEX < 0x03000000 - if (PyInt_Check(obj)) { - long val; - - val = PYGLIB_PyLong_AsLong(obj); - if (val < 0) { - PyErr_SetString(PyExc_OverflowError, "negative value not allowed for uint64 property"); - return -1; - } - g_value_set_ulong(value, (gulong)val); - } else -#endif - 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; - case G_TYPE_UINT64: -#if PY_VERSION_HEX < 0x03000000 - if (PyInt_Check(obj)) { - long v = PyInt_AsLong(obj); - if (v < 0) { - PyErr_SetString(PyExc_OverflowError, "negative value not allowed for uint64 property"); - return -1; - } - g_value_set_uint64(value, v); - } else -#endif - 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) { - return -1; - } - g_value_set_enum(value, val); - } - break; - case G_TYPE_FLAGS: - { - 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; - case G_TYPE_DOUBLE: - 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 { - PyErr_SetString(PyExc_TypeError, "Expected string"); - return -1; - } - } else { -#if PY_VERSION_HEX < 0x03000000 - 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); -#endif - } - 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 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)); - 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)) { - 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_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 (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); - 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: - /* 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 { - 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); - } 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); - 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. - * - * This function creates/returns a Python wrapper object that - * represents the GValue passed as an argument. - * - * Returns: a PyObject representing the value. - */ -PyObject * -pyg_value_as_pyobject(const GValue *value, gboolean copy_boxed) -{ - gchar buf[128]; - - 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; - case G_TYPE_CHAR: { - 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); - } - case G_TYPE_BOOLEAN: { - return PyBool_FromLong(g_value_get_boolean(value)); - } - case G_TYPE_INT: - 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 - 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)); -#else - return PyLong_FromUnsignedLong((gulong) g_value_get_uint(value)); -#endif - } - case G_TYPE_LONG: - return PYGLIB_PyLong_FromLong(g_value_get_long(value)); - case G_TYPE_ULONG: - { - gulong val = g_value_get_ulong(value); - - 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); - - 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); - - 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)); - case G_TYPE_FLAGS: - 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)); - case G_TYPE_DOUBLE: - return PyFloat_FromDouble(g_value_get_double(value)); - case G_TYPE_STRING: - { - const gchar *str = g_value_get_string(value); - - if (str) - return PYGLIB_PyUnicode_FromString(str); - Py_INCREF(Py_None); - return Py_None; - } - case G_TYPE_POINTER: - 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; - - 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); - } - } - case G_TYPE_PARAM: - return pyg_param_spec_new(g_value_get_param(value)); - case G_TYPE_OBJECT: - 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; - } - } - g_snprintf(buf, sizeof(buf), "unknown type %s", - g_type_name(G_VALUE_TYPE(value))); - PyErr_SetString(PyExc_TypeError, buf); - return NULL; -} - -/* -------------- PyGClosure ----------------- */ - -static void -pyg_closure_invalidate(gpointer data, GClosure *closure) -{ - PyGClosure *pc = (PyGClosure *)closure; - PyGILState_STATE state; - - state = pyglib_gil_state_ensure(); - Py_XDECREF(pc->callback); - Py_XDECREF(pc->extra_args); - Py_XDECREF(pc->swap_data); - pyglib_gil_state_release(state); - - pc->callback = NULL; - pc->extra_args = NULL; - pc->swap_data = NULL; -} - -static void -pyg_closure_marshal(GClosure *closure, - GValue *return_value, - guint n_param_values, - const GValue *param_values, - gpointer invocation_hint, - gpointer marshal_data) -{ - PyGILState_STATE state; - PyGClosure *pc = (PyGClosure *)closure; - PyObject *params, *ret; - guint i; - - state = pyglib_gil_state_ensure(); - - /* construct Python tuple for the parameter values */ - params = PyTuple_New(n_param_values); - for (i = 0; i < n_param_values; i++) { - /* swap in a different initial data for connect_object() */ - if (i == 0 && G_CCLOSURE_SWAP_DATA(closure)) { - g_return_if_fail(pc->swap_data != NULL); - Py_INCREF(pc->swap_data); - PyTuple_SetItem(params, 0, pc->swap_data); - } else { - PyObject *item = pyg_value_as_pyobject(¶m_values[i], FALSE); - - /* error condition */ - if (!item) { - goto out; - } - PyTuple_SetItem(params, i, item); - } - } - /* 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 == NULL) { - if (pc->exception_handler) - pc->exception_handler(return_value, n_param_values, param_values); - else - PyErr_Print(); - goto out; - } - - 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); - else - PyErr_Print(); - } - Py_DECREF(ret); - - out: - Py_DECREF(params); - pyglib_gil_state_release(state); -} - -/** - * pyg_closure_new: - * callback: a Python callable object - * extra_args: a tuple of extra arguments, or None/NULL. - * swap_data: an alternative python object to pass first. - * - * Creates a GClosure wrapping a Python callable and optionally a set - * of additional function arguments. This is needed to attach python - * handlers to signals, for instance. - * - * Returns: the new closure. - */ -GClosure * -pyg_closure_new(PyObject *callback, PyObject *extra_args, PyObject *swap_data) -{ - 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, pyg_closure_invalidate); - g_closure_set_marshal(closure, pyg_closure_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; - } - if (swap_data) { - Py_INCREF(swap_data); - ((PyGClosure *)closure)->swap_data = swap_data; - closure->derivative_flag = TRUE; - } - return closure; -} - -/** - * pyg_closure_set_exception_handler: - * @closure: a closure created with pyg_closure_new() - * @handler: the handler to call when an exception occurs or NULL for none - * - * Sets the handler to call when an exception occurs during closure invocation. - * The handler is responsible for providing a proper return value to the - * closure invocation. If @handler is %NULL, the default handler will be used. - * The default handler prints the exception to stderr and doesn't touch the - * closure's return value. - */ -void -pyg_closure_set_exception_handler(GClosure *closure, - PyClosureExceptionHandler handler) -{ - PyGClosure *pygclosure; - - g_return_if_fail(closure != NULL); - - pygclosure = (PyGClosure *)closure; - pygclosure->exception_handler = handler; -} -/* -------------- PySignalClassClosure ----------------- */ -/* a closure used for the `class closure' of a signal. As this gets - * all the info from the first argument to the closure and the - * invocation hint, we can have a single closure that handles all - * class closure cases. We call a method by the name of the signal - * with "do_" prepended. - * - * We also remove the first argument from the * param list, as it is - * the instance object, which is passed * implicitly to the method - * object. */ - -static void -pyg_signal_class_closure_marshal(GClosure *closure, - GValue *return_value, - guint n_param_values, - const GValue *param_values, - gpointer invocation_hint, - gpointer marshal_data) -{ - PyGILState_STATE state; - GObject *object; - PyObject *object_wrapper; - GSignalInvocationHint *hint = (GSignalInvocationHint *)invocation_hint; - gchar *method_name, *tmp; - PyObject *method; - PyObject *params, *ret; - guint i, len; - - state = pyglib_gil_state_ensure(); - - g_return_if_fail(invocation_hint != NULL); - /* get the object passed as the first argument to the closure */ - object = g_value_get_object(¶m_values[0]); - g_return_if_fail(object != NULL && G_IS_OBJECT(object)); - - /* get the wrapper for this object */ - object_wrapper = pygobject_new(object); - g_return_if_fail(object_wrapper != NULL); - - /* construct method name for this class closure */ - method_name = g_strconcat("do_", g_signal_name(hint->signal_id), NULL); - - /* convert dashes to underscores. For some reason, g_signal_name - * seems to convert all the underscores in the signal name to - dashes??? */ - for (tmp = method_name; *tmp != '\0'; tmp++) - if (*tmp == '-') *tmp = '_'; - - method = PyObject_GetAttrString(object_wrapper, method_name); - g_free(method_name); - - if (!method) { - PyErr_Clear(); - Py_DECREF(object_wrapper); - pyglib_gil_state_release(state); - return; - } - Py_DECREF(object_wrapper); - - /* construct Python tuple for the parameter values; don't copy boxed values - initially because we'll check after the call to see if a copy is needed. */ - params = PyTuple_New(n_param_values - 1); - for (i = 1; i < n_param_values; i++) { - PyObject *item = pyg_value_as_pyobject(¶m_values[i], FALSE); - - /* error condition */ - if (!item) { - Py_DECREF(params); - pyglib_gil_state_release(state); - return; - } - PyTuple_SetItem(params, i - 1, item); - } - - ret = PyObject_CallObject(method, params); - - /* Copy boxed values if others ref them, this needs to be done regardless of - exception status. */ - len = PyTuple_Size(params); - for (i = 0; i < len; i++) { - PyObject *item = PyTuple_GetItem(params, i); - if (item != NULL && PyObject_TypeCheck(item, &PyGBoxed_Type) - && item->ob_refcnt != 1) { - PyGBoxed* boxed_item = (PyGBoxed*)item; - if (!boxed_item->free_on_dealloc) { - boxed_item->boxed = g_boxed_copy(boxed_item->gtype, boxed_item->boxed); - boxed_item->free_on_dealloc = TRUE; - } - } - } - - if (ret == NULL) { - PyErr_Print(); - Py_DECREF(method); - Py_DECREF(params); - pyglib_gil_state_release(state); - return; - } - Py_DECREF(method); - Py_DECREF(params); - if (G_IS_VALUE(return_value)) - pyg_value_from_pyobject(return_value, ret); - Py_DECREF(ret); - pyglib_gil_state_release(state); -} - -/** - * pyg_signal_class_closure_get: - * - * Returns the GClosure used for the class closure of signals. When - * called, it will invoke the method do_signalname (for the signal - * "signalname"). - * - * Returns: the closure. - */ -GClosure * -pyg_signal_class_closure_get(void) -{ - static GClosure *closure; - - if (closure == NULL) { - closure = g_closure_new_simple(sizeof(GClosure), NULL); - g_closure_set_marshal(closure, pyg_signal_class_closure_marshal); - - g_closure_ref(closure); - g_closure_sink(closure); - } - return closure; -} - -GClosure * -gclosure_from_pyfunc(PyGObject *object, PyObject *func) -{ - GSList *l; - PyGObjectData *inst_data; - inst_data = pyg_object_peek_inst_data(object->obj); - if (inst_data) { - for (l = inst_data->closures; l; l = l->next) { - PyGClosure *pyclosure = l->data; - int res = PyObject_RichCompareBool(pyclosure->callback, func, Py_EQ); - if (res == -1) { - PyErr_Clear(); // Is there anything else to do? - } else if (res) { - return (GClosure*)pyclosure; - } - } - } - return NULL; -} - -/* ----- __doc__ descriptor for GObject and GInterface ----- */ - -static void -object_doc_dealloc(PyObject *self) -{ - PyObject_FREE(self); -} - -/* append information about signals of a particular gtype */ -static void -add_signal_docs(GType gtype, GString *string) -{ - GTypeClass *class = NULL; - guint *signal_ids, n_ids = 0, i; - - if (G_TYPE_IS_CLASSED(gtype)) - class = g_type_class_ref(gtype); - signal_ids = g_signal_list_ids(gtype, &n_ids); - - if (n_ids > 0) { - g_string_append_printf(string, "Signals from %s:\n", - g_type_name(gtype)); - - for (i = 0; i < n_ids; i++) { - GSignalQuery query; - guint j; - - g_signal_query(signal_ids[i], &query); - - g_string_append(string, " "); - g_string_append(string, query.signal_name); - g_string_append(string, " ("); - for (j = 0; j < query.n_params; j++) { - g_string_append(string, g_type_name(query.param_types[j])); - if (j != query.n_params - 1) - g_string_append(string, ", "); - } - g_string_append(string, ")"); - if (query.return_type && query.return_type != G_TYPE_NONE) { - g_string_append(string, " -> "); - g_string_append(string, g_type_name(query.return_type)); - } - g_string_append(string, "\n"); - } - g_free(signal_ids); - g_string_append(string, "\n"); - } - if (class) - g_type_class_unref(class); -} - -static void -add_property_docs(GType gtype, GString *string) -{ - GObjectClass *class; - GParamSpec **props; - guint n_props = 0, i; - gboolean has_prop = FALSE; - G_CONST_RETURN gchar *blurb=NULL; - - class = g_type_class_ref(gtype); - props = g_object_class_list_properties(class, &n_props); - - for (i = 0; i < n_props; i++) { - if (props[i]->owner_type != gtype) - continue; /* these are from a parent type */ - - /* print out the heading first */ - if (!has_prop) { - g_string_append_printf(string, "Properties from %s:\n", - g_type_name(gtype)); - has_prop = TRUE; - } - g_string_append_printf(string, " %s -> %s: %s\n", - g_param_spec_get_name(props[i]), - g_type_name(props[i]->value_type), - g_param_spec_get_nick(props[i])); - - /* g_string_append_printf crashes on win32 if the third - argument is NULL. */ - blurb=g_param_spec_get_blurb(props[i]); - if (blurb) - g_string_append_printf(string, " %s\n",blurb); - } - g_free(props); - if (has_prop) - g_string_append(string, "\n"); - g_type_class_unref(class); -} - -static PyObject * -object_doc_descr_get(PyObject *self, PyObject *obj, PyObject *type) -{ - GType gtype = 0; - GString *string; - PyObject *pystring; - - if (obj && pygobject_check(obj, &PyGObject_Type)) { - gtype = G_OBJECT_TYPE(pygobject_get(obj)); - if (!gtype) - PyErr_SetString(PyExc_RuntimeError, "could not get object type"); - } else { - gtype = pyg_type_from_object(type); - } - if (!gtype) - return NULL; - - string = g_string_new_len(NULL, 512); - - if (g_type_is_a(gtype, G_TYPE_INTERFACE)) - g_string_append_printf(string, "Interface %s\n\n", g_type_name(gtype)); - else if (g_type_is_a(gtype, G_TYPE_OBJECT)) - g_string_append_printf(string, "Object %s\n\n", g_type_name(gtype)); - else - g_string_append_printf(string, "%s\n\n", g_type_name(gtype)); - - if (((PyTypeObject *) type)->tp_doc) - g_string_append_printf(string, "%s\n\n", ((PyTypeObject *) type)->tp_doc); - - if (g_type_is_a(gtype, G_TYPE_OBJECT)) { - GType parent = G_TYPE_OBJECT; - GArray *parents = g_array_new(FALSE, FALSE, sizeof(GType)); - int iparent; - - while (parent) { - g_array_append_val(parents, parent); - parent = g_type_next_base(gtype, parent); - } - - for (iparent = parents->len - 1; iparent >= 0; --iparent) { - GType *interfaces; - guint n_interfaces, i; - - parent = g_array_index(parents, GType, iparent); - add_signal_docs(parent, string); - add_property_docs(parent, string); - - /* add docs for implemented interfaces */ - interfaces = g_type_interfaces(parent, &n_interfaces); - for (i = 0; i < n_interfaces; i++) - add_signal_docs(interfaces[i], string); - g_free(interfaces); - } - g_array_free(parents, TRUE); - } - - pystring = PYGLIB_PyUnicode_FromStringAndSize(string->str, string->len); - g_string_free(string, TRUE); - return pystring; -} - -PYGLIB_DEFINE_TYPE("gobject.GObject.__doc__", PyGObjectDoc_Type, PyObject); - -/** - * pyg_object_descr_doc_get: - * - * Returns an object intended to be the __doc__ attribute of GObject - * wrappers. When read in the context of the object it will return - * some documentation about the signals and properties of the object. - * - * Returns: the descriptor. - */ -PyObject * -pyg_object_descr_doc_get(void) -{ - static PyObject *doc_descr = NULL; - - if (!doc_descr) { - Py_TYPE(&PyGObjectDoc_Type) = &PyType_Type; - if (PyType_Ready(&PyGObjectDoc_Type)) - return NULL; - - doc_descr = PyObject_NEW(PyObject, &PyGObjectDoc_Type); - if (doc_descr == NULL) - return NULL; - } - return doc_descr; -} - - -/** - * pyg_pyobj_to_unichar_conv: - * - * Converts PyObject value to a unichar and write result to memory - * pointed to by ptr. Follows the calling convention of a ParseArgs - * converter (O& format specifier) so it may be used to convert function - * arguments. - * - * Returns: 1 if the conversion succeeds and 0 otherwise. If the conversion - * did not succeesd, a Python exception is raised - */ -int pyg_pyobj_to_unichar_conv(PyObject* py_obj, void* ptr) -{ - gunichar* u = ptr; - const Py_UNICODE* uni_buffer; - PyObject* tmp_uni = NULL; - - if (PyUnicode_Check(py_obj)) { - tmp_uni = py_obj; - Py_INCREF(tmp_uni); - } - else { - tmp_uni = PyUnicode_FromObject(py_obj); - if (tmp_uni == NULL) - goto failure; - } - - if ( PyUnicode_GetSize(tmp_uni) != 1) { - PyErr_SetString(PyExc_ValueError, "unicode character value must be 1 character uniode string"); - goto failure; - } - uni_buffer = PyUnicode_AsUnicode(tmp_uni); - if ( uni_buffer == NULL) - goto failure; - *u = uni_buffer[0]; - - Py_DECREF(tmp_uni); - return 1; - - failure: - Py_XDECREF(tmp_uni); - return 0; -} - - -int -pyg_param_gvalue_from_pyobject(GValue* value, - PyObject* py_obj, - const GParamSpec* pspec) -{ - if (G_IS_PARAM_SPEC_UNICHAR(pspec)) { - gunichar u; - - if (!pyg_pyobj_to_unichar_conv(py_obj, &u)) { - PyErr_Clear(); - return -1; - } - g_value_set_uint(value, u); - return 0; - } - else if (G_IS_PARAM_SPEC_VALUE_ARRAY(pspec)) - return pyg_value_array_from_pyobject(value, py_obj, - G_PARAM_SPEC_VALUE_ARRAY(pspec)); - else { - return pyg_value_from_pyobject(value, py_obj); - } -} - -PyObject* -pyg_param_gvalue_as_pyobject(const GValue* gvalue, - gboolean copy_boxed, - const GParamSpec* pspec) -{ - if (G_IS_PARAM_SPEC_UNICHAR(pspec)) { - gunichar u; - Py_UNICODE uni_buffer[2] = { 0, 0 }; - - u = g_value_get_uint(gvalue); - uni_buffer[0] = u; - return PyUnicode_FromUnicode(uni_buffer, 1); - } - else { - return pyg_value_as_pyobject(gvalue, copy_boxed); - } -} - -gboolean -pyg_gtype_is_custom(GType gtype) -{ - return g_type_get_qdata (gtype, pygobject_custom_key) != NULL; -} - -static PyObject * -_pyg_strv_from_gvalue(const GValue *value) -{ - gchar **argv = (gchar **) g_value_get_boxed(value); - int argc = 0, i; - PyObject *py_argv; - - if (argv) { - while (argv[argc]) - argc++; - } - py_argv = PyList_New(argc); - for (i = 0; i < argc; ++i) - PyList_SET_ITEM(py_argv, i, PYGLIB_PyUnicode_FromString(argv[i])); - return py_argv; -} - -static int -_pyg_strv_to_gvalue(GValue *value, PyObject *obj) -{ - Py_ssize_t argc, i; - gchar **argv; - - if (!(PyTuple_Check(obj) || PyList_Check(obj))) - return -1; - - argc = PySequence_Length(obj); - for (i = 0; i < argc; ++i) - if (!PYGLIB_PyUnicode_Check(PySequence_Fast_GET_ITEM(obj, i))) - return -1; - argv = g_new(gchar *, argc + 1); - for (i = 0; i < argc; ++i) - argv[i] = g_strdup(PYGLIB_PyUnicode_AsString(PySequence_Fast_GET_ITEM(obj, i))); - argv[i] = NULL; - g_value_take_boxed(value, argv); - return 0; -} - -void -pygobject_type_register_types(PyObject *d) -{ - PyGTypeWrapper_Type.tp_dealloc = (destructor)pyg_type_wrapper_dealloc; - PyGTypeWrapper_Type.tp_richcompare = pyg_type_wrapper_richcompare; - PyGTypeWrapper_Type.tp_repr = (reprfunc)pyg_type_wrapper_repr; - PyGTypeWrapper_Type.tp_hash = (hashfunc)pyg_type_wrapper_hash; - PyGTypeWrapper_Type.tp_flags = Py_TPFLAGS_DEFAULT; - PyGTypeWrapper_Type.tp_methods = _PyGTypeWrapper_methods; - PyGTypeWrapper_Type.tp_getset = _PyGTypeWrapper_getsets; - PyGTypeWrapper_Type.tp_init = (initproc)pyg_type_wrapper_init; - PYGLIB_REGISTER_TYPE(d, PyGTypeWrapper_Type, "GType"); - - /* This type lazily registered in pyg_object_descr_doc_get */ - PyGObjectDoc_Type.tp_dealloc = (destructor)object_doc_dealloc; - PyGObjectDoc_Type.tp_flags = Py_TPFLAGS_DEFAULT; - PyGObjectDoc_Type.tp_descr_get = (descrgetfunc)object_doc_descr_get; - - pyg_register_gtype_custom(G_TYPE_STRV, - _pyg_strv_from_gvalue, - _pyg_strv_to_gvalue); -} diff --git a/gi/_gobject/pygtype.h b/gi/_gobject/pygtype.h deleted file mode 100644 index 2f9e7ad..0000000 --- a/gi/_gobject/pygtype.h +++ /dev/null @@ -1,28 +0,0 @@ -/* -*- Mode: C; c-basic-offset: 4 -*- - * pygtk- Python bindings for the GTK toolkit. - * Copyright (C) 1998-2003 James Henstridge - * 2004-2008 Johan Dahlin - * pyginterface.c: wrapper for the gobject library. - * - * 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 - */ - -#ifndef __PYGOBJECT_TYPE_H__ -#define __PYGOBJECT_TYPE_H__ - -void pygobject_type_register_types(PyObject *d); - -#endif /* __PYGOBJECT_TYPE_H__ */ diff --git a/gi/_gtktemplate.py b/gi/_gtktemplate.py new file mode 100644 index 0000000..f253887 --- /dev/null +++ b/gi/_gtktemplate.py @@ -0,0 +1,307 @@ +# Copyright 2015 Dustin Spicuzza <dustin@virtualroadside.com> +# 2018 Nikita Churaev <lamefun.x0r@gmail.com> +# 2018 Christoph Reiter <reiter.christoph@gmail.com> +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +# USA + +import os +from collections import abc +from functools import partial + +from gi.repository import GLib, GObject, Gio + + +def _extract_handler_and_args(obj_or_map, handler_name): + handler = None + if isinstance(obj_or_map, abc.Mapping): + handler = obj_or_map.get(handler_name, None) + else: + handler = getattr(obj_or_map, handler_name, None) + + if handler is None: + raise AttributeError('Handler %s not found' % handler_name) + + args = () + if isinstance(handler, abc.Sequence): + if len(handler) == 0: + raise TypeError("Handler %s tuple can not be empty" % handler) + args = handler[1:] + handler = handler[0] + + elif not callable(handler): + raise TypeError('Handler %s is not a method, function or tuple' % handler) + + return handler, args + + +def define_builder_scope(): + from gi.repository import Gtk + + class BuilderScope(GObject.GObject, Gtk.BuilderScope): + + def __init__(self, scope_object=None): + super().__init__() + self._scope_object = scope_object + + def do_create_closure(self, builder, func_name, flags, obj): + current_object = builder.get_current_object() or self._scope_object + + if not self._scope_object: + current_object = builder.get_current_object() + if func_name not in current_object.__gtktemplate_methods__: + return None + + current_object.__gtktemplate_handlers__.add(func_name) + handler_name = current_object.__gtktemplate_methods__[func_name] + else: + current_object = self._scope_object + handler_name = func_name + + swapped = int(flags & Gtk.BuilderClosureFlags.SWAPPED) + if swapped: + raise RuntimeError( + "%r not supported" % GObject.ConnectFlags.SWAPPED) + return None + + handler, args = _extract_handler_and_args(current_object, handler_name) + + if obj: + p = partial(handler, *args, swap_data=obj) + else: + p = partial(handler, *args) + + p.__gtk_template__ = True + return p + + return BuilderScope + + +def connect_func(builder, obj, signal_name, handler_name, + connect_object, flags, cls): + + if handler_name not in cls.__gtktemplate_methods__: + return + + method_name = cls.__gtktemplate_methods__[handler_name] + template_inst = builder.get_object(cls.__gtype_name__) + template_inst.__gtktemplate_handlers__.add(handler_name) + handler = getattr(template_inst, method_name) + + after = int(flags & GObject.ConnectFlags.AFTER) + swapped = int(flags & GObject.ConnectFlags.SWAPPED) + if swapped: + raise RuntimeError( + "%r not supported" % GObject.ConnectFlags.SWAPPED) + + if connect_object is not None: + if after: + func = obj.connect_object_after + else: + func = obj.connect_object + func(signal_name, handler, connect_object) + else: + if after: + func = obj.connect_after + else: + func = obj.connect + func(signal_name, handler) + + +def register_template(cls): + from gi.repository import Gtk + + bound_methods = {} + bound_widgets = {} + + for attr_name, obj in list(cls.__dict__.items()): + if isinstance(obj, CallThing): + setattr(cls, attr_name, obj._func) + handler_name = obj._name + if handler_name is None: + handler_name = attr_name + + if handler_name in bound_methods: + old_attr_name = bound_methods[handler_name] + raise RuntimeError( + "Error while exposing handler %r as %r, " + "already available as %r" % ( + handler_name, attr_name, old_attr_name)) + else: + bound_methods[handler_name] = attr_name + elif isinstance(obj, Child): + widget_name = obj._name + if widget_name is None: + widget_name = attr_name + + if widget_name in bound_widgets: + old_attr_name = bound_widgets[widget_name] + raise RuntimeError( + "Error while exposing child %r as %r, " + "already available as %r" % ( + widget_name, attr_name, old_attr_name)) + else: + bound_widgets[widget_name] = attr_name + cls.bind_template_child_full(widget_name, obj._internal, 0) + + cls.__gtktemplate_methods__ = bound_methods + cls.__gtktemplate_widgets__ = bound_widgets + + if Gtk._version == "4.0": + BuilderScope = define_builder_scope() + cls.set_template_scope(BuilderScope()) + else: + cls.set_connect_func(connect_func, cls) + + base_init_template = cls.init_template + cls.__dontuse_ginstance_init__ = \ + lambda s: init_template(s, cls, base_init_template) + # To make this file work with older PyGObject we expose our init code + # as init_template() but make it a noop when we call it ourselves first + cls.init_template = cls.__dontuse_ginstance_init__ + + +def init_template(self, cls, base_init_template): + self.init_template = lambda: None + + if self.__class__ is not cls: + raise TypeError( + "Inheritance from classes with @Gtk.Template decorators " + "is not allowed at this time") + + self.__gtktemplate_handlers__ = set() + + base_init_template(self) + + for widget_name, attr_name in self.__gtktemplate_widgets__.items(): + self.__dict__[attr_name] = self.get_template_child(cls, widget_name) + + for handler_name, attr_name in self.__gtktemplate_methods__.items(): + if handler_name not in self.__gtktemplate_handlers__: + raise RuntimeError( + "Handler '%s' was declared with @Gtk.Template.Callback " + "but was not present in template" % handler_name) + + +class Child(object): + + def __init__(self, name=None, **kwargs): + self._name = name + self._internal = kwargs.pop("internal", False) + if kwargs: + raise TypeError("Unhandled arguments: %r" % kwargs) + + +class CallThing(object): + + def __init__(self, name, func): + self._name = name + self._func = func + + +class Callback(object): + + def __init__(self, name=None): + self._name = name + + def __call__(self, func): + return CallThing(self._name, func) + + +def validate_resource_path(path): + """Raises GLib.Error in case the resource doesn't exist""" + + try: + Gio.resources_get_info(path, Gio.ResourceLookupFlags.NONE) + except GLib.Error: + # resources_get_info() doesn't handle overlays but we keep using it + # as a fast path. + # https://gitlab.gnome.org/GNOME/pygobject/issues/230 + Gio.resources_lookup_data(path, Gio.ResourceLookupFlags.NONE) + + +class Template(object): + + def __init__(self, **kwargs): + self.string = None + self.filename = None + self.resource_path = None + if "string" in kwargs: + self.string = kwargs.pop("string") + elif "filename" in kwargs: + self.filename = kwargs.pop("filename") + elif "resource_path" in kwargs: + self.resource_path = kwargs.pop("resource_path") + else: + raise TypeError( + "Requires one of the following arguments: " + "string, filename, resource_path") + + if kwargs: + raise TypeError("Unhandled keyword arguments %r" % kwargs) + + @classmethod + def from_file(cls, filename): + return cls(filename=filename) + + @classmethod + def from_string(cls, string): + return cls(string=string) + + @classmethod + def from_resource(cls, resource_path): + return cls(resource_path=resource_path) + + Callback = Callback + + Child = Child + + def __call__(self, cls): + from gi.repository import Gtk + + if not isinstance(cls, type) or not issubclass(cls, Gtk.Widget): + raise TypeError("Can only use @Gtk.Template on Widgets") + + if "__gtype_name__" not in cls.__dict__: + raise TypeError( + "%r does not have a __gtype_name__. Set it to the name " + "of the class in your template" % cls.__name__) + + if hasattr(cls, "__gtktemplate_methods__"): + raise TypeError("Cannot nest template classes") + + if self.string is not None: + data = self.string + if not isinstance(data, bytes): + data = data.encode("utf-8") + bytes_ = GLib.Bytes.new(data) + cls.set_template(bytes_) + register_template(cls) + return cls + elif self.resource_path is not None: + validate_resource_path(self.resource_path) + cls.set_template_from_resource(self.resource_path) + register_template(cls) + return cls + else: + assert self.filename is not None + file_ = Gio.File.new_for_path(os.fspath(self.filename)) + bytes_ = GLib.Bytes.new(file_.load_contents()[1]) + cls.set_template(bytes_) + register_template(cls) + return cls + + +__all__ = ["Template"] diff --git a/gi/_glib/option.py b/gi/_option.py index 54e802f..2fa54d8 100644 --- a/gi/_glib/option.py +++ b/gi/_option.py @@ -15,9 +15,7 @@ # 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 +# License along with this library; if not, see <http://www.gnu.org/licenses/>. """GOption command line parser @@ -33,16 +31,10 @@ import sys import optparse from optparse import OptParseError, OptionError, OptionValueError, \ BadOptionError, OptionConflictError -from ..module import get_introspection_module +from .module import get_introspection_module -if sys.version_info >= (3, 0): - _basestring = str - _bytes = lambda s: s.encode() -else: - _basestring = basestring - _bytes = str - -from gi._glib import _glib +from gi import _gi +from gi._error import GError GLib = get_introspection_module('GLib') OPTION_CONTEXT_ERROR_QUARK = GLib.quark_to_string(GLib.option_error_quark()) @@ -70,17 +62,20 @@ class Option(optparse.Option): filename The supplied arguments are read as filename, GOption parses this type in with the GLib filename encoding. - Attributes: - optional_arg This does not need a arguement, but it can be supplied. - hidden The help list does not show this option - in_main This option apears in the main group, this should only - be used for backwards compatibility. + :ivar optional_arg: + This does not need a arguement, but it can be supplied. + :ivar hidden: + The help list does not show this option + :ivar in_main: + This option apears in the main group, this should only + be used for backwards compatibility. Use Option.REMAINING as option name to get all positional arguments. - NOTE: Every argument to an option is passed as utf-8 coded string, the only - exception are options which use the 'filename' type, its arguments - are passed as strings in the GLib filename encoding. + .. NOTE:: + Every argument to an option is passed as utf-8 coded string, the only + exception are options which use the 'filename' type, its arguments + are passed as strings in the GLib filename encoding. For further help, see optparse.Option. """ @@ -135,28 +130,36 @@ class Option(optparse.Option): flags |= GLib.OptionFlags.FILENAME for (long_name, short_name) in zip(self._long_opts, self._short_opts): - yield (long_name[2:], _bytes(short_name[1]), flags, self.help, self.metavar) + short_bytes = short_name[1] + if not isinstance(short_bytes, bytes): + short_bytes = short_bytes.encode("utf-8") + yield (long_name[2:], short_bytes, flags, self.help, self.metavar) for long_name in self._long_opts[len(self._short_opts):]: - yield (long_name[2:], _bytes('\0'), flags, self.help, self.metavar) + yield (long_name[2:], b'\0', flags, self.help, self.metavar) class OptionGroup(optparse.OptionGroup): """A group of command line options. - Arguements: - name: The groups name, used to create the - --help-{name} option - description: Shown as title of the groups help view - help_description: Shown as help to the --help-{name} option - option_list: The options used in this group, must be option.Option() - defaults: A dicitionary of default values - translation_domain: Sets the translation domain for gettext(). - - NOTE: This OptionGroup does not exactly map the optparse.OptionGroup - interface. There is no parser object to supply, but it is possible - to set default values and option_lists. Also the default values and - values are not shared with the OptionParser. + :param str name: + The groups name, used to create the --help-{name} option + :param str description: + Shown as title of the groups help view + :param str help_description: + Shown as help to the --help-{name} option + :param list option_list: + The options used in this group, must be option.Option() + :param dict defaults: + A dicitionary of default values + :param translation_domain: + Sets the translation domain for gettext(). + + .. NOTE:: + This OptionGroup does not exactly map the optparse.OptionGroup + interface. There is no parser object to supply, but it is possible + to set default values and option_lists. Also the default values and + values are not shared with the OptionParser. To pass a OptionGroup into a function which expects a GOptionGroup (e.g. gnome_program_init() ). OptionGroup.get_option_group() can be used. @@ -196,14 +199,14 @@ class OptionGroup(optparse.OptionGroup): opt.process(option_name, option_value, self.values, parser) except OptionValueError: error = sys.exc_info()[1] - gerror = _glib.GError(str(error)) + gerror = GError(str(error)) gerror.domain = OPTION_CONTEXT_ERROR_QUARK gerror.code = GLib.OptionError.BAD_VALUE gerror.message = str(error) raise gerror - group = _glib.OptionGroup(self.name, self.description, - self.help_description, callback) + group = _gi.OptionGroup(self.name, self.description, + self.help_description, callback) if self.translation_domain: group.set_translation_domain(self.translation_domain) @@ -226,7 +229,7 @@ class OptionGroup(optparse.OptionGroup): def set_values_to_defaults(self): for option in self.option_list: default = self.defaults.get(option.dest) - if isinstance(default, _basestring): + if isinstance(default, str): opt_str = option.get_opt_string() self.defaults[option.dest] = option.check_value( opt_str, default) @@ -236,15 +239,16 @@ class OptionGroup(optparse.OptionGroup): class OptionParser(optparse.OptionParser): """Command line parser with GOption support. - NOTE: The OptionParser interface is not the exactly the same as the - optparse.OptionParser interface. Especially the usage parameter - is only used to show the metavar of the arguements. + :param bool help_enabled: + The --help, --help-all and --help-{group} options are enabled (default). + :param bool ignore_unknown_options: + Do not throw a exception when a option is not knwon, the option + will be in the result list. - Attribues: - help_enabled: The --help, --help-all and --help-{group} - options are enabled (default). - ignore_unknown_options: Do not throw a exception when a option is not - knwon, the option will be in the result list. + .. NOTE:: + The OptionParser interface is not the exactly the same as the + optparse.OptionParser interface. Especially the usage parameter + is only used to show the metavar of the arguements. OptionParser.add_option_group() does not only accept OptionGroup instances but also glib.OptionGroup, which is returned by gtk_get_option_group(). @@ -277,12 +281,12 @@ class OptionParser(optparse.OptionParser): parameter_string = self.usage + " - " + self.description else: parameter_string = self.usage - context = _glib.OptionContext(parameter_string) + context = _gi.OptionContext(parameter_string) context.set_help_enabled(self.help_enabled) context.set_ignore_unknown_options(self.ignore_unknown_options) for option_group in self.option_groups: - if isinstance(option_group, _glib.OptionGroup): + if isinstance(option_group, _gi.OptionGroup): g_group = option_group else: g_group = option_group.get_option_group(self) @@ -295,7 +299,7 @@ class OptionParser(optparse.OptionParser): opt = self._short_opt[option_name] opt.process(option_name, option_value, values, self) - main_group = _glib.OptionGroup(None, None, None, callback) + main_group = _gi.OptionGroup(None, None, None, callback) main_entries = [] for option in self.option_list: main_entries.extend(option._to_goptionentries()) @@ -305,7 +309,7 @@ class OptionParser(optparse.OptionParser): return context def add_option_group(self, *args, **kwargs): - if isinstance(args[0], _basestring): + if isinstance(args[0], str): optparse.OptionParser.add_option_group(self, OptionGroup(self, *args, **kwargs)) return @@ -315,7 +319,7 @@ class OptionParser(optparse.OptionParser): args[0].parser = self if args[0].parser is not self: raise ValueError("invalid OptionGroup (wrong parser)") - if isinstance(args[0], _glib.OptionGroup): + if isinstance(args[0], _gi.OptionGroup): self.option_groups.append(args[0]) return optparse.OptionParser.add_option_group(self, *args, **kwargs) @@ -336,11 +340,10 @@ class OptionParser(optparse.OptionParser): rargs[:] = context.parse([sys.argv[0]] + rargs)[1:] def parse_args(self, args=None, values=None): - old_args = args or [] try: options, args = optparse.OptionParser.parse_args( self, args, values) - except _glib.GError: + except GError: error = sys.exc_info()[1] if error.domain != OPTION_CONTEXT_ERROR_QUARK: raise @@ -357,7 +360,7 @@ class OptionParser(optparse.OptionParser): for key, value in group.values.__dict__.items(): options.ensure_value(key, value) - args = args[2:-len(old_args)] return options, args + make_option = Option diff --git a/gi/_ossighelper.py b/gi/_ossighelper.py new file mode 100644 index 0000000..fba24e6 --- /dev/null +++ b/gi/_ossighelper.py @@ -0,0 +1,239 @@ +# Copyright 2017 Christoph Reiter +# +# 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, see <http://www.gnu.org/licenses/>. + +from __future__ import print_function + +import os +import socket +import signal +import threading +from contextlib import closing, contextmanager + +from . import _gi + + +def ensure_socket_not_inheritable(sock): + """Ensures that the socket is not inherited by child processes + + Raises: + EnvironmentError + NotImplementedError: With Python <3.4 on Windows + """ + + if hasattr(sock, "set_inheritable"): + sock.set_inheritable(False) + else: + try: + import fcntl + except ImportError: + raise NotImplementedError( + "Not implemented for older Python on Windows") + else: + fd = sock.fileno() + flags = fcntl.fcntl(fd, fcntl.F_GETFD) + fcntl.fcntl(fd, fcntl.F_SETFD, flags | fcntl.FD_CLOEXEC) + + +_wakeup_fd_is_active = False +"""Since we can't check if set_wakeup_fd() is already used for nested event +loops without introducing a race condition we keep track of it globally. +""" + + +@contextmanager +def wakeup_on_signal(): + """A decorator for functions which create a glib event loop to keep + Python signal handlers working while the event loop is idling. + + In case an OS signal is received will wake the default event loop up + shortly so that any registered Python signal handlers registered through + signal.signal() can run. + + In case the wrapped function is not called from the main thread it will be + called as is and it will not wake up the default loop for signals. + """ + + global _wakeup_fd_is_active + + if _wakeup_fd_is_active: + yield + return + + from gi.repository import GLib + + read_socket, write_socket = socket.socketpair() + with closing(read_socket), closing(write_socket): + + for sock in [read_socket, write_socket]: + sock.setblocking(False) + ensure_socket_not_inheritable(sock) + + try: + orig_fd = signal.set_wakeup_fd(write_socket.fileno()) + except ValueError: + # Raised in case this is not the main thread -> give up. + yield + return + else: + _wakeup_fd_is_active = True + + def signal_notify(source, condition): + if condition & GLib.IO_IN: + try: + return bool(read_socket.recv(1)) + except EnvironmentError as e: + print(e) + return False + return True + else: + return False + + try: + if os.name == "nt": + channel = GLib.IOChannel.win32_new_socket( + read_socket.fileno()) + else: + channel = GLib.IOChannel.unix_new(read_socket.fileno()) + + source_id = GLib.io_add_watch( + channel, + GLib.PRIORITY_DEFAULT, + (GLib.IOCondition.IN | GLib.IOCondition.HUP | + GLib.IOCondition.NVAL | GLib.IOCondition.ERR), + signal_notify) + try: + yield + finally: + GLib.source_remove(source_id) + finally: + write_fd = signal.set_wakeup_fd(orig_fd) + if write_fd != write_socket.fileno(): + # Someone has called set_wakeup_fd while func() was active, + # so let's re-revert again. + signal.set_wakeup_fd(write_fd) + _wakeup_fd_is_active = False + + +PyOS_getsig = _gi.pyos_getsig + +# We save the signal pointer so we can detect if glib has changed the +# signal handler behind Python's back (GLib.unix_signal_add) +if signal.getsignal(signal.SIGINT) is signal.default_int_handler: + startup_sigint_ptr = PyOS_getsig(signal.SIGINT) +else: + # Something has set the handler before import, we can't get a ptr + # for the default handler so make sure the pointer will never match. + startup_sigint_ptr = -1 + + +def sigint_handler_is_default(): + """Returns if on SIGINT the default Python handler would be called""" + + return (signal.getsignal(signal.SIGINT) is signal.default_int_handler and + PyOS_getsig(signal.SIGINT) == startup_sigint_ptr) + + +@contextmanager +def sigint_handler_set_and_restore_default(handler): + """Context manager for saving/restoring the SIGINT handler default state. + + Will only restore the default handler again if the handler is not changed + while the context is active. + """ + + assert sigint_handler_is_default() + + signal.signal(signal.SIGINT, handler) + sig_ptr = PyOS_getsig(signal.SIGINT) + try: + yield + finally: + if signal.getsignal(signal.SIGINT) is handler and \ + PyOS_getsig(signal.SIGINT) == sig_ptr: + signal.signal(signal.SIGINT, signal.default_int_handler) + + +def is_main_thread(): + """Returns True in case the function is called from the main thread""" + + return threading.current_thread().name == "MainThread" + + +_callback_stack = [] +_sigint_called = False + + +@contextmanager +def register_sigint_fallback(callback): + """Installs a SIGINT signal handler in case the default Python one is + active which calls 'callback' in case the signal occurs. + + Only does something if called from the main thread. + + In case of nested context managers the signal handler will be only + installed once and the callbacks will be called in the reverse order + of their registration. + + The old signal handler will be restored in case no signal handler is + registered while the context is active. + """ + + # To handle multiple levels of event loops we need to call the last + # callback first, wait until the inner most event loop returns control + # and only then call the next callback, and so on... until we + # reach the outer most which manages the signal handler and raises + # in the end + + global _callback_stack, _sigint_called + + if not is_main_thread(): + yield + return + + if not sigint_handler_is_default(): + if _callback_stack: + # This is an inner event loop, append our callback + # to the stack so the parent context can call it. + _callback_stack.append(callback) + try: + yield + finally: + cb = _callback_stack.pop() + if _sigint_called: + cb() + else: + # There is a signal handler set by the user, just do nothing + yield + return + + _sigint_called = False + + def sigint_handler(sig_num, frame): + global _callback_stack, _sigint_called + + if _sigint_called: + return + _sigint_called = True + _callback_stack.pop()() + + _callback_stack.append(callback) + try: + with sigint_handler_set_and_restore_default(sigint_handler): + yield + finally: + if _sigint_called: + signal.default_int_handler(signal.SIGINT, None) + else: + _callback_stack.pop() diff --git a/gi/_gobject/propertyhelper.py b/gi/_propertyhelper.py index c9400df..def34b2 100644 --- a/gi/_gobject/propertyhelper.py +++ b/gi/_propertyhelper.py @@ -2,7 +2,7 @@ # pygobject - Python bindings for the GObject library # Copyright (C) 2007 Johan Dahlin # -# gobject/propertyhelper.py: GObject property wrapper/helper +# gi/_propertyhelper.py: GObject property wrapper/helper # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public @@ -15,67 +15,83 @@ # 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 +# License along with this library; if not, see <http://www.gnu.org/licenses/>. -import sys - -from . import _gobject - -from .constants import \ +from . import _gi +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, 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 - _long = int -else: - _basestring = basestring - _long = long +G_MAXFLOAT = _gi.G_MAXFLOAT +G_MAXDOUBLE = _gi.G_MAXDOUBLE +G_MININT = _gi.G_MININT +G_MAXINT = _gi.G_MAXINT +G_MAXUINT = _gi.G_MAXUINT +G_MINLONG = _gi.G_MINLONG +G_MAXLONG = _gi.G_MAXLONG +G_MAXULONG = _gi.G_MAXULONG 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) + """Creates a new Property which when used in conjunction with + GObject subclass will create a Python property accessor for the + GObject ParamSpec. + + :param callable getter: + getter to get the value of the property + :param callable setter: + setter to set the value of the property + :param type type: + type of property + :param default: + default value, must match the property type. + :param str nick: + short description + :param str blurb: + long description + :param GObject.ParamFlags flags: + parameter flags + :keyword minimum: + minimum allowed value (int, float, long only) + :keyword maximum: + maximum allowed value (int, float, long only) + + .. code-block:: python + + class MyObject(GObject.Object): + prop = GObject.Property(type=str) obj = MyObject() obj.prop = 'value' obj.prop # now is 'value' - The API is similar to the builtin property: + The API is similar to the builtin :py:func:`property`: + + .. code-block:: python - class AnotherObject(GObject.GObject): - @GObject.Property - def prop(self): - '''Read only property.''' - return ... + class AnotherObject(GObject.Object): + value = 0 - @GObject.Property(type=int) - def propInt(self): - '''Read-write integer property.''' - return ... + @GObject.Property + def prop(self): + 'Read only property.' + return 1 - @propInt.setter - def propInt(self, value): - ... + @GObject.Property(type=int) + def propInt(self): + 'Read-write integer property.' + return self.value + + @propInt.setter + def propInt(self, value): + self.value = 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, @@ -123,31 +139,8 @@ class Property(object): return "<class 'GObject.Property'>" def __init__(self, getter=None, setter=None, type=None, default=None, - nick='', blurb='', flags=_gobject.PARAM_READWRITE, + nick='', blurb='', flags=_gi.PARAM_READWRITE, minimum=None, maximum=None): - """ - @param getter: getter to get the value of the property - @type getter: callable - @param setter: setter to set the value of the property - @type setter: callable - @param type: type of property - @type type: type - @param default: default value - @param nick: short description - @type nick: string - @param blurb: long description - @type blurb: string - @param flags: parameter flags, one of: - - gobject.PARAM_READABLE - - gobject.PARAM_READWRITE - - gobject.PARAM_WRITABLE - - gobject.PARAM_CONSTRUCT - - gobject.PARAM_CONSTRUCT_ONLY - - gobject.PARAM_LAX_VALIDATION - @keyword minimum: minimum allowed value (int, float, long only) - @keyword maximum: maximum allowed value (int, float, long only) - """ - self.name = None if type is None: @@ -156,11 +149,11 @@ class Property(object): self.default = self._get_default(default) self._check_default() - if not isinstance(nick, _basestring): + if not isinstance(nick, str): raise TypeError("nick must be a string") self.nick = nick - if not isinstance(blurb, _basestring): + if not isinstance(blurb, str): raise TypeError("blurb must be a string") self.blurb = blurb # Always clobber __doc__ with blurb even if blurb is empty because @@ -204,14 +197,14 @@ class Property(object): def __repr__(self): return '<GObject Property %s (%s)>' % ( self.name or '(uninitialized)', - _gobject.type_name(self.type)) + self.type.name) def __get__(self, instance, klass): if instance is None: return self self._exc = None - value = instance.get_property(self.name) + value = self.fget(instance) if self._exc: exc = self._exc self._exc = None @@ -257,11 +250,11 @@ class Property(object): 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.GFlags, - _gobject.GBoxed, - _gobject.GInterface))): + issubclass(type_, (_gi.GObject, + _gi.GEnum, + _gi.GFlags, + _gi.GBoxed, + _gi.GInterface))): return type_.__gtype__ elif type_ in (TYPE_NONE, TYPE_INTERFACE, TYPE_CHAR, TYPE_UCHAR, TYPE_INT, TYPE_UINT, TYPE_BOOLEAN, TYPE_LONG, @@ -290,24 +283,24 @@ class Property(object): 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): + elif ptype.is_a(TYPE_ENUM): if default is None: raise TypeError("enum properties needs a default value") - elif not _gobject.type_is_a(default, ptype): + elif not _gi.GType(default).is_a(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): + elif ptype.is_a(TYPE_FLAGS): + if not _gi.GType(default).is_a(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: + elif ptype.is_a(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): + elif ptype.is_a(TYPE_VARIANT) and default is not None: + if not hasattr(default, '__gtype__') or not _gi.GType(default).is_a(TYPE_VARIANT): raise TypeError("variant value %s must be an instance of %r" % (default, ptype)) @@ -398,9 +391,7 @@ def install_properties(cls): def obj_get_property(self, pspec): name = pspec.name.replace('-', '_') - prop = getattr(cls, name, None) - if prop: - return prop.fget(self) + return getattr(self, name, None) cls.do_get_property = obj_get_property def obj_set_property(self, pspec, value): diff --git a/gi/_gobject/signalhelper.py b/gi/_signalhelper.py index b630158..8a1f0a4 100644 --- a/gi/_gobject/signalhelper.py +++ b/gi/_signalhelper.py @@ -2,7 +2,7 @@ # pygobject - Python bindings for the GObject library # Copyright (C) 2012 Simon Feltman # -# gobject/signalhelper.py: GObject signal binding decorator object +# gi/_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 @@ -15,52 +15,60 @@ # 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 +# License along with this library; if not, see <http://www.gnu.org/licenses/>. -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__') +from . import _gi 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() + """Object which gives a nice API for creating and binding signals. + + :param name: + Name of signal or callable closure when used as a decorator. + :type name: str or callable + :param callable func: + Callable closure method. + :param GObject.SignalFlags flags: + Flags specifying when to run closure. + :param type return_type: + Return type of the Signal. + :param list arg_types: + List of argument types specifying the signals function signature + :param str doc: + Documentation of signal object. + :param callable accumulator: + Accumulator method with the signature: + func(ihint, return_accu, handler_return, accu_data) -> boolean + :param object accu_data: + User data passed to the accumulator. + + :Example: + + .. code-block:: python + + class Spam(GObject.Object): + 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): """ @@ -83,12 +91,12 @@ class Signal(str): 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 + """Same as GObject.Object.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 + """Same as GObject.Object.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. @@ -96,11 +104,11 @@ class Signal(str): return self.gobj.connect(self + '::' + detail, callback, *args, **kargs) def disconnect(self, handler_id): - """Same as GObject.GObject.disconnect.""" - self.instance.disconnect(handler_id) + """Same as GObject.Object.disconnect.""" + self.gobj.disconnect(handler_id) def emit(self, *args, **kargs): - """Same as GObject.GObject.emit except there is no need to specify + """Same as GObject.Object.emit except there is no need to specify the signal name.""" return self.gobj.emit(str(self), *args, **kargs) @@ -109,32 +117,11 @@ class Signal(str): name = name.__name__ return str.__new__(cls, name) - def __init__(self, name='', func=None, flags=_gobject.SIGNAL_RUN_FIRST, + def __init__(self, name='', func=None, flags=_gi.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): + if func is None and callable(name): func = name - name = func.__name__ + if func and not doc: doc = func.__doc__ @@ -165,7 +152,7 @@ class Signal(str): # 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): + if isinstance(obj, _gi.GObject): self.func(obj, *args, **kargs) else: # If self is already an allocated name, use it otherwise create a new named @@ -181,8 +168,7 @@ class Signal(str): 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) @@ -193,14 +179,17 @@ class Signal(str): class SignalOverride(Signal): - """Specialized sub-class of signal which can be used as a decorator for overriding + """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 + :Example: + + .. code-block:: python + + class MyWidget(Gtk.Widget): + @GObject.SignalOverride + def configure_event(self): + pass """ def get_signal_args(self): """Returns the string 'override'.""" @@ -217,6 +206,8 @@ def get_signal_annotations(func): return_type = None if hasattr(func, '__annotations__'): + # import inspect only when needed because it takes ~10 msec to load + import inspect spec = inspect.getfullargspec(func) arg_types = tuple(spec.annotations[arg] for arg in spec.args if arg in spec.annotations) diff --git a/gi/docstring.py b/gi/docstring.py index 713bb6e..08bcef9 100644 --- a/gi/docstring.py +++ b/gi/docstring.py @@ -23,9 +23,11 @@ from ._gi import \ VFuncInfo, \ FunctionInfo, \ - DIRECTION_IN, \ - DIRECTION_OUT, \ - DIRECTION_INOUT + CallableInfo, \ + ObjectInfo, \ + StructInfo, \ + Direction, \ + TypeTag #: Module storage for currently registered doc string generator function. @@ -35,21 +37,26 @@ _generate_doc_string_func = None def set_doc_string_generator(func): """Set doc string generator function - :Parameters: - func : callable - Function which takes a GIInfoStruct and returns - documentation for it. + :param callable func: + Callable which takes a GIInfoStruct and returns documentation for it. """ global _generate_doc_string_func _generate_doc_string_func = func def get_doc_string_generator(): + """Returns the currently registered doc string generator.""" return _generate_doc_string_func def generate_doc_string(info): - """Generator a doc string given a GIInfoStruct + """Generate a doc string given a GIInfoStruct. + + :param gi.types.BaseInfo info: + GI info instance to generate documentation for. + :returns: + Generated documentation as a string. + :rtype: str This passes the info struct to the currently registered doc string generator and returns the result. @@ -57,50 +64,142 @@ def generate_doc_string(info): return _generate_doc_string_func(info) -def split_function_info_args(info): - """Split a functions args into a tuple of two lists. - - Note that args marked as DIRECTION_INOUT will be in both lists. - - :Returns: - Tuple of (in_args, out_args) - """ - in_args = [] - out_args = [] - for arg in info.get_arguments(): - direction = arg.get_direction() - if direction in (DIRECTION_IN, DIRECTION_INOUT): - in_args.append(arg) - if direction in (DIRECTION_OUT, DIRECTION_INOUT): - out_args.append(arg) - return (in_args, out_args) - - -def _generate_callable_info_function_signature(info): - """Default doc string generator""" - in_args, out_args = split_function_info_args(info) +_type_tag_to_py_type = {TypeTag.BOOLEAN: bool, + TypeTag.INT8: int, + TypeTag.UINT8: int, + TypeTag.INT16: int, + TypeTag.UINT16: int, + TypeTag.INT32: int, + TypeTag.UINT32: int, + TypeTag.INT64: int, + TypeTag.UINT64: int, + TypeTag.FLOAT: float, + TypeTag.DOUBLE: float, + TypeTag.GLIST: list, + TypeTag.GSLIST: list, + TypeTag.ARRAY: list, + TypeTag.GHASH: dict, + TypeTag.UTF8: str, + TypeTag.FILENAME: str, + TypeTag.UNICHAR: str, + TypeTag.INTERFACE: None, + TypeTag.GTYPE: None, + TypeTag.ERROR: None, + TypeTag.VOID: None, + } + + +def _get_pytype_hint(gi_type): + type_tag = gi_type.get_tag() + py_type = _type_tag_to_py_type.get(type_tag, None) + + if py_type and hasattr(py_type, '__name__'): + return py_type.__name__ + elif type_tag == TypeTag.INTERFACE: + iface = gi_type.get_interface() + + info_name = iface.get_name() + if not info_name: + return gi_type.get_tag_as_string() + + return '%s.%s' % (iface.get_namespace(), info_name) + + return gi_type.get_tag_as_string() + + +def _generate_callable_info_doc(info): in_args_strs = [] if isinstance(info, VFuncInfo): in_args_strs = ['self'] elif isinstance(info, FunctionInfo): if info.is_method(): in_args_strs = ['self'] - elif info.is_constructor(): - in_args_strs = ['cls'] - for arg in in_args: - argstr = arg.get_name() + ':' + arg.get_pytype_hint() - if arg.is_optional(): + args = info.get_arguments() + hint_blacklist = ('void',) + + # Build lists of indices prior to adding the docs because it is possible + # the index retrieved comes before input arguments being used. + ignore_indices = {info.get_return_type().get_array_length()} + user_data_indices = set() + for arg in args: + ignore_indices.add(arg.get_destroy()) + ignore_indices.add(arg.get_type().get_array_length()) + user_data_indices.add(arg.get_closure()) + + # Build input argument strings + for i, arg in enumerate(args): + if arg.get_direction() == Direction.OUT: + continue # skip exclusively output args + if i in ignore_indices: + continue + argstr = arg.get_name() + hint = _get_pytype_hint(arg.get_type()) + if hint not in hint_blacklist: + argstr += ':' + hint + if arg.may_be_null() or i in user_data_indices: + # allow-none or user_data from a closure + argstr += '=None' + elif arg.is_optional(): argstr += '=<optional>' in_args_strs.append(argstr) in_args_str = ', '.join(in_args_strs) - if out_args: - out_args_str = ', '.join(arg.get_name() + ':' + arg.get_pytype_hint() - for arg in out_args) - return '%s(%s) -> %s' % (info.get_name(), in_args_str, out_args_str) + # Build return + output argument strings + out_args_strs = [] + return_hint = _get_pytype_hint(info.get_return_type()) + if not info.skip_return() and return_hint and return_hint not in hint_blacklist: + argstr = return_hint + if info.may_return_null(): + argstr += ' or None' + out_args_strs.append(argstr) + + for i, arg in enumerate(args): + if arg.get_direction() == Direction.IN: + continue # skip exclusively input args + if i in ignore_indices: + continue + argstr = arg.get_name() + hint = _get_pytype_hint(arg.get_type()) + if hint not in hint_blacklist: + argstr += ':' + hint + out_args_strs.append(argstr) + + if out_args_strs: + return '%s(%s) -> %s' % (info.__name__, in_args_str, ', '.join(out_args_strs)) + else: + return '%s(%s)' % (info.__name__, in_args_str) + + +def _generate_class_info_doc(info): + header = '\n:Constructors:\n\n::\n\n' # start with \n to avoid auto indent of other lines + doc = '' + + if isinstance(info, StructInfo): + # Don't show default constructor for disguised (0 length) structs + if info.get_size() > 0: + doc += ' ' + info.get_name() + '()\n' else: - return '%s(%s)' % (info.get_name(), in_args_str) + doc += ' ' + info.get_name() + '(**properties)\n' + + for method_info in info.get_methods(): + if method_info.is_constructor(): + doc += ' ' + _generate_callable_info_doc(method_info) + '\n' + + if doc: + return header + doc + else: + return '' + + +def _generate_doc_dispatch(info): + if isinstance(info, (ObjectInfo, StructInfo)): + return _generate_class_info_doc(info) + + elif isinstance(info, CallableInfo): + return _generate_callable_info_doc(info) + + return '' -set_doc_string_generator(_generate_callable_info_function_signature) +set_doc_string_generator(_generate_doc_dispatch) diff --git a/gi/gimodule.c b/gi/gimodule.c index 12dfb36..9bc86be 100644 --- a/gi/gimodule.c +++ b/gi/gimodule.c @@ -21,14 +21,1469 @@ * USA */ -#include "pygi-private.h" -#include "pygi.h" -#include "pyglib.h" +#include <Python.h> +#include <glib-object.h> + +#include "config.h" +#include "pyginterface.h" +#include "pygi-repository.h" +#include "pygi-type.h" +#include "pygenum.h" +#include "pygboxed.h" +#include "pygflags.h" +#include "pygi-error.h" +#include "pygi-foreign.h" +#include "pygi-resulttuple.h" +#include "pygi-source.h" +#include "pygi-ccallback.h" +#include "pygi-closure.h" +#include "pygi-type.h" +#include "pygi-boxed.h" +#include "pygi-info.h" +#include "pygi-struct.h" +#include "pygobject-object.h" +#include "pygoptioncontext.h" +#include "pygoptiongroup.h" +#include "pygspawn.h" +#include "pygparamspec.h" +#include "pygpointer.h" +#include "pygobject-internal.h" +#include "pygi-value.h" +#include "pygi-property.h" +#include "pygi-util.h" +#include "gimodule.h" +#include "pygi-basictype.h" + +PyObject *PyGIWarning; +PyObject *PyGIDeprecationWarning; +PyObject *_PyGIDefaultArgPlaceholder; -#include <pygobject.h> -#include <pyglib-python-compat.h> +/* Returns a new flag/enum type or %NULL */ +static PyObject * +flags_enum_from_gtype (GType g_type, + PyObject * (add_func) (PyObject *, const char *, + const char *, GType)) +{ + PyObject *new_type; + GIRepository *repository; + GIBaseInfo *info; + const gchar *type_name; -PyObject *PyGIDeprecationWarning; + repository = g_irepository_get_default (); + info = g_irepository_find_by_gtype (repository, g_type); + if (info != NULL) { + type_name = g_base_info_get_name (info); + new_type = add_func (NULL, type_name, NULL, g_type); + g_base_info_unref (info); + } else { + type_name = g_type_name (g_type); + new_type = add_func (NULL, type_name, NULL, g_type); + } + + return new_type; +} + +static void pyg_flags_add_constants(PyObject *module, GType flags_type, + const gchar *strip_prefix); + +/** + * pyg_enum_add_constants: + * @module: a Python module + * @enum_type: the GType of the enumeration. + * @strip_prefix: the prefix to strip from the constant names. + * + * Adds constants to the given Python module for each value name of + * the enumeration. A prefix will be stripped from each enum name. + */ +static void +pyg_enum_add_constants(PyObject *module, GType enum_type, + const gchar *strip_prefix) +{ + GEnumClass *eclass; + guint i; + + if (!G_TYPE_IS_ENUM(enum_type)) { + if (G_TYPE_IS_FLAGS(enum_type)) /* See bug #136204 */ + pyg_flags_add_constants(module, enum_type, strip_prefix); + else + g_warning("`%s' is not an enum type", g_type_name(enum_type)); + return; + } + g_return_if_fail (strip_prefix != NULL); + + eclass = G_ENUM_CLASS(g_type_class_ref(enum_type)); + + for (i = 0; i < eclass->n_values; i++) { + const gchar *name = eclass->values[i].value_name; + gint value = eclass->values[i].value; + + PyModule_AddIntConstant(module, + (char*) pyg_constant_strip_prefix(name, strip_prefix), + (long) value); + } + + g_type_class_unref(eclass); +} + +/** + * pyg_flags_add_constants: + * @module: a Python module + * @flags_type: the GType of the flags type. + * @strip_prefix: the prefix to strip from the constant names. + * + * Adds constants to the given Python module for each value name of + * the flags set. A prefix will be stripped from each flag name. + */ +static void +pyg_flags_add_constants(PyObject *module, GType flags_type, + const gchar *strip_prefix) +{ + GFlagsClass *fclass; + guint i; + + if (!G_TYPE_IS_FLAGS(flags_type)) { + if (G_TYPE_IS_ENUM(flags_type)) /* See bug #136204 */ + pyg_enum_add_constants(module, flags_type, strip_prefix); + else + g_warning("`%s' is not an flags type", g_type_name(flags_type)); + return; + } + g_return_if_fail (strip_prefix != NULL); + + fclass = G_FLAGS_CLASS(g_type_class_ref(flags_type)); + + for (i = 0; i < fclass->n_values; i++) { + const gchar *name = fclass->values[i].value_name; + guint value = fclass->values[i].value; + + PyModule_AddIntConstant(module, + (char*) pyg_constant_strip_prefix(name, strip_prefix), + (long) value); + } + + g_type_class_unref(fclass); +} + +/** + * pyg_set_thread_block_funcs: + * Deprecated, only available for ABI compatibility. + */ +static void +_pyg_set_thread_block_funcs (PyGThreadBlockFunc block_threads_func, + PyGThreadBlockFunc unblock_threads_func) +{ + PyGILState_STATE state = PyGILState_Ensure (); + PyErr_Warn (PyExc_DeprecationWarning, + "Using pyg_set_thread_block_funcs is not longer needed. " + "PyGObject always uses Py_BLOCK/UNBLOCK_THREADS."); + PyGILState_Release (state); +} + +static GParamSpec * +create_property (const gchar *prop_name, + GType prop_type, + const gchar *nick, + const gchar *blurb, + PyObject *args, + GParamFlags flags) +{ + GParamSpec *pspec = NULL; + + switch (G_TYPE_FUNDAMENTAL(prop_type)) { + case G_TYPE_CHAR: + { + gchar minimum, maximum, default_value; + + if (!PyArg_ParseTuple(args, "ccc", &minimum, &maximum, + &default_value)) + return NULL; + pspec = g_param_spec_char (prop_name, nick, blurb, minimum, + maximum, default_value, flags); + } + break; + case G_TYPE_UCHAR: + { + gchar minimum, maximum, default_value; + + if (!PyArg_ParseTuple(args, "ccc", &minimum, &maximum, + &default_value)) + return NULL; + pspec = g_param_spec_uchar (prop_name, nick, blurb, minimum, + maximum, default_value, flags); + } + break; + case G_TYPE_BOOLEAN: + { + gboolean default_value; + + if (!PyArg_ParseTuple(args, "i", &default_value)) + return NULL; + pspec = g_param_spec_boolean (prop_name, nick, blurb, + default_value, flags); + } + break; + case G_TYPE_INT: + { + gint minimum, maximum, default_value; + + if (!PyArg_ParseTuple(args, "iii", &minimum, &maximum, + &default_value)) + return NULL; + pspec = g_param_spec_int (prop_name, nick, blurb, minimum, + maximum, default_value, flags); + } + break; + case G_TYPE_UINT: + { + guint minimum, maximum, default_value; + + if (!PyArg_ParseTuple(args, "III", &minimum, &maximum, + &default_value)) + return NULL; + pspec = g_param_spec_uint (prop_name, nick, blurb, minimum, + maximum, default_value, flags); + } + break; + case G_TYPE_LONG: + { + glong minimum, maximum, default_value; + + if (!PyArg_ParseTuple(args, "lll", &minimum, &maximum, + &default_value)) + return NULL; + pspec = g_param_spec_long (prop_name, nick, blurb, minimum, + maximum, default_value, flags); + } + break; + case G_TYPE_ULONG: + { + gulong minimum, maximum, default_value; + + if (!PyArg_ParseTuple(args, "kkk", &minimum, &maximum, + &default_value)) + return NULL; + pspec = g_param_spec_ulong (prop_name, nick, blurb, minimum, + maximum, default_value, flags); + } + break; + case G_TYPE_INT64: + { + gint64 minimum, maximum, default_value; + + if (!PyArg_ParseTuple(args, "LLL", &minimum, &maximum, + &default_value)) + return NULL; + pspec = g_param_spec_int64 (prop_name, nick, blurb, minimum, + maximum, default_value, flags); + } + break; + case G_TYPE_UINT64: + { + guint64 minimum, maximum, default_value; + + if (!PyArg_ParseTuple(args, "KKK", &minimum, &maximum, + &default_value)) + return NULL; + pspec = g_param_spec_uint64 (prop_name, nick, blurb, minimum, + maximum, default_value, flags); + } + break; + case G_TYPE_ENUM: + { + gint default_value; + PyObject *pydefault; + + if (!PyArg_ParseTuple(args, "O", &pydefault)) + return NULL; + + if (pyg_enum_get_value(prop_type, pydefault, + (gint *)&default_value)) + return NULL; + + pspec = g_param_spec_enum (prop_name, nick, blurb, + prop_type, default_value, flags); + } + break; + case G_TYPE_FLAGS: + { + guint default_value; + PyObject *pydefault; + + if (!PyArg_ParseTuple(args, "O", &pydefault)) + return NULL; + + if (pyg_flags_get_value(prop_type, pydefault, + &default_value)) + return NULL; + + pspec = g_param_spec_flags (prop_name, nick, blurb, + prop_type, default_value, flags); + } + break; + case G_TYPE_FLOAT: + { + gfloat minimum, maximum, default_value; + + if (!PyArg_ParseTuple(args, "fff", &minimum, &maximum, + &default_value)) + return NULL; + pspec = g_param_spec_float (prop_name, nick, blurb, minimum, + maximum, default_value, flags); + } + break; + case G_TYPE_DOUBLE: + { + gdouble minimum, maximum, default_value; + + if (!PyArg_ParseTuple(args, "ddd", &minimum, &maximum, + &default_value)) + return NULL; + pspec = g_param_spec_double (prop_name, nick, blurb, minimum, + maximum, default_value, flags); + } + break; + case G_TYPE_STRING: + { + const gchar *default_value; + + if (!PyArg_ParseTuple(args, "z", &default_value)) + return NULL; + pspec = g_param_spec_string (prop_name, nick, blurb, + default_value, flags); + } + break; + case G_TYPE_PARAM: + if (!PyArg_ParseTuple(args, "")) + return NULL; + pspec = g_param_spec_param (prop_name, nick, blurb, prop_type, flags); + break; + case G_TYPE_BOXED: + if (!PyArg_ParseTuple(args, "")) + return NULL; + pspec = g_param_spec_boxed (prop_name, nick, blurb, prop_type, flags); + break; + case G_TYPE_POINTER: + if (!PyArg_ParseTuple(args, "")) + return NULL; + 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; + } + + if (!pspec) { + char buf[128]; + + g_snprintf(buf, sizeof(buf), "could not create param spec for type %s", + g_type_name(prop_type)); + PyErr_SetString(PyExc_TypeError, buf); + return NULL; + } + + return pspec; +} + +static GParamSpec * +pyg_param_spec_from_object (PyObject *tuple) +{ + Py_ssize_t val_length; + const gchar *prop_name; + GType prop_type; + const gchar *nick, *blurb; + PyObject *slice, *item, *py_prop_type; + GParamSpec *pspec; + gint intvalue; + + val_length = PyTuple_Size(tuple); + if (val_length < 4) { + PyErr_SetString(PyExc_TypeError, + "paramspec tuples must be at least 4 elements long"); + return NULL; + } + + slice = PySequence_GetSlice(tuple, 0, 4); + if (!slice) { + return NULL; + } + + if (!PyArg_ParseTuple(slice, "sOzz", &prop_name, &py_prop_type, &nick, &blurb)) { + Py_DECREF(slice); + return NULL; + } + + Py_DECREF(slice); + + prop_type = pyg_type_from_object(py_prop_type); + if (!prop_type) { + return NULL; + } + + item = PyTuple_GetItem(tuple, val_length-1); + if (!PyLong_Check (item)) { + PyErr_SetString(PyExc_TypeError, + "last element in tuple must be an int"); + return NULL; + } + + if (!pygi_gint_from_py (item, &intvalue)) + return NULL; + + /* slice is the extra items in the tuple */ + slice = PySequence_GetSlice(tuple, 4, val_length-1); + pspec = create_property(prop_name, prop_type, + nick, blurb, slice, + intvalue); + + return pspec; +} + +G_GNUC_BEGIN_IGNORE_DEPRECATIONS + +/** + * pyg_parse_constructor_args: helper function for PyGObject constructors + * @obj_type: GType of the GObject, for parameter introspection + * @arg_names: %NULL-terminated array of constructor argument names + * @prop_names: %NULL-terminated array of property names, with direct + * correspondence to @arg_names + * @params: GParameter array where parameters will be placed; length + * of this array must be at least equal to the number of + * arguments/properties + * @nparams: output parameter to contain actual number of arguments found + * @py_args: array of PyObject* containing the actual constructor arguments + * + * Parses an array of PyObject's and creates a GParameter array + * + * Return value: %TRUE if all is successful, otherwise %FALSE and + * python exception set. + **/ +static gboolean +pyg_parse_constructor_args(GType obj_type, + char **arg_names, + char **prop_names, + GParameter *params, + guint *nparams, + PyObject **py_args) +{ + guint arg_i, param_i; + GObjectClass *oclass; + + oclass = g_type_class_ref(obj_type); + g_return_val_if_fail(oclass, FALSE); + + for (param_i = arg_i = 0; arg_names[arg_i]; ++arg_i) { + GParamSpec *spec; + if (!py_args[arg_i]) + continue; + spec = g_object_class_find_property(oclass, prop_names[arg_i]); + params[param_i].name = prop_names[arg_i]; + g_value_init(¶ms[param_i].value, spec->value_type); + if (pyg_value_from_pyobject(¶ms[param_i].value, py_args[arg_i]) == -1) { + guint i; + PyErr_Format(PyExc_TypeError, "could not convert parameter '%s' of type '%s'", + arg_names[arg_i], g_type_name(spec->value_type)); + g_type_class_unref(oclass); + for (i = 0; i < param_i; ++i) + g_value_unset(¶ms[i].value); + return FALSE; + } + ++param_i; + } + g_type_class_unref(oclass); + *nparams = param_i; + return TRUE; +} + +G_GNUC_END_IGNORE_DEPRECATIONS + +/* Only for backwards compatibility */ +static int +pygobject_enable_threads(void) +{ + return 0; +} + +static int +pygobject_gil_state_ensure (void) +{ + return PyGILState_Ensure (); +} + +static void +pygobject_gil_state_release (int flag) +{ + PyGILState_Release(flag); +} + +static void +pyg_register_class_init(GType gtype, PyGClassInitFunc class_init) +{ + GSList *list; + + list = g_type_get_qdata(gtype, pygobject_class_init_key); + list = g_slist_prepend(list, class_init); + g_type_set_qdata(gtype, pygobject_class_init_key, list); +} + +static gboolean +add_properties (GObjectClass *klass, PyObject *properties) +{ + gboolean ret = TRUE; + Py_ssize_t pos = 0; + PyObject *key, *value; + + while (PyDict_Next(properties, &pos, &key, &value)) { + const gchar *prop_name; + GType prop_type; + const gchar *nick, *blurb; + GParamFlags flags; + Py_ssize_t val_length; + PyObject *slice, *item, *py_prop_type; + GParamSpec *pspec; + + /* values are of format (type,nick,blurb, type_specific_args, flags) */ + + if (!PyUnicode_Check(key)) { + PyErr_SetString(PyExc_TypeError, + "__gproperties__ keys must be strings"); + ret = FALSE; + break; + } + prop_name = PyUnicode_AsUTF8 (key); + + if (!PyTuple_Check(value)) { + PyErr_SetString(PyExc_TypeError, + "__gproperties__ values must be tuples"); + ret = FALSE; + break; + } + val_length = PyTuple_Size(value); + if (val_length < 4) { + PyErr_SetString(PyExc_TypeError, + "__gproperties__ values must be at least 4 elements long"); + ret = FALSE; + break; + } + + slice = PySequence_GetSlice(value, 0, 3); + if (!slice) { + ret = FALSE; + break; + } + if (!PyArg_ParseTuple(slice, "Ozz", &py_prop_type, &nick, &blurb)) { + Py_DECREF(slice); + ret = FALSE; + break; + } + Py_DECREF(slice); + prop_type = pyg_type_from_object(py_prop_type); + if (!prop_type) { + ret = FALSE; + break; + } + item = PyTuple_GetItem(value, val_length-1); + if (!PyLong_Check (item)) { + PyErr_SetString(PyExc_TypeError, + "last element in __gproperties__ value tuple must be an int"); + ret = FALSE; + break; + } + if (!pygi_gint_from_py (item, &flags)) { + ret = FALSE; + break; + } + + /* slice is the extra items in the tuple */ + slice = PySequence_GetSlice(value, 3, val_length-1); + pspec = create_property(prop_name, prop_type, nick, blurb, + slice, flags); + Py_DECREF(slice); + + if (pspec) { + g_object_class_install_property(klass, 1, pspec); + } else { + PyObject *type, *pvalue, *traceback; + ret = FALSE; + PyErr_Fetch(&type, &pvalue, &traceback); + if (PyUnicode_Check(pvalue)) { + char msg[256]; + g_snprintf(msg, 256, + "%s (while registering property '%s' for GType '%s')", + PyUnicode_AsUTF8 (pvalue), + prop_name, G_OBJECT_CLASS_NAME(klass)); + Py_DECREF(pvalue); + value = PyUnicode_FromString (msg); + } + PyErr_Restore(type, pvalue, traceback); + break; + } + } + + return ret; +} + +static gboolean +override_signal(GType instance_type, const gchar *signal_name) +{ + guint signal_id; + + signal_id = g_signal_lookup(signal_name, instance_type); + if (!signal_id) { + gchar buf[128]; + + g_snprintf(buf, sizeof(buf), "could not look up %s", signal_name); + PyErr_SetString(PyExc_TypeError, buf); + return FALSE; + } + g_signal_override_class_closure(signal_id, instance_type, + pyg_signal_class_closure_get()); + return TRUE; +} + +typedef struct _PyGSignalAccumulatorData { + PyObject *callable; + PyObject *user_data; +} PyGSignalAccumulatorData; + + +static gboolean +_pyg_signal_accumulator(GSignalInvocationHint *ihint, + GValue *return_accu, + const GValue *handler_return, + gpointer _data) +{ + PyObject *py_ihint, *py_return_accu, *py_handler_return, *py_detail; + PyObject *py_retval; + gboolean retval = FALSE; + PyGSignalAccumulatorData *data = _data; + PyGILState_STATE state; + + state = PyGILState_Ensure(); + if (ihint->detail) + py_detail = PyUnicode_FromString (g_quark_to_string(ihint->detail)); + else { + Py_INCREF(Py_None); + py_detail = Py_None; + } + + py_ihint = Py_BuildValue("lNi", (long int) ihint->signal_id, + py_detail, ihint->run_type); + py_handler_return = pyg_value_as_pyobject(handler_return, TRUE); + py_return_accu = pyg_value_as_pyobject(return_accu, FALSE); + if (data->user_data) + py_retval = PyObject_CallFunction(data->callable, "NNNO", py_ihint, + py_return_accu, py_handler_return, + data->user_data); + else + py_retval = PyObject_CallFunction(data->callable, "NNN", py_ihint, + py_return_accu, py_handler_return); + if (!py_retval) + PyErr_Print(); + else { + if (!PyTuple_Check(py_retval) || PyTuple_Size(py_retval) != 2) { + PyErr_SetString(PyExc_TypeError, "accumulator function must return" + " a (bool, object) tuple"); + PyErr_Print(); + } else { + retval = PyObject_IsTrue(PyTuple_GET_ITEM(py_retval, 0)); + if (pyg_value_from_pyobject(return_accu, PyTuple_GET_ITEM(py_retval, 1))) { + PyErr_Print(); + } + } + Py_DECREF(py_retval); + } + PyGILState_Release(state); + return retval; +} + +static gboolean +create_signal (GType instance_type, const gchar *signal_name, PyObject *tuple) +{ + GSignalFlags signal_flags; + PyObject *py_return_type, *py_param_types; + GType return_type; + guint n_params, i; + Py_ssize_t py_n_params; + GType *param_types; + guint signal_id; + GSignalAccumulator accumulator = NULL; + PyGSignalAccumulatorData *accum_data = NULL; + PyObject *py_accum = NULL, *py_accum_data = NULL; + + if (!PyArg_ParseTuple(tuple, "iOO|OO", &signal_flags, &py_return_type, + &py_param_types, &py_accum, &py_accum_data)) + { + gchar buf[128]; + + PyErr_Clear(); + g_snprintf(buf, sizeof(buf), + "value for __gsignals__['%s'] not in correct format", signal_name); + PyErr_SetString(PyExc_TypeError, buf); + return FALSE; + } + + if (py_accum && py_accum != Py_None && !PyCallable_Check(py_accum)) + { + gchar buf[128]; + + g_snprintf(buf, sizeof(buf), + "accumulator for __gsignals__['%s'] must be callable", signal_name); + PyErr_SetString(PyExc_TypeError, buf); + return FALSE; + } + + return_type = pyg_type_from_object(py_return_type); + if (!return_type) + return FALSE; + if (!PySequence_Check(py_param_types)) { + gchar buf[128]; + + g_snprintf(buf, sizeof(buf), + "third element of __gsignals__['%s'] tuple must be a sequence", signal_name); + PyErr_SetString(PyExc_TypeError, buf); + return FALSE; + } + py_n_params = PySequence_Length(py_param_types); + if (py_n_params < 0) + return FALSE; + + if (!pygi_guint_from_pyssize (py_n_params, &n_params)) + return FALSE; + + param_types = g_new(GType, n_params); + for (i = 0; i < n_params; i++) { + PyObject *item = PySequence_GetItem(py_param_types, i); + + param_types[i] = pyg_type_from_object(item); + if (param_types[i] == 0) { + Py_DECREF(item); + g_free(param_types); + return FALSE; + } + Py_DECREF(item); + } + + 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, + pyg_signal_class_closure_get(), + accumulator, accum_data, + gi_cclosure_marshal_generic, + return_type, n_params, param_types); + g_free(param_types); + + if (signal_id == 0) { + gchar buf[128]; + + g_snprintf(buf, sizeof(buf), "could not create signal for %s", + signal_name); + PyErr_SetString(PyExc_RuntimeError, buf); + return FALSE; + } + return TRUE; +} + + +static PyObject * +add_signals (GObjectClass *klass, PyObject *signals) +{ + gboolean ret = TRUE; + Py_ssize_t pos = 0; + PyObject *key, *value, *overridden_signals = NULL; + GType instance_type = G_OBJECT_CLASS_TYPE (klass); + + overridden_signals = PyDict_New(); + while (PyDict_Next(signals, &pos, &key, &value)) { + const gchar *signal_name; + gchar *signal_name_canon, *c; + + if (!PyUnicode_Check(key)) { + PyErr_SetString(PyExc_TypeError, + "__gsignals__ keys must be strings"); + ret = FALSE; + break; + } + signal_name = PyUnicode_AsUTF8 (key); + + if (value == Py_None || + (PyUnicode_Check(value) && + !strcmp(PyUnicode_AsUTF8 (value), "override"))) + { + /* canonicalize signal name, replacing '-' with '_' */ + signal_name_canon = g_strdup(signal_name); + for (c = signal_name_canon; *c; ++c) + if (*c == '-') + *c = '_'; + if (PyDict_SetItemString(overridden_signals, + signal_name_canon, key)) { + g_free(signal_name_canon); + ret = FALSE; + break; + } + g_free(signal_name_canon); + + ret = override_signal(instance_type, signal_name); + } else { + ret = create_signal(instance_type, signal_name, value); + } + + if (!ret) + break; + } + if (ret) + return overridden_signals; + else { + Py_XDECREF(overridden_signals); + return NULL; + } +} + +static void +pyg_object_get_property (GObject *object, guint property_id, + GValue *value, GParamSpec *pspec) +{ + PyObject *object_wrapper, *retval; + PyGILState_STATE state; + + state = PyGILState_Ensure(); + + object_wrapper = g_object_get_qdata(object, pygobject_wrapper_key); + + if (object_wrapper) + Py_INCREF (object_wrapper); + else + object_wrapper = pygobject_new(object); + + if (object_wrapper == NULL) { + PyGILState_Release(state); + return; + } + + retval = pygi_call_do_get_property (object_wrapper, pspec); + if (retval && pyg_value_from_pyobject (value, retval) < 0) { + PyErr_Print(); + } + Py_DECREF(object_wrapper); + Py_XDECREF(retval); + + PyGILState_Release(state); +} + +static void +pyg_object_set_property (GObject *object, guint property_id, + const GValue *value, GParamSpec *pspec) +{ + PyObject *object_wrapper, *retval; + PyObject *py_pspec, *py_value; + PyGILState_STATE state; + + state = PyGILState_Ensure(); + + object_wrapper = g_object_get_qdata(object, pygobject_wrapper_key); + + if (object_wrapper) + Py_INCREF (object_wrapper); + else + object_wrapper = pygobject_new(object); + + if (object_wrapper == NULL) { + PyGILState_Release(state); + return; + } + + py_pspec = pyg_param_spec_new(pspec); + py_value = pyg_value_as_pyobject (value, TRUE); + + retval = PyObject_CallMethod(object_wrapper, "do_set_property", + "OO", py_pspec, py_value); + if (retval) { + Py_DECREF(retval); + } else { + PyErr_Print(); + } + + Py_DECREF(object_wrapper); + Py_DECREF(py_pspec); + Py_DECREF(py_value); + + PyGILState_Release(state); +} + +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 GPrivate pygobject_construction_wrapper; + +static inline void +pygobject_init_wrapper_set(PyObject *wrapper) +{ + g_private_set(&pygobject_construction_wrapper, wrapper); +} + +static inline PyObject * +pygobject_init_wrapper_get(void) +{ + return (PyObject *) g_private_get(&pygobject_construction_wrapper); +} + +/** + * Like g_object_new_with_properties() but also works with older glib versions. + */ +GObject * +pygobject_object_new_with_properties(GType object_type, + guint n_properties, + const char *names[], + const GValue values[]) +{ + GObject *obj; + +#if GLIB_CHECK_VERSION(2, 54, 0) + obj = g_object_new_with_properties(object_type, n_properties, names, values); +#else + { + GParameter *parameters; + uint i; + + parameters = g_new(GParameter, n_properties); + for (i = 0; i < n_properties; i++) { + parameters[i].name = names[i]; + parameters[i].value = values[i]; + } + obj = g_object_newv(object_type, n_properties, parameters); + g_free(parameters); + } +#endif + + return obj; +} + +int +pygobject_constructv (PyGObject *self, + guint n_properties, + const char *names[], + const GValue values[]) +{ + GObject *obj; + + g_assert (self->obj == NULL); + pygobject_init_wrapper_set((PyObject *) self); + + obj = pygobject_object_new_with_properties(pyg_type_from_object((PyObject *) self), + n_properties, + names, + values); + + if (g_object_is_floating (obj)) + self->private_flags.flags |= PYGOBJECT_GOBJECT_WAS_FLOATING; + pygobject_sink (obj); + + pygobject_init_wrapper_set(NULL); + self->obj = obj; + pygobject_register_wrapper((PyObject *) self); + + return 0; +} + +static void +pygobject__g_instance_init(GTypeInstance *instance, + gpointer g_class) +{ + GObject *object; + PyObject *wrapper, *result; + PyGILState_STATE state; + gboolean needs_init = FALSE; + + g_return_if_fail(G_IS_OBJECT(instance)); + + object = (GObject *) instance; + + wrapper = g_object_get_qdata(object, pygobject_wrapper_key); + if (wrapper == NULL) { + wrapper = pygobject_init_wrapper_get(); + if (wrapper && ((PyGObject *) wrapper)->obj == NULL) { + ((PyGObject *) wrapper)->obj = object; + pygobject_register_wrapper(wrapper); + } + } + pygobject_init_wrapper_set(NULL); + + state = PyGILState_Ensure(); + + if (wrapper == NULL) { + /* this looks like a python object created through + * g_object_new -> we have no python wrapper, so create it + * now */ + + if (g_object_is_floating (object)) { + g_object_ref (object); + wrapper = pygobject_new_full(object, + /*steal=*/ TRUE, + g_class); + g_object_force_floating (object); + } else { + 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 + * will take the ref */ + pygobject_ref_float ((PyGObject *) wrapper); + + needs_init = TRUE; + } + + /* XXX: used for Gtk.Template */ + if (PyObject_HasAttrString ((PyObject*) Py_TYPE (wrapper), "__dontuse_ginstance_init__")) { + result = PyObject_CallMethod (wrapper, "__dontuse_ginstance_init__", NULL); + if (result == NULL) + PyErr_Print (); + else + Py_DECREF (result); + } + + if (needs_init) { + result = PyObject_CallMethod (wrapper, "__init__", NULL); + if (result == NULL) + PyErr_Print (); + else + Py_DECREF (result); + } + + PyGILState_Release(state); +} + +/* This implementation is bad, see bug 566571 for an example why. + * Instead of scanning explicitly declared bases for interfaces, we + * should automatically initialize all implemented interfaces to + * prevent bugs like that one. However, this will lead to + * performance degradation as each virtual method in derived classes + * will round-trip through do_*() stuff, *even* if it is not + * overriden. We need to teach codegen to retain parent method + * instead of setting virtual to *_proxy_do_*() if corresponding + * do_*() is not overriden. Ok, that was a messy explanation. + */ +static void +pyg_type_add_interfaces(PyTypeObject *class, GType instance_type, + PyObject *bases, + GType *parent_interfaces, guint n_parent_interfaces) +{ + int i; + + if (!bases) { + g_warning("type has no bases"); + return; + } + + for (i = 0; i < PyTuple_GET_SIZE(bases); ++i) { + PyObject *base = PyTuple_GET_ITEM(bases, i); + GType itype; + const GInterfaceInfo *iinfo; + GInterfaceInfo iinfo_copy; + + /* 'base' can also be a PyClassObject, see bug #566571. */ + if (!PyType_Check(base)) + continue; + + if (!PyType_IsSubtype((PyTypeObject*) base, &PyGInterface_Type)) + continue; + + itype = pyg_type_from_object(base); + + /* Happens for _implementations_ of an interface. */ + if (!G_TYPE_IS_INTERFACE(itype)) + continue; + + iinfo = pyg_lookup_interface_info(itype); + if (!iinfo) { + gchar *error; + error = g_strdup_printf("Interface type %s " + "has no Python implementation support", + ((PyTypeObject *) base)->tp_name); + PyErr_Warn(PyExc_RuntimeWarning, error); + g_free(error); + continue; + } + + iinfo_copy = *iinfo; + iinfo_copy.interface_data = class; + g_type_add_interface_static(instance_type, itype, &iinfo_copy); + } +} + +static int +pyg_run_class_init(GType gtype, gpointer gclass, PyTypeObject *pyclass) +{ + GSList *list; + PyGClassInitFunc class_init; + GType parent_type; + int rv; + + parent_type = g_type_parent(gtype); + if (parent_type) { + rv = pyg_run_class_init(parent_type, gclass, pyclass); + if (rv) + return rv; + } + + list = g_type_get_qdata(gtype, pygobject_class_init_key); + for (; list; list = list->next) { + class_init = list->data; + rv = class_init(gclass, pyclass); + if (rv) + return rv; + } + + return 0; +} + +static char * +get_type_name_for_class(PyTypeObject *class) +{ + gint i, name_serial; + char name_serial_str[16]; + PyObject *module; + char *type_name = NULL; + + /* make name for new GType */ + name_serial = 1; + /* give up after 1000 tries, just in case.. */ + while (name_serial < 1000) + { + g_free(type_name); + g_snprintf(name_serial_str, 16, "-v%i", name_serial); + module = PyObject_GetAttrString((PyObject *)class, "__module__"); + if (module && PyUnicode_Check (module)) { + type_name = g_strconcat(PyUnicode_AsUTF8 (module), ".", + class->tp_name, + name_serial > 1 ? name_serial_str : NULL, + NULL); + Py_DECREF(module); + } else { + if (module) + Py_DECREF(module); + else + PyErr_Clear(); + type_name = g_strconcat(class->tp_name, + name_serial > 1 ? name_serial_str : NULL, + NULL); + } + /* convert '.' in type name to '+', which isn't banned (grumble) */ + for (i = 0; type_name[i] != '\0'; i++) + if (type_name[i] == '.') + type_name[i] = '+'; + if (g_type_from_name(type_name) == 0) + break; /* we now have a unique name */ + ++name_serial; + } + + return type_name; +} + +static int +pyg_type_register(PyTypeObject *class, const char *type_name) +{ + PyObject *gtype; + GType parent_type, instance_type; + GType *parent_interfaces; + guint n_parent_interfaces; + GTypeQuery query; + gpointer gclass; + GTypeInfo type_info = { + 0, /* class_size */ + + (GBaseInitFunc) NULL, + (GBaseFinalizeFunc) NULL, + + (GClassInitFunc) pyg_object_class_init, + (GClassFinalizeFunc) NULL, + NULL, /* class_data */ + + 0, /* instance_size */ + 0, /* n_preallocs */ + (GInstanceInitFunc) pygobject__g_instance_init + }; + gchar *new_type_name; + + /* find the GType of the parent */ + parent_type = pyg_type_from_object((PyObject *)class); + if (!parent_type) + return -1; + + parent_interfaces = g_type_interfaces(parent_type, &n_parent_interfaces); + + if (type_name) + /* care is taken below not to free this */ + new_type_name = (gchar *) type_name; + else + new_type_name = get_type_name_for_class(class); + + /* set class_data that will be passed to the class_init function. */ + type_info.class_data = class; + + /* fill in missing values of GTypeInfo struct */ + g_type_query(parent_type, &query); + type_info.class_size = (guint16)query.class_size; + type_info.instance_size = (guint16)query.instance_size; + + /* create new typecode */ + instance_type = g_type_register_static(parent_type, new_type_name, + &type_info, 0); + if (instance_type == 0) { + PyErr_Format(PyExc_RuntimeError, + "could not create new GType: %s (subclass of %s)", + new_type_name, + g_type_name(parent_type)); + + if (type_name == NULL) + g_free(new_type_name); + + return -1; + } + + if (type_name == NULL) + g_free(new_type_name); + + /* store pointer to the class with the GType */ + Py_INCREF(class); + g_type_set_qdata(instance_type, pygobject_class_key, + 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); + Py_DECREF(gtype); + + /* if no __doc__, set it to the auto doc descriptor */ + if (PyDict_GetItemString(class->tp_dict, "__doc__") == NULL) { + PyDict_SetItemString(class->tp_dict, "__doc__", + pyg_object_descr_doc_get()); + } + + /* + * 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, + parent_interfaces, n_parent_interfaces); + + + gclass = g_type_class_ref(instance_type); + if (PyErr_Occurred() != NULL) { + g_type_class_unref(gclass); + g_free(parent_interfaces); + return -1; + } + + if (pyg_run_class_init(instance_type, gclass, class)) { + g_type_class_unref(gclass); + g_free(parent_interfaces); + return -1; + } + g_type_class_unref(gclass); + g_free(parent_interfaces); + + if (PyErr_Occurred() != NULL) + return -1; + return 0; +} + +static PyObject * +_wrap_pyg_type_register(PyObject *self, PyObject *args) +{ + PyTypeObject *class; + char *type_name = NULL; + + if (!PyArg_ParseTuple(args, "O!|z:gobject.type_register", + &PyType_Type, &class, &type_name)) + return NULL; + if (!PyType_IsSubtype(class, &PyGObject_Type)) { + PyErr_SetString(PyExc_TypeError, + "argument must be a GObject subclass"); + return NULL; + } + + /* Check if type already registered */ + if (pyg_type_from_object((PyObject *) class) == + pyg_type_from_object((PyObject *) class->tp_base)) + { + if (pyg_type_register(class, type_name)) + return NULL; + } + + Py_INCREF(class); + return (PyObject *) class; +} + +static GHashTable *log_handlers = NULL; +static gboolean log_handlers_disabled = FALSE; + +static void +remove_handler(gpointer domain, + gpointer handler, + gpointer unused) +{ + g_log_remove_handler(domain, GPOINTER_TO_UINT(handler)); +} + +static void +_log_func(const gchar *log_domain, + GLogLevelFlags log_level, + const gchar *message, + gpointer user_data) +{ + if (G_LIKELY(Py_IsInitialized())) + { + PyGILState_STATE state; + PyObject* warning = user_data; + + state = PyGILState_Ensure(); + PyErr_Warn(warning, (char *) message); + PyGILState_Release(state); + } else + g_log_default_handler(log_domain, log_level, message, user_data); +} + +static void +add_warning_redirection(const char *domain, + PyObject *warning) +{ + g_return_if_fail(domain != NULL); + g_return_if_fail(warning != NULL); + + if (!log_handlers_disabled) + { + guint handler; + gpointer old_handler; + + if (!log_handlers) + log_handlers = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL); + + if ((old_handler = g_hash_table_lookup(log_handlers, domain))) + g_log_remove_handler(domain, GPOINTER_TO_UINT(old_handler)); + + handler = g_log_set_handler(domain, G_LOG_LEVEL_CRITICAL|G_LOG_LEVEL_WARNING, + _log_func, warning); + g_hash_table_insert(log_handlers, g_strdup(domain), GUINT_TO_POINTER(handler)); + } +} + +static void +disable_warning_redirections(void) +{ + log_handlers_disabled = TRUE; + + if (log_handlers) + { + g_hash_table_foreach(log_handlers, remove_handler, NULL); + g_hash_table_destroy(log_handlers); + log_handlers = NULL; + } +} + +/** + * Returns 0 on success, or -1 and sets an exception. + */ +static int +pygi_register_warnings(PyObject *d) +{ + PyObject *warning; + + warning = PyErr_NewException("gobject.Warning", PyExc_Warning, NULL); + if (warning == NULL) + return -1; + PyDict_SetItemString(d, "Warning", warning); + add_warning_redirection("GLib", warning); + add_warning_redirection("GLib-GObject", warning); + add_warning_redirection("GThread", warning); + + return 0; +} static PyObject * _wrap_pyg_enum_add (PyObject *self, @@ -50,7 +1505,7 @@ _wrap_pyg_enum_add (PyObject *self, return NULL; } - return pyg_enum_add (NULL, g_type_name (g_type), NULL, g_type); + return flags_enum_from_gtype (g_type, pyg_enum_add); } static PyObject * @@ -102,7 +1557,7 @@ _wrap_pyg_enum_register_new_gtype_and_add (PyObject *self, enum_value = &g_enum_values[i]; enum_value->value_nick = g_strdup (name); - enum_value->value = g_value_info_get_value (value_info); + enum_value->value = (gint)g_value_info_get_value (value_info); if (c_identifier == NULL) { enum_value->value_name = enum_value->value_nick; @@ -146,7 +1601,7 @@ _wrap_pyg_enum_register_new_gtype_and_add (PyObject *self, } g_free (full_name); - return pyg_enum_add (NULL, g_type_name (g_type), NULL, g_type); + return pyg_enum_add (NULL, type_name, NULL, g_type); } static PyObject * @@ -169,7 +1624,7 @@ _wrap_pyg_flags_add (PyObject *self, return NULL; } - return pyg_flags_add (NULL, g_type_name (g_type), NULL, g_type); + return flags_enum_from_gtype (g_type, pyg_flags_add); } static PyObject * @@ -221,7 +1676,7 @@ _wrap_pyg_flags_register_new_gtype_and_add (PyObject *self, flags_value = &g_flags_values[i]; flags_value->value_nick = g_strdup (name); - flags_value->value = g_value_info_get_value (value_info); + flags_value->value = (guint)g_value_info_get_value (value_info); if (c_identifier == NULL) { flags_value->value_name = flags_value->value_nick; @@ -265,13 +1720,13 @@ _wrap_pyg_flags_register_new_gtype_and_add (PyObject *self, } g_free (full_name); - return pyg_flags_add (NULL, g_type_name (g_type), NULL, g_type); + return pyg_flags_add (NULL, type_name, NULL, g_type); } 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 * @@ -296,6 +1751,7 @@ _wrap_pyg_register_interface_info (PyObject *self, PyObject *args) info->interface_init = (GInterfaceInitFunc) initialize_interface; pyg_register_interface_info (g_type, info); + g_free (info); Py_RETURN_NONE; } @@ -308,11 +1764,11 @@ find_vfunc_info (GIBaseInfo *vfunc_info, GIFieldInfo **field_info_ret) { GType ancestor_g_type = 0; - int length, i; GIBaseInfo *ancestor_info; GIStructInfo *struct_info; gpointer implementor_class = NULL; gboolean is_interface = FALSE; + GIFieldInfo *field_info; ancestor_info = g_base_info_get_container (vfunc_info); is_interface = g_base_info_get_type (ancestor_info) == GI_INFO_TYPE_INTERFACE; @@ -343,28 +1799,18 @@ find_vfunc_info (GIBaseInfo *vfunc_info, *implementor_class_ret = implementor_class; - length = g_struct_info_get_n_fields (struct_info); - for (i = 0; i < length; i++) { - GIFieldInfo *field_info; + field_info = g_struct_info_find_field (struct_info, + g_base_info_get_name ( (GIBaseInfo*) vfunc_info)); + if (field_info != NULL) { GITypeInfo *type_info; - field_info = g_struct_info_get_field (struct_info, i); - - if (strcmp (g_base_info_get_name ( (GIBaseInfo*) field_info), - g_base_info_get_name ( (GIBaseInfo*) vfunc_info)) != 0) { - g_base_info_unref (field_info); - continue; - } - type_info = g_field_info_get_type (field_info); if (g_type_info_get_tag (type_info) == GI_TYPE_TAG_INTERFACE) { - g_base_info_unref (type_info); *field_info_ret = field_info; - break; + } else { + g_base_info_unref (field_info); } - g_base_info_unref (type_info); - g_base_info_unref (field_info); } g_base_info_unref (struct_info); @@ -382,6 +1828,7 @@ _wrap_pyg_hook_up_vfunc_implementation (PyObject *self, PyObject *args) GIFieldInfo *field_info = NULL; gpointer *method_ptr = NULL; PyGICClosure *closure = NULL; + PyGIClosureCache *cache = NULL; if (!PyArg_ParseTuple (args, "O!O!O:hook_up_vfunc_implementation", &PyGIBaseInfo_Type, &py_info, @@ -408,10 +1855,15 @@ _wrap_pyg_hook_up_vfunc_implementation (PyObject *self, PyObject *args) offset = g_field_info_get_offset (field_info); method_ptr = G_STRUCT_MEMBER_P (implementor_vtable, offset); - closure = _pygi_make_native_closure ( (GICallableInfo*) callback_info, + cache = pygi_closure_cache_new (callback_info); + closure = _pygi_make_native_closure ( (GICallableInfo*) callback_info, cache, GI_SCOPE_TYPE_NOTIFIED, py_function, NULL); +#if GI_CHECK_VERSION (1, 72, 0) + *method_ptr = g_callable_info_get_closure_native_address (callback_info, closure->closure); +#else *method_ptr = closure->closure; +#endif g_base_info_unref (interface_info); g_base_info_unref (type_info); @@ -465,43 +1917,6 @@ _wrap_pyg_has_vfunc_implementation (PyObject *self, PyObject *args) #endif static PyObject * -_wrap_pyg_variant_new_tuple (PyObject *self, PyObject *args) -{ - PyObject *py_values; - GVariant **values = NULL; - GVariant *variant = NULL; - PyObject *py_variant = NULL; - PyObject *py_type; - gssize i; - - if (!PyArg_ParseTuple (args, "O!:variant_new_tuple", - &PyTuple_Type, &py_values)) { - return NULL; - } - - py_type = _pygi_type_import_by_name ("GLib", "Variant"); - - values = g_newa (GVariant*, PyTuple_Size (py_values)); - - for (i = 0; i < PyTuple_Size (py_values); i++) { - PyObject *value = PyTuple_GET_ITEM (py_values, i); - - if (!PyObject_IsInstance (value, py_type)) { - PyErr_Format (PyExc_TypeError, "argument %" G_GSSIZE_FORMAT " is not a GLib.Variant", i); - return NULL; - } - - values[i] = (GVariant *) ( (PyGPointer *) value)->pointer; - } - - variant = g_variant_new_tuple (values, PyTuple_Size (py_values)); - - py_variant = _pygi_struct_new ( (PyTypeObject *) py_type, variant, FALSE); - - return py_variant; -} - -static PyObject * _wrap_pyg_variant_type_from_string (PyObject *self, PyObject *args) { char *type_string; @@ -513,19 +1928,13 @@ _wrap_pyg_variant_type_from_string (PyObject *self, PyObject *args) return NULL; } - py_type = _pygi_type_import_by_name ("GLib", "VariantType"); + py_type = pygi_type_import_by_name ("GLib", "VariantType"); - py_variant = _pygi_boxed_new ( (PyTypeObject *) py_type, type_string, FALSE, 0); + py_variant = pygi_boxed_new ( (PyTypeObject *) py_type, type_string, FALSE, 0); return py_variant; } -static PyObject * -_wrap_pyg_source_new (PyObject *self, PyObject *args) -{ - return pyg_source_new (); -} - #define CHUNK_SIZE 8192 static PyObject* @@ -545,50 +1954,50 @@ pyg_channel_read(PyObject* self, PyObject *args, PyObject *kwargs) PyErr_SetString(PyExc_TypeError, "first argument is not a GLib.IOChannel"); return NULL; } - + if (max_count == 0) - return PYGLIB_PyBytes_FromString(""); + return PyBytes_FromString (""); iochannel = pyg_boxed_get (py_iochannel, GIOChannel); while (status == G_IO_STATUS_NORMAL - && (max_count == -1 || total_read < max_count)) { + && (max_count == -1 || total_read < (gsize)max_count)) { gsize single_read; char* buf; gsize buf_size; - - if (max_count == -1) + + if (max_count == -1) buf_size = CHUNK_SIZE; else { buf_size = max_count - total_read; if (buf_size > CHUNK_SIZE) buf_size = CHUNK_SIZE; } - + if ( ret_obj == NULL ) { - ret_obj = PYGLIB_PyBytes_FromStringAndSize((char *)NULL, buf_size); + ret_obj = PyBytes_FromStringAndSize ((char *)NULL, buf_size); if (ret_obj == NULL) goto failure; } - else if (buf_size + total_read > PYGLIB_PyBytes_Size(ret_obj)) { - if (PYGLIB_PyBytes_Resize(&ret_obj, buf_size + total_read) == -1) + else if (buf_size + total_read > (gsize)PyBytes_Size (ret_obj)) { + if (_PyBytes_Resize (&ret_obj, buf_size + total_read) == -1) goto failure; } - - buf = PYGLIB_PyBytes_AsString(ret_obj) + total_read; + + buf = PyBytes_AsString (ret_obj) + total_read; Py_BEGIN_ALLOW_THREADS; status = g_io_channel_read_chars (iochannel, buf, buf_size, &single_read, &error); Py_END_ALLOW_THREADS; - if (pyglib_error_check(&error)) + if (pygi_error_check (&error)) goto failure; - + total_read += single_read; } - - if ( total_read != PYGLIB_PyBytes_Size(ret_obj) ) { - if (PYGLIB_PyBytes_Resize(&ret_obj, total_read) == -1) + + if ( total_read != (gsize)PyBytes_Size (ret_obj) ) { + if (_PyBytes_Resize (&ret_obj, total_read) == -1) goto failure; } @@ -599,8 +2008,314 @@ pyg_channel_read(PyObject* self, PyObject *args, PyObject *kwargs) return NULL; } +static gboolean +marshal_emission_hook(GSignalInvocationHint *ihint, + guint n_param_values, + const GValue *param_values, + gpointer user_data) +{ + PyGILState_STATE state; + gboolean retval = FALSE; + PyObject *func, *args; + PyObject *retobj; + PyObject *params; + guint i; + + state = PyGILState_Ensure(); + + /* construct Python tuple for the parameter values */ + params = PyTuple_New(n_param_values); + + for (i = 0; i < n_param_values; i++) { + PyObject *item = pyg_value_as_pyobject(¶m_values[i], FALSE); + + /* error condition */ + if (!item) { + goto out; + } + PyTuple_SetItem(params, i, item); + } + + args = (PyObject *)user_data; + func = PyTuple_GetItem(args, 0); + args = PySequence_Concat(params, PyTuple_GetItem(args, 1)); + Py_DECREF(params); + + /* params passed to function may have extra arguments */ + + retobj = PyObject_CallObject(func, args); + Py_DECREF(args); + if (retobj == NULL) { + PyErr_Print(); + } + + retval = (retobj == Py_True ? TRUE : FALSE); + Py_XDECREF(retobj); +out: + PyGILState_Release(state); + return retval; +} + +/** + * pyg_destroy_notify: + * @user_data: a PyObject pointer. + * + * A function that can be used as a GDestroyNotify callback that will + * call Py_DECREF on the data. + */ +static void +pyg_destroy_notify(gpointer user_data) +{ + PyObject *obj = (PyObject *)user_data; + PyGILState_STATE state; + + state = PyGILState_Ensure(); + Py_DECREF(obj); + PyGILState_Release(state); +} + +static PyObject * +pyg_add_emission_hook(PyGObject *self, PyObject *args) +{ + PyObject *first, *callback, *extra_args, *data, *repr; + gchar *name; + gulong hook_id; + guint sigid; + Py_ssize_t len; + GQuark detail = 0; + GType gtype; + PyObject *pygtype; + + len = PyTuple_Size(args); + if (len < 3) { + PyErr_SetString(PyExc_TypeError, + "gobject.add_emission_hook requires at least 3 arguments"); + return NULL; + } + first = PySequence_GetSlice(args, 0, 3); + if (!PyArg_ParseTuple(first, "OsO:add_emission_hook", + &pygtype, &name, &callback)) { + Py_DECREF(first); + return NULL; + } + Py_DECREF(first); + + if ((gtype = pyg_type_from_object(pygtype)) == 0) { + return NULL; + } + if (!PyCallable_Check(callback)) { + PyErr_SetString(PyExc_TypeError, "third argument must be callable"); + return NULL; + } + + if (!g_signal_parse_name(name, gtype, &sigid, &detail, TRUE)) { + repr = PyObject_Repr((PyObject*)self); + PyErr_Format(PyExc_TypeError, "%s: unknown signal name: %s", + PyUnicode_AsUTF8 (repr), + name); + Py_DECREF(repr); + return NULL; + } + extra_args = PySequence_GetSlice(args, 3, len); + if (extra_args == NULL) + return NULL; + + data = Py_BuildValue("(ON)", callback, extra_args); + if (data == NULL) + return NULL; + + hook_id = g_signal_add_emission_hook(sigid, detail, + marshal_emission_hook, + data, + (GDestroyNotify)pyg_destroy_notify); + + return pygi_gulong_to_py (hook_id); +} + +static PyObject * +pyg_signal_new(PyObject *self, PyObject *args) +{ + gchar *signal_name; + PyObject *py_type; + GSignalFlags signal_flags; + GType return_type; + PyObject *py_return_type, *py_param_types; + + GType instance_type = 0; + Py_ssize_t py_n_params; + guint n_params, i; + GType *param_types; + + guint signal_id; + + if (!PyArg_ParseTuple(args, "sOiOO:gobject.signal_new", &signal_name, + &py_type, &signal_flags, &py_return_type, + &py_param_types)) + return NULL; + + instance_type = pyg_type_from_object(py_type); + if (!instance_type) + return NULL; + if (!(G_TYPE_IS_INSTANTIATABLE(instance_type) || G_TYPE_IS_INTERFACE(instance_type))) { + PyErr_SetString(PyExc_TypeError, + "argument 2 must be an object type or interface type"); + return NULL; + } + + return_type = pyg_type_from_object(py_return_type); + if (!return_type) + return NULL; + + if (!PySequence_Check(py_param_types)) { + PyErr_SetString(PyExc_TypeError, + "argument 5 must be a sequence of GType codes"); + return NULL; + } + + py_n_params = PySequence_Length(py_param_types); + if (py_n_params < 0) + return FALSE; + + if (!pygi_guint_from_pyssize (py_n_params, &n_params)) + return FALSE; + + param_types = g_new(GType, n_params); + for (i = 0; i < n_params; i++) { + PyObject *item = PySequence_GetItem(py_param_types, i); + + param_types[i] = pyg_type_from_object(item); + if (param_types[i] == 0) { + PyErr_Clear(); + Py_DECREF(item); + PyErr_SetString(PyExc_TypeError, + "argument 5 must be a sequence of GType codes"); + g_free(param_types); + return NULL; + } + Py_DECREF(item); + } + + signal_id = g_signal_newv(signal_name, instance_type, signal_flags, + pyg_signal_class_closure_get(), + (GSignalAccumulator)0, NULL, + (GSignalCMarshaller)0, + return_type, n_params, param_types); + g_free(param_types); + if (signal_id != 0) + return pygi_guint_to_py (signal_id); + PyErr_SetString(PyExc_RuntimeError, "could not create signal"); + return NULL; +} + +static PyObject * +pyg_object_class_list_properties (PyObject *self, PyObject *args) +{ + GParamSpec **specs; + PyObject *py_itype, *list; + GType itype; + GObjectClass *class = NULL; + gpointer iface = NULL; + guint nprops; + guint i; + + if (!PyArg_ParseTuple(args, "O:gobject.list_properties", + &py_itype)) + return NULL; + if ((itype = pyg_type_from_object(py_itype)) == 0) + return NULL; + + if (G_TYPE_IS_INTERFACE(itype)) { + iface = g_type_default_interface_ref(itype); + if (!iface) { + PyErr_SetString(PyExc_RuntimeError, + "could not get a reference to interface type"); + return NULL; + } + specs = g_object_interface_list_properties(iface, &nprops); + } else if (g_type_is_a(itype, G_TYPE_OBJECT)) { + class = g_type_class_ref(itype); + if (!class) { + PyErr_SetString(PyExc_RuntimeError, + "could not get a reference to type class"); + return NULL; + } + specs = g_object_class_list_properties(class, &nprops); + } else { + PyErr_SetString(PyExc_TypeError, + "type must be derived from GObject or an interface"); + return NULL; + } + + list = PyTuple_New(nprops); + if (list == NULL) { + g_free(specs); + g_type_class_unref(class); + return NULL; + } + for (i = 0; i < nprops; i++) { + PyTuple_SetItem(list, i, pyg_param_spec_new(specs[i])); + } + g_free(specs); + if (class) + g_type_class_unref(class); + else + g_type_default_interface_unref(iface); + + return list; +} + +static PyObject * +pyg__install_metaclass(PyObject *dummy, PyTypeObject *metaclass) +{ + Py_INCREF(metaclass); + PyGObject_MetaType = metaclass; + Py_INCREF(metaclass); + + Py_SET_TYPE(&PyGObject_Type, metaclass); + + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject * +_wrap_pyig_pyos_getsig (PyObject *self, PyObject *args) +{ + int sig_num; + + if (!PyArg_ParseTuple (args, "i:pyos_getsig", &sig_num)) + return NULL; + + return PyLong_FromVoidPtr ((void *)(PyOS_getsig (sig_num))); +} + +static PyObject * +_wrap_pygobject_new_full (PyObject *self, PyObject *args) +{ + PyObject *ptr_value, *long_value; + PyObject *steal; + GObject *obj; + + if (!PyArg_ParseTuple (args, "OO", &ptr_value, &steal)) + return NULL; + + long_value = PyNumber_Long (ptr_value); + if (!long_value) { + PyErr_SetString (PyExc_TypeError, "first argument must be an integer"); + return NULL; + } + obj = PyLong_AsVoidPtr (long_value); + Py_DECREF (long_value); + + if (!G_IS_OBJECT (obj)) { + PyErr_SetString (PyExc_TypeError, "pointer is not a GObject"); + return NULL; + } + + return pygobject_new_full (obj, PyObject_IsTrue (steal), NULL); +} static PyMethodDef _gi_functions[] = { + { "pygobject_new_full", (PyCFunction) _wrap_pygobject_new_full, METH_VARARGS }, { "enum_add", (PyCFunction) _wrap_pyg_enum_add, METH_VARARGS | METH_KEYWORDS }, { "enum_register_new_gtype_and_add", (PyCFunction) _wrap_pyg_enum_register_new_gtype_and_add, METH_VARARGS | METH_KEYWORDS }, { "flags_add", (PyCFunction) _wrap_pyg_flags_add, METH_VARARGS | METH_KEYWORDS }, @@ -608,61 +2323,309 @@ static PyMethodDef _gi_functions[] = { { "register_interface_info", (PyCFunction) _wrap_pyg_register_interface_info, METH_VARARGS }, { "hook_up_vfunc_implementation", (PyCFunction) _wrap_pyg_hook_up_vfunc_implementation, METH_VARARGS }, - { "variant_new_tuple", (PyCFunction) _wrap_pyg_variant_new_tuple, METH_VARARGS }, { "variant_type_from_string", (PyCFunction) _wrap_pyg_variant_type_from_string, METH_VARARGS }, - { "source_new", (PyCFunction) _wrap_pyg_source_new, METH_NOARGS }, - { "source_set_callback", (PyCFunction) pyg_source_set_callback, METH_VARARGS }, + { "source_new", (PyCFunction) pygi_source_new, METH_NOARGS }, + { "pyos_getsig", (PyCFunction) _wrap_pyig_pyos_getsig, METH_VARARGS }, + { "source_set_callback", (PyCFunction) pygi_source_set_callback, METH_VARARGS }, { "io_channel_read", (PyCFunction) pyg_channel_read, METH_VARARGS }, + { "require_foreign", (PyCFunction) pygi_require_foreign, METH_VARARGS | METH_KEYWORDS }, + { "register_foreign", (PyCFunction) pygi_register_foreign, METH_NOARGS }, + { "spawn_async", + (PyCFunction)pyglib_spawn_async, METH_VARARGS|METH_KEYWORDS, + "spawn_async(argv, envp=None, working_directory=None,\n" + " flags=0, child_setup=None, user_data=None,\n" + " standard_input=None, standard_output=None,\n" + " standard_error=None) -> (pid, stdin, stdout, stderr)\n" + "\n" + "Execute a child program asynchronously within a glib.MainLoop()\n" + "See the reference manual for a complete reference.\n" }, + { "type_register", _wrap_pyg_type_register, METH_VARARGS }, + { "signal_new", pyg_signal_new, METH_VARARGS }, + { "list_properties", + pyg_object_class_list_properties, METH_VARARGS }, + { "new", + (PyCFunction)pyg_object_new, METH_VARARGS|METH_KEYWORDS }, + { "add_emission_hook", + (PyCFunction)pyg_add_emission_hook, METH_VARARGS }, + { "_install_metaclass", + (PyCFunction)pyg__install_metaclass, METH_O }, + { "_gvalue_get", + (PyCFunction)pyg__gvalue_get, METH_O }, + { "_gvalue_get_type", + (PyCFunction)pyg__gvalue_get_type, METH_O }, + { "_gvalue_set", + (PyCFunction)pyg__gvalue_set, METH_VARARGS }, { NULL, NULL, 0 } }; static struct PyGI_API CAPI = { - pygi_type_import_by_g_type_real, - pygi_get_property_value_real, - pygi_set_property_value_real, - pygi_signal_closure_new_real, - pygi_register_foreign_struct_real, + pygi_register_foreign_struct, }; -PYGLIB_MODULE_START(_gi, "_gi") +struct _PyGObject_Functions pygobject_api_functions = { + pygobject_register_class, + pygobject_register_wrapper, + pygobject_lookup_class, + pygobject_new, + + pyg_closure_new, + pygobject_watch_closure, + pyg_destroy_notify, + + pyg_type_from_object, + pyg_type_wrapper_new, + pyg_enum_get_value, + pyg_flags_get_value, + pyg_register_gtype_custom, + pyg_value_from_pyobject, + pyg_value_as_pyobject, + + pyg_register_interface, + + &PyGBoxed_Type, + pygi_register_gboxed, + pygi_gboxed_new, + + &PyGPointer_Type, + pyg_register_pointer, + pyg_pointer_new, + + pyg_enum_add_constants, + pyg_flags_add_constants, + + pyg_constant_strip_prefix, + + pygi_error_check, + + _pyg_set_thread_block_funcs, + (PyGThreadBlockFunc)0, /* block_threads */ + (PyGThreadBlockFunc)0, /* unblock_threads */ + + &PyGParamSpec_Type, + pyg_param_spec_new, + pyg_param_spec_from_object, + + pyg_pyobj_to_unichar_conv, + pyg_parse_constructor_args, + pyg_param_gvalue_as_pyobject, + pyg_param_gvalue_from_pyobject, + + &PyGEnum_Type, + pyg_enum_add, + pyg_enum_from_gtype, + + &PyGFlags_Type, + pyg_flags_add, + pyg_flags_from_gtype, + + TRUE, /* threads_enabled */ + + pygobject_enable_threads, + pygobject_gil_state_ensure, + pygobject_gil_state_release, + pyg_register_class_init, + pyg_register_interface_info, + + pyg_closure_set_exception_handler, + + add_warning_redirection, + disable_warning_redirections, + + NULL, /* previously type_register_custom */ + + pygi_gerror_exception_check, + + pyg_option_group_new, + pyg_type_from_object_strict, + + pygobject_new_full, + &PyGObject_Type, + + pyg_value_from_pyobject_with_error +}; + +/** + * Returns 0 on success, or -1 and sets an exception. + */ +static int +pygi_register_api(PyObject *d) { PyObject *api; - if (pygobject_init (-1, -1, -1) == NULL) { - return PYGLIB_MODULE_ERROR_RETURN; - } + api = PyCapsule_New (&pygobject_api_functions, "gobject._PyGObject_API", NULL); + if (api == NULL) + return -1; + PyDict_SetItemString(d, "_PyGObject_API", api); + Py_DECREF(api); + return 0; +} - if (_pygobject_import() < 0) { - return PYGLIB_MODULE_ERROR_RETURN; - } +/** + * Returns 0 on success, or -1 and sets an exception. + */ +static int +pygi_register_constants(PyObject *m) +{ + /* PyFloat_ return a new ref, and add object takes the ref */ + PyModule_AddObject(m, "G_MINFLOAT", pygi_gfloat_to_py (G_MINFLOAT)); + PyModule_AddObject(m, "G_MAXFLOAT", pygi_gfloat_to_py (G_MAXFLOAT)); + PyModule_AddObject(m, "G_MINDOUBLE", pygi_gdouble_to_py (G_MINDOUBLE)); + PyModule_AddObject(m, "G_MAXDOUBLE", pygi_gdouble_to_py (G_MAXDOUBLE)); + PyModule_AddIntConstant(m, "G_MINSHORT", G_MINSHORT); + PyModule_AddIntConstant(m, "G_MAXSHORT", G_MAXSHORT); + 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", pygi_guint_to_py (G_MAXUINT)); + PyModule_AddObject(m, "G_MINLONG", pygi_glong_to_py (G_MINLONG)); + PyModule_AddObject(m, "G_MAXLONG", pygi_glong_to_py (G_MAXLONG)); + PyModule_AddObject(m, "G_MAXULONG", pygi_gulong_to_py (G_MAXULONG)); + PyModule_AddObject(m, "G_MAXSIZE", pygi_gsize_to_py (G_MAXSIZE)); + PyModule_AddObject(m, "G_MAXSSIZE", pygi_gssize_to_py (G_MAXSSIZE)); + PyModule_AddObject(m, "G_MINSSIZE", pygi_gssize_to_py (G_MINSSIZE)); + PyModule_AddObject(m, "G_MINOFFSET", pygi_gint64_to_py (G_MINOFFSET)); + PyModule_AddObject(m, "G_MAXOFFSET", pygi_gint64_to_py (G_MAXOFFSET)); + + PyModule_AddIntConstant(m, "SIGNAL_RUN_FIRST", G_SIGNAL_RUN_FIRST); + PyModule_AddIntConstant(m, "PARAM_READWRITE", G_PARAM_READWRITE); + + /* The rest of the types are set in __init__.py */ + PyModule_AddObject(m, "TYPE_INVALID", pyg_type_wrapper_new(G_TYPE_INVALID)); + PyModule_AddObject(m, "TYPE_GSTRING", pyg_type_wrapper_new(G_TYPE_GSTRING)); + + return 0; +} - _pygi_repository_register_types (module); - _pygi_info_register_types (module); - _pygi_struct_register_types (module); - _pygi_boxed_register_types (module); - _pygi_ccallback_register_types (module); - _pygi_argument_init(); +/** + * Returns 0 on success, or -1 and sets an exception. + */ +static int +pygi_register_version_tuples(PyObject *d) +{ + PyObject *tuple; + + /* pygobject version */ + tuple = Py_BuildValue ("(iii)", + PYGOBJECT_MAJOR_VERSION, + PYGOBJECT_MINOR_VERSION, + PYGOBJECT_MICRO_VERSION); + PyDict_SetItemString(d, "pygobject_version", tuple); + Py_DECREF (tuple); + return 0; +} - /* Use RuntimeWarning as the base class of PyGIDeprecationWarning - * for unstable (odd minor version) and use DeprecationWarning for - * stable (even minor version). This is so PyGObject deprecations - * behave the same as regular Python deprecations in stable releases. - */ -#if PYGOBJECT_MINOR_VERSION % 2 - PyGIDeprecationWarning = PyErr_NewException("gi.PyGIDeprecationWarning", - PyExc_RuntimeWarning, NULL); +static struct PyModuleDef __gimodule = { + PyModuleDef_HEAD_INIT, + "_gi", + NULL, + -1, + _gi_functions, + NULL, + NULL, + NULL, + NULL +}; + +#ifdef __GNUC__ +#define PYGI_MODINIT_FUNC __attribute__((visibility("default"))) PyMODINIT_FUNC #else +#define PYGI_MODINIT_FUNC PyMODINIT_FUNC +#endif + +PYGI_MODINIT_FUNC PyInit__gi(void); + +PYGI_MODINIT_FUNC PyInit__gi(void) { + PyObject *module; + PyObject *api; + module = PyModule_Create(&__gimodule); + PyObject *module_dict = PyModule_GetDict (module); + +#if PY_VERSION_HEX < 0x03090000 || defined(PYPY_VERSION) + /* Deprecated since 3.9 */ + /* Except in PyPy it's still not a no-op: https://foss.heptapod.net/pypy/pypy/-/issues/3691 */ + + /* Always enable Python threads since we cannot predict which GI repositories + * might accept Python callbacks run within non-Python threads or might trigger + * toggle ref notifications. + * See: https://bugzilla.gnome.org/show_bug.cgi?id=709223 + */ + PyEval_InitThreads (); +#endif + + PyModule_AddStringConstant(module, "__package__", "gi._gi"); + + if (pygi_foreign_init () < 0) + return NULL; + if (pygi_error_register_types (module) < 0) + return NULL; + if (pygi_repository_register_types (module) < 0) + return NULL; + if (pygi_info_register_types (module) < 0) + return NULL; + if (pygi_type_register_types (module_dict) < 0) + return NULL; + if (pygi_pointer_register_types (module_dict) < 0) + return NULL; + if (pygi_struct_register_types (module) < 0) + return NULL; + if (pygi_gboxed_register_types (module_dict) < 0) + return NULL; + if (pygi_boxed_register_types (module) < 0) + return NULL; + if (pygi_ccallback_register_types (module) < 0) + return NULL; + if (pygi_resulttuple_register_types (module) < 0) + return NULL; + + if (pygi_spawn_register_types (module_dict) < 0) + return NULL; + if (pygi_option_context_register_types (module_dict) < 0) + return NULL; + if (pygi_option_group_register_types (module_dict) < 0) + return NULL; + + if (pygi_register_api (module_dict) < 0) + return NULL; + if (pygi_register_constants (module) < 0) + return NULL; + if (pygi_register_version_tuples (module_dict) < 0) + return NULL; + if (pygi_register_warnings (module_dict) < 0) + return NULL; + if (pyi_object_register_types (module_dict) < 0) + return NULL; + if (pygi_interface_register_types (module_dict) < 0) + return NULL; + if (pygi_paramspec_register_types (module_dict) < 0) + return NULL; + if (pygi_enum_register_types (module_dict) < 0) + return NULL; + if (pygi_flags_register_types (module_dict) < 0) + return NULL; + + PyGIWarning = PyErr_NewException ("gi.PyGIWarning", PyExc_Warning, NULL); + if (PyGIWarning == NULL) + return NULL; + PyGIDeprecationWarning = PyErr_NewException("gi.PyGIDeprecationWarning", PyExc_DeprecationWarning, NULL); -#endif + + /* Place holder object used to fill in "from Python" argument lists + * for values not supplied by the caller but support a GI default. + */ + _PyGIDefaultArgPlaceholder = PyList_New(0); + + Py_INCREF (PyGIWarning); + PyModule_AddObject (module, "PyGIWarning", PyGIWarning); Py_INCREF(PyGIDeprecationWarning); PyModule_AddObject(module, "PyGIDeprecationWarning", PyGIDeprecationWarning); - api = PYGLIB_CPointer_WrapPointer ( (void *) &CAPI, "gi._API"); + api = PyCapsule_New ( (void *) &CAPI, "gi._API", NULL); if (api == NULL) { - return PYGLIB_MODULE_ERROR_RETURN; + return NULL; } PyModule_AddObject (module, "_API", api); + + return module; } -PYGLIB_MODULE_END diff --git a/gi/gimodule.h b/gi/gimodule.h new file mode 100644 index 0000000..b9274bc --- /dev/null +++ b/gi/gimodule.h @@ -0,0 +1,17 @@ +#ifndef _PYGOBJECT_GIMODULE_H_ +#define _PYGOBJECT_GIMODULE_H_ + +#include "pygobject-internal.h" + +int pygobject_constructv (PyGObject *self, + guint n_properties, + const char *names[], + const GValue values[]); + +GObject * +pygobject_object_new_with_properties(GType object_type, + guint n_properties, + const char *names[], + const GValue values[]); + +#endif /*_PYGOBJECT_GIMODULE_H_*/ diff --git a/gi/importer.py b/gi/importer.py index aa95cf6..73d0c5c 100644 --- a/gi/importer.py +++ b/gi/importer.py @@ -2,6 +2,7 @@ # vim: tabstop=4 shiftwidth=4 expandtab # # Copyright (C) 2005-2009 Johan Dahlin <johan@gnome.org> +# 2015 Christoph Reiter # # importer.py: dynamic importer for introspected libraries. # @@ -20,18 +21,85 @@ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 # USA -from __future__ import absolute_import -import logging import sys +import warnings +import importlib +from contextlib import contextmanager -from ._gi import Repository -from .module import DynamicModule +import gi +from ._gi import Repository, RepositoryError +from ._gi import PyGIWarning +from .module import get_introspection_module +from .overrides import load_overrides repository = Repository.get_default() + +# only for backwards compatibility modules = {} +@contextmanager +def _check_require_version(namespace, stacklevel): + """A context manager which tries to give helpful warnings + about missing gi.require_version() which could potentially + break code if only an older version than expected is installed + or a new version gets introduced. + + :: + + with _check_require_version("Gtk", stacklevel): + load_namespace_and_overrides() + """ + + was_loaded = repository.is_registered(namespace) + + yield + + if was_loaded: + # it was loaded before by another import which depended on this + # namespace or by C code like libpeas + return + + if namespace in ("GLib", "GObject", "Gio"): + # part of glib (we have bigger problems if versions change there) + return + + if gi.get_required_version(namespace) is not None: + # the version was forced using require_version() + return + + version = repository.get_version(namespace) + warnings.warn( + "%(namespace)s was imported without specifying a version first. " + "Use gi.require_version('%(namespace)s', '%(version)s') before " + "import to ensure that the right version gets loaded." + % {"namespace": namespace, "version": version}, + PyGIWarning, stacklevel=stacklevel) + + +def get_import_stacklevel(import_hook): + """Returns the stacklevel value for warnings.warn() for when the warning + gets emitted by an imported module, but the warning should point at the + code doing the import. + + Pass import_hook=True if the warning gets generated by an import hook + (warn() gets called in load_module(), see PEP302) + """ + + py_version = sys.version_info[:2] + if py_version <= (3, 2): + # 2.7 included + return 4 if import_hook else 2 + elif py_version == (3, 3): + return 8 if import_hook else 10 + elif py_version == (3, 4): + return 10 if import_hook else 8 + else: + # fixed again in 3.5+, see https://bugs.python.org/issue24305 + return 4 if import_hook else 2 + + class DynamicImporter(object): # Note: see PEP302 for the Importer Protocol implemented below. @@ -39,32 +107,47 @@ class DynamicImporter(object): def __init__(self, path): self.path = path - def find_module(self, fullname, path=None): + def _find_module_check(self, fullname): if not fullname.startswith(self.path): - return + return False path, namespace = fullname.rsplit('.', 1) - if path != self.path: - return - - if not repository.enumerate_versions(namespace): - logging.error('Could not find any typelib for %s', namespace) - return None - else: - return self + return path == self.path - def load_module(self, fullname): - if fullname in sys.modules: - return sys.modules[fullname] + def find_spec(self, fullname, path=None, target=None): + if self._find_module_check(fullname): + return importlib.util.spec_from_loader(fullname, self) - path, namespace = fullname.rsplit('.', 1) - dynamic_module = DynamicModule(namespace) - modules[namespace] = dynamic_module - - dynamic_module.__file__ = '<%s>' % fullname - dynamic_module.__loader__ = self + def find_module(self, fullname, path=None): + if self._find_module_check(fullname): + return self - sys.modules[fullname] = dynamic_module - dynamic_module._load() + def create_module(self, spec): + path, namespace = spec.name.rsplit('.', 1) + + # is_registered() is faster than enumerate_versions() and + # in the common case of a namespace getting loaded before its + # dependencies, is_registered() returns True for all dependencies. + if not repository.is_registered(namespace) and not \ + repository.enumerate_versions(namespace): + raise ImportError('cannot import name %s, ' + 'introspection typelib not found' % namespace) + + stacklevel = get_import_stacklevel(import_hook=True) + with _check_require_version(namespace, stacklevel=stacklevel): + try: + introspection_module = get_introspection_module(namespace) + except RepositoryError as e: + raise ImportError(e) + # Import all dependencies first so their init functions + # (gdk_init, ..) in overrides get called. + # https://bugzilla.gnome.org/show_bug.cgi?id=656314 + for dep in repository.get_immediate_dependencies(namespace): + importlib.import_module('gi.repository.' + dep.split("-")[0]) + dynamic_module = load_overrides(introspection_module) return dynamic_module + + def exec_module(self, fullname): + # “exec” the module and consequently populate the module’s namespace + pass diff --git a/gi/meson.build b/gi/meson.build new file mode 100644 index 0000000..8edf832 --- /dev/null +++ b/gi/meson.build @@ -0,0 +1,91 @@ +sources = [ + 'pygboxed.c', + 'pygenum.c', + 'pygflags.c', + 'pyginterface.c', + 'pygobject-object.c', + 'pygparamspec.c', + 'pygpointer.c', + 'pygoptioncontext.c', + 'pygoptiongroup.c', + 'pygspawn.c', + 'gimodule.c', + 'pygi-repository.c', + 'pygi-info.c', + 'pygi-foreign.c', + 'pygi-struct.c', + 'pygi-source.c', + 'pygi-argument.c', + 'pygi-resulttuple.c', + 'pygi-type.c', + 'pygi-boxed.c', + 'pygi-closure.c', + 'pygi-ccallback.c', + 'pygi-util.c', + 'pygi-property.c', + 'pygi-signal-closure.c', + 'pygi-invoke.c', + 'pygi-cache.c', + 'pygi-marshal-cleanup.c', + 'pygi-basictype.c', + 'pygi-list.c', + 'pygi-array.c', + 'pygi-error.c', + 'pygi-object.c', + 'pygi-value.c', + 'pygi-enum-marshal.c', + 'pygi-struct-marshal.c', + 'pygi-hashtable.c'] + +headers = [ + 'pygobject.h' +] + +install_headers(headers, subdir : 'pygobject-@0@'.format(platform_version)) + +python_sources = [ + '_constants.py', + 'docstring.py', + '_error.py', + '_gtktemplate.py', + 'importer.py', + '__init__.py', + 'module.py', + '_option.py', + '_ossighelper.py', + '_propertyhelper.py', + 'pygtkcompat.py', + '_signalhelper.py', + 'types.py', +] + +python.install_sources(python_sources, + pure : false, + subdir : 'gi' +) + +# https://github.com/mesonbuild/meson/issues/4117 +if host_machine.system() == 'windows' + python_ext_dep = python_dep +else + python_ext_dep = python_dep.partial_dependency(compile_args: true) +endif + +giext = python.extension_module('_gi', sources, + dependencies : [python_ext_dep, glib_dep, gi_dep, ffi_dep], + include_directories: include_directories('..'), + install: true, + subdir : 'gi', + c_args: pyext_c_args + main_c_args +) + +if cairo_dep.found() + gicairoext = python.extension_module('_gi_cairo', ['pygi-foreign-cairo.c'], + dependencies : [python_ext_dep, glib_dep, gi_dep, ffi_dep, pycairo_dep, cairo_dep, cairo_gobject_dep], + install: true, + subdir : 'gi', + c_args: pyext_c_args + main_c_args) +endif + +subdir('overrides') +subdir('repository') diff --git a/gi/module.py b/gi/module.py index 71f8ac5..93b8e6a 100644 --- a/gi/module.py +++ b/gi/module.py @@ -20,22 +20,10 @@ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 # USA -from __future__ import absolute_import - -import sys -import types import importlib - -_have_py3 = (sys.version_info[0] >= 3) - -try: - maketrans = ''.maketrans -except AttributeError: - # fallback for Python 2 - from string import maketrans +from threading import Lock import gi -from .overrides import registry from ._gi import \ Repository, \ @@ -54,16 +42,13 @@ from ._gi import \ enum_add, \ enum_register_new_gtype_and_add, \ flags_add, \ - flags_register_new_gtype_and_add + flags_register_new_gtype_and_add, \ + GInterface from .types import \ GObjectMeta, \ StructMeta -from ._gobject._gobject import \ - GInterface, \ - GObject - -from ._gobject.constants import \ +from ._constants import \ TYPE_NONE, \ TYPE_BOXED, \ TYPE_POINTER, \ @@ -81,10 +66,16 @@ def get_parent_for_object(object_info): parent_object_info = object_info.get_parent() if not parent_object_info: - # Special case GObject.Object as being derived from the static GObject. - if object_info.get_namespace() == 'GObject' and object_info.get_name() == 'Object': - return GObject - + # If we reach the end of the introspection info class hierarchy, look + # for an existing wrapper on the GType and use it as a base for the + # new introspection wrapper. This allows static C wrappers already + # registered with the GType to be used as the introspection base + # (_gi.GObject for example) + gtype = object_info.get_g_type() + if gtype and gtype.pytype: + return gtype.pytype + + # Otherwise use builtins.object as the base return object namespace = parent_object_info.get_namespace() @@ -114,19 +105,21 @@ class IntrospectionModule(object): These members are then cached on this introspection module. """ def __init__(self, namespace, version=None): + """Might raise gi._gi.RepositoryError""" + repository.require(namespace, version) self._namespace = namespace self._version = version self.__name__ = 'gi.repository.' + namespace - self.__path__ = repository.get_typelib_path(self._namespace) - if _have_py3: - # get_typelib_path() delivers bytes, not a string - self.__path__ = self.__path__.decode('UTF-8') + path = repository.get_typelib_path(self._namespace) + self.__path__ = [path] if self._version is None: self._version = repository.get_version(self._namespace) + self._lock = Lock() + def __getattr__(self, name): info = repository.find_by_name(self._namespace, name) if not info: @@ -135,37 +128,41 @@ class IntrospectionModule(object): if isinstance(info, EnumInfo): g_type = info.get_g_type() - wrapper = g_type.pytype - if wrapper is None: - if info.is_flags(): - if g_type.is_a(TYPE_FLAGS): - wrapper = flags_add(g_type) - else: - assert g_type == TYPE_NONE - wrapper = flags_register_new_gtype_and_add(info) - else: - if g_type.is_a(TYPE_ENUM): - wrapper = enum_add(g_type) - else: - assert g_type == TYPE_NONE - wrapper = enum_register_new_gtype_and_add(info) - - wrapper.__info__ = info - wrapper.__module__ = 'gi.repository.' + info.get_namespace() - - # Don't use upper() here to avoid locale specific - # identifier conversion (e. g. in Turkish 'i'.upper() == 'i') - # see https://bugzilla.gnome.org/show_bug.cgi?id=649165 - ascii_upper_trans = maketrans( - 'abcdefgjhijklmnopqrstuvwxyz', - 'ABCDEFGJHIJKLMNOPQRSTUVWXYZ') - for value_info in info.get_values(): - value_name = value_info.get_name_unescaped().translate(ascii_upper_trans) - setattr(wrapper, value_name, wrapper(value_info.get_value())) + with self._lock: + wrapper = g_type.pytype - if g_type != TYPE_NONE: - g_type.pytype = wrapper + if wrapper is None: + if info.is_flags(): + if g_type.is_a(TYPE_FLAGS): + wrapper = flags_add(g_type) + else: + assert g_type == TYPE_NONE + wrapper = flags_register_new_gtype_and_add(info) + else: + if g_type.is_a(TYPE_ENUM): + wrapper = enum_add(g_type) + else: + assert g_type == TYPE_NONE + wrapper = enum_register_new_gtype_and_add(info) + + wrapper.__info__ = info + wrapper.__module__ = 'gi.repository.' + info.get_namespace() + + # Don't use upper() here to avoid locale specific + # identifier conversion (e. g. in Turkish 'i'.upper() == 'i') + # see https://bugzilla.gnome.org/show_bug.cgi?id=649165 + ascii_upper_trans = ''.maketrans( + 'abcdefgjhijklmnopqrstuvwxyz', + 'ABCDEFGJHIJKLMNOPQRSTUVWXYZ') + for value_info in info.get_values(): + value_name = value_info.get_name_unescaped().translate(ascii_upper_trans) + setattr(wrapper, value_name, wrapper(value_info.get_value())) + for method_info in info.get_methods(): + setattr(wrapper, method_info.__name__, method_info) + + if g_type != TYPE_NONE: + g_type.pytype = wrapper elif isinstance(info, RegisteredTypeInfo): g_type = info.get_g_type() @@ -196,27 +193,28 @@ class IntrospectionModule(object): else: raise NotImplementedError(info) - # Check if there is already a Python wrapper that is not a parent class - # of the wrapper being created. If it is a parent, it is ok to clobber - # g_type.pytype with a new child class wrapper of the existing parent. - # Note that the return here never occurs under normal circumstances due - # to caching on the __dict__ itself. - if g_type != TYPE_NONE: - type_ = g_type.pytype - if type_ is not None and type_ not in bases: - self.__dict__[name] = type_ - return type_ - - dict_ = { - '__info__': info, - '__module__': 'gi.repository.' + self._namespace, - '__gtype__': g_type - } - wrapper = metaclass(name, bases, dict_) - - # Register the new Python wrapper. - if g_type != TYPE_NONE: - g_type.pytype = wrapper + with self._lock: + # Check if there is already a Python wrapper that is not a parent class + # of the wrapper being created. If it is a parent, it is ok to clobber + # g_type.pytype with a new child class wrapper of the existing parent. + # Note that the return here never occurs under normal circumstances due + # to caching on the __dict__ itself. + if g_type != TYPE_NONE: + type_ = g_type.pytype + if type_ is not None and type_ not in bases: + self.__dict__[name] = type_ + return type_ + + dict_ = { + '__info__': info, + '__module__': 'gi.repository.' + self._namespace, + '__gtype__': g_type + } + wrapper = metaclass(name, bases, dict_) + + # Register the new Python wrapper. + if g_type != TYPE_NONE: + g_type.pytype = wrapper elif isinstance(info, FunctionInfo): wrapper = info @@ -233,9 +231,6 @@ class IntrospectionModule(object): def __repr__(self): path = repository.get_typelib_path(self._namespace) - if _have_py3: - # get_typelib_path() delivers bytes, not a string - path = path.decode('UTF-8') return "<IntrospectionModule %r from %r>" % (self._namespace, path) def __dir__(self): @@ -258,6 +253,8 @@ def get_introspection_module(namespace): """ :Returns: An object directly wrapping the gi module without overrides. + + Might raise gi._gi.RepositoryError """ if namespace in _introspection_modules: return _introspection_modules[namespace] @@ -266,69 +263,3 @@ def get_introspection_module(namespace): module = IntrospectionModule(namespace, version) _introspection_modules[namespace] = module return module - - -class DynamicModule(types.ModuleType): - """A module composed of an IntrospectionModule and an overrides module. - - DynamicModule wraps up an IntrospectionModule and an overrides module - into a single accessible module. This is what is returned from statements - like "from gi.repository import Foo". Accessing attributes on a DynamicModule - will first look overrides (or the gi.overrides.registry cache) and then - in the introspection module if it was not found as an override. - """ - def __init__(self, namespace): - self._namespace = namespace - self._introspection_module = None - self._overrides_module = None - self.__path__ = None - - def _load(self): - self._introspection_module = get_introspection_module(self._namespace) - try: - self._overrides_module = importlib.import_module('gi.overrides.' + self._namespace) - except ImportError: - self._overrides_module = None - - self.__path__ = repository.get_typelib_path(self._namespace) - if _have_py3: - # get_typelib_path() delivers bytes, not a string - self.__path__ = self.__path__.decode('UTF-8') - - def __getattr__(self, name): - if self._overrides_module is not None: - override_exports = getattr(self._overrides_module, '__all__', ()) - if name in override_exports: - return getattr(self._overrides_module, name, None) - else: - # check the registry just in case the module hasn't loaded yet - # TODO: Only gtypes are registered in the registry right now - # but it would be nice to register all overrides and - # get rid of the module imports. We might actually see a - # speedup. - key = '%s.%s' % (self._namespace, name) - if key in registry: - return registry[key] - - return getattr(self._introspection_module, name) - - def __dir__(self): - # Python's default dir() is just dir(self.__class__) + self.__dict__.keys() - result = set(dir(self.__class__)) - result.update(self.__dict__.keys()) - - result.update(dir(self._introspection_module)) - override_exports = getattr(self._overrides_module, '__all__', ()) - result.update(override_exports) - return list(result) - - def __repr__(self): - path = repository.get_typelib_path(self._namespace) - if _have_py3: - # get_typelib_path() delivers bytes, not a string - path = path.decode('UTF-8') - - return "<%s.%s %r from %r>" % (self.__class__.__module__, - self.__class__.__name__, - self._namespace, - path) diff --git a/gi/overrides/GIMarshallingTests.py b/gi/overrides/GIMarshallingTests.py index cc967b4..e9f8e33 100644 --- a/gi/overrides/GIMarshallingTests.py +++ b/gi/overrides/GIMarshallingTests.py @@ -41,6 +41,7 @@ class OverridesStruct(GIMarshallingTests.OverridesStruct): def method(self): return GIMarshallingTests.OverridesStruct.method(self) / 7 + OverridesStruct = override(OverridesStruct) __all__.append('OverridesStruct') @@ -53,18 +54,19 @@ class OverridesObject(GIMarshallingTests.OverridesObject): def __init__(self, long_): GIMarshallingTests.OverridesObject.__init__(self) # FIXME: doesn't work yet - #self.long_ = long_ + # self.long_ = long_ @classmethod def new(cls, long_): self = GIMarshallingTests.OverridesObject.new() # FIXME: doesn't work yet - #self.long_ = long_ + # self.long_ = long_ return self def method(self): """Overridden doc string.""" return GIMarshallingTests.OverridesObject.method(self) / 7 + OverridesObject = override(OverridesObject) __all__.append('OverridesObject') diff --git a/gi/overrides/GLib.py b/gi/overrides/GLib.py index f4b1ef5..78d309b 100644 --- a/gi/overrides/GLib.py +++ b/gi/overrides/GLib.py @@ -19,41 +19,67 @@ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 # USA -import signal import warnings import sys +import socket +from .._ossighelper import wakeup_on_signal, register_sigint_fallback from ..module import get_introspection_module -from .._gi import (variant_new_tuple, variant_type_from_string, source_new, +from .._gi import (variant_type_from_string, source_new, source_set_callback, io_channel_read) -from ..overrides import override, deprecated +from ..overrides import override, deprecated, deprecated_attr from gi import PyGIDeprecationWarning, version_info GLib = get_introspection_module('GLib') __all__ = [] -from gi._glib import option +from gi import _option as option option # pyflakes __all__.append('option') # Types and functions still needed from static bindings -from gi._glib import _glib -GError = _glib.GError -OptionContext = _glib.OptionContext -OptionGroup = _glib.OptionGroup -Pid = _glib.Pid -spawn_async = _glib.spawn_async +from gi import _gi +from gi._error import GError + +Error = GError +OptionContext = _gi.OptionContext +OptionGroup = _gi.OptionGroup +Pid = _gi.Pid +spawn_async = _gi.spawn_async def threads_init(): - warnings.warn('threads_init no longer needs to be called. ' - 'See: https://bugzilla.gnome.org/show_bug.cgi?id=686914', - PyGIDeprecationWarning) + warnings.warn('Since version 3.11, calling threads_init is no longer needed. ' + 'See: https://wiki.gnome.org/PyGObject/Threading', + PyGIDeprecationWarning, stacklevel=2) + + +def gerror_matches(self, domain, code): + # Handle cases where self.domain was set to an integer for compatibility + # with the introspected GLib.Error. + if isinstance(self.domain, str): + self_domain_quark = GLib.quark_from_string(self.domain) + else: + self_domain_quark = self.domain + return (self_domain_quark, self.code) == (domain, code) + +def gerror_new_literal(domain, message, code): + domain_quark = GLib.quark_to_string(domain) + return GError(message, domain_quark, code) -__all__ += ['GError', 'OptionContext', 'OptionGroup', 'Pid', + +# Monkey patch methods that rely on GLib introspection to be loaded at runtime. +Error.__name__ = 'Error' +Error.__module__ = 'gi.repository.GLib' +Error.__gtype__ = GLib.Error.__gtype__ +Error.matches = gerror_matches +Error.new_literal = staticmethod(gerror_new_literal) + + +__all__ += ['GError', 'Error', 'OptionContext', 'OptionGroup', 'Pid', 'spawn_async', 'threads_init'] @@ -76,132 +102,77 @@ class _VariantCreator(object): 'v': GLib.Variant.new_variant, } - def _create(self, format, args): - '''Create a GVariant object from given format and argument list. + def _create(self, format, value): + """Create a GVariant object from given format and a value that matches + the format. This method recursively calls itself for complex structures (arrays, dictionaries, boxed). - Return a tuple (variant, rest_format, rest_args) with the generated - GVariant, the remainder of the format string, and the remainder of the - arguments. - - If args is None, then this won't actually consume any arguments, and - just parse the format string and generate empty GVariant structures. - This is required for creating empty dictionaries or arrays. - ''' - # leaves (simple types) - constructor = self._LEAF_CONSTRUCTORS.get(format[0]) - if constructor: - if args is not None: - if not args: - raise TypeError('not enough arguments for GVariant format string') - v = constructor(args[0]) - return (v, format[1:], args[1:]) - else: - return (None, format[1:], None) - - if format[0] == '(': - return self._create_tuple(format, args) - - if format.startswith('a{'): - return self._create_dict(format, args) - - if format[0] == 'a': - return self._create_array(format, args) - - raise NotImplementedError('cannot handle GVariant type ' + format) - - def _create_tuple(self, format, args): - '''Handle the case where the outermost type of format is a tuple.''' - - format = format[1:] # eat the '(' - if args is None: - # empty value: we need to call _create() to parse the subtype - rest_format = format - while rest_format: - if rest_format.startswith(')'): - break - rest_format = self._create(rest_format, None)[1] - else: - raise TypeError('tuple type string not closed with )') - - rest_format = rest_format[1:] # eat the ) - return (None, rest_format, None) - else: - if not args or not isinstance(args[0], tuple): - raise TypeError('expected tuple argument') - - builder = GLib.VariantBuilder.new(variant_type_from_string('r')) - for i in range(len(args[0])): - if format.startswith(')'): - raise TypeError('too many arguments for tuple signature') - - (v, format, _) = self._create(format, args[0][i:]) - builder.add_value(v) - args = args[1:] - if not format.startswith(')'): - raise TypeError('tuple type string not closed with )') - - rest_format = format[1:] # eat the ) - return (builder.end(), rest_format, args) - - def _create_dict(self, format, args): - '''Handle the case where the outermost type of format is a dict.''' - - builder = None - if args is None or not args[0]: - # empty value: we need to call _create() to parse the subtype, - # and specify the element type precisely - rest_format = self._create(format[2:], None)[1] - rest_format = self._create(rest_format, None)[1] - if not rest_format.startswith('}'): - raise TypeError('dictionary type string not closed with }') - rest_format = rest_format[1:] # eat the } - element_type = format[:len(format) - len(rest_format)] - builder = GLib.VariantBuilder.new(variant_type_from_string(element_type)) - else: - builder = GLib.VariantBuilder.new(variant_type_from_string('a{?*}')) - for k, v in args[0].items(): - (key_v, rest_format, _) = self._create(format[2:], [k]) - (val_v, rest_format, _) = self._create(rest_format, [v]) - - if not rest_format.startswith('}'): - raise TypeError('dictionary type string not closed with }') - rest_format = rest_format[1:] # eat the } - - entry = GLib.VariantBuilder.new(variant_type_from_string('{?*}')) - entry.add_value(key_v) - entry.add_value(val_v) - builder.add_value(entry.end()) - - if args is not None: - args = args[1:] - return (builder.end(), rest_format, args) - - def _create_array(self, format, args): - '''Handle the case where the outermost type of format is an array.''' - - builder = None - if args is None or not args[0]: - # empty value: we need to call _create() to parse the subtype, - # and specify the element type precisely - rest_format = self._create(format[1:], None)[1] - element_type = format[:len(format) - len(rest_format)] - builder = GLib.VariantBuilder.new(variant_type_from_string(element_type)) + Returns the generated GVariant. + + If value is None it will generate an empty GVariant container type. + """ + gvtype = GLib.VariantType(format) + if format in self._LEAF_CONSTRUCTORS: + return self._LEAF_CONSTRUCTORS[format](value) + + # Since we discarded all leaf types, this must be a container + builder = GLib.VariantBuilder.new(gvtype) + if value is None: + return builder.end() + + if gvtype.is_maybe(): + builder.add_value(self._create(gvtype.element().dup_string(), value)) + return builder.end() + + try: + iter(value) + except TypeError: + raise TypeError("Could not create array, tuple or dictionary entry from non iterable value %s %s" % + (format, value)) + + if gvtype.is_tuple() and gvtype.n_items() != len(value): + raise TypeError("Tuple mismatches value's number of elements %s %s" % (format, value)) + if gvtype.is_dict_entry() and len(value) != 2: + raise TypeError("Dictionary entries must have two elements %s %s" % (format, value)) + + if gvtype.is_array(): + element_type = gvtype.element().dup_string() + if isinstance(value, dict): + value = value.items() + for i in value: + builder.add_value(self._create(element_type, i)) else: - builder = GLib.VariantBuilder.new(variant_type_from_string('a*')) - for i in range(len(args[0])): - (v, rest_format, _) = self._create(format[1:], args[0][i:]) - builder.add_value(v) - if args is not None: - args = args[1:] - return (builder.end(), rest_format, args) + remainer_format = format[1:] + for i in value: + dup = variant_type_from_string(remainer_format).dup_string() + builder.add_value(self._create(dup, i)) + remainer_format = remainer_format[len(dup):] + + return builder.end() + + +LEAF_ACCESSORS = { + 'b': 'get_boolean', + 'y': 'get_byte', + 'n': 'get_int16', + 'q': 'get_uint16', + 'i': 'get_int32', + 'u': 'get_uint32', + 'x': 'get_int64', + 't': 'get_uint64', + 'h': 'get_handle', + 'd': 'get_double', + 's': 'get_string', + 'o': 'get_string', # object path + 'g': 'get_string', # signature +} class Variant(GLib.Variant): def __new__(cls, format_string, value): - '''Create a GVariant from a native Python object. + """Create a GVariant from a native Python object. format_string is a standard GVariant type signature, value is a Python object whose structure has to match the signature. @@ -211,16 +182,29 @@ class Variant(GLib.Variant): GLib.Variant('(is)', (1, 'hello')) GLib.Variant('(asa{sv})', ([], {'foo': GLib.Variant('b', True), 'bar': GLib.Variant('i', 2)})) - ''' + """ + if not GLib.VariantType.string_is_valid(format_string): + raise TypeError("Invalid GVariant format string '%s'", format_string) creator = _VariantCreator() - (v, rest_format, _) = creator._create(format_string, [value]) - if rest_format: - raise TypeError('invalid remaining format string: "%s"' % rest_format) + v = creator._create(format_string, value) v.format_string = format_string return v + @staticmethod + def new_tuple(*elements): + return GLib.Variant.new_tuple(elements) + def __del__(self): - self.unref() + try: + self.unref() + except ImportError: + # Calling unref will cause gi and gi.repository.GLib to be + # imported. However, if the program is exiting, then these + # modules have likely been removed from sys.modules and will + # raise an exception. Assume that's the case for ImportError + # and ignore the exception since everything will be cleaned + # up, anyways. + pass def __str__(self): return self.print_(True) @@ -251,37 +235,22 @@ class Variant(GLib.Variant): return hash((self.get_type_string(), self.unpack())) def unpack(self): - '''Decompose a GVariant into a native Python object.''' - - LEAF_ACCESSORS = { - 'b': self.get_boolean, - 'y': self.get_byte, - 'n': self.get_int16, - 'q': self.get_uint16, - 'i': self.get_int32, - 'u': self.get_uint32, - 'x': self.get_int64, - 't': self.get_uint64, - 'h': self.get_handle, - 'd': self.get_double, - 's': self.get_string, - 'o': self.get_string, # object path - 'g': self.get_string, # signature - } + """Decompose a GVariant into a native Python object.""" + + type_string = self.get_type_string() # simple values - la = LEAF_ACCESSORS.get(self.get_type_string()) + la = LEAF_ACCESSORS.get(type_string) if la: - return la() + return getattr(self, la)() # tuple - if self.get_type_string().startswith('('): - res = [self.get_child_value(i).unpack() - for i in range(self.n_children())] - return tuple(res) + if type_string.startswith('('): + return tuple(self.get_child_value(i).unpack() + for i in range(self.n_children())) # dictionary - if self.get_type_string().startswith('a{'): + if type_string.startswith('a{'): res = {} for i in range(self.n_children()): v = self.get_child_value(i) @@ -289,31 +258,32 @@ class Variant(GLib.Variant): return res # array - if self.get_type_string().startswith('a'): + if type_string.startswith('a'): return [self.get_child_value(i).unpack() for i in range(self.n_children())] # variant (just unbox transparently) - if self.get_type_string().startswith('v'): + if type_string.startswith('v'): return self.get_variant().unpack() # maybe - if self.get_type_string().startswith('m'): - m = self.get_maybe() - return m.unpack() if m else None + if type_string.startswith('m'): + if not self.n_children(): + return None + return self.get_child_value(0).unpack() - raise NotImplementedError('unsupported GVariant type ' + self.get_type_string()) + raise NotImplementedError('unsupported GVariant type ' + type_string) @classmethod def split_signature(klass, signature): - '''Return a list of the element signatures of the topmost signature tuple. + """Return a list of the element signatures of the topmost signature tuple. If the signature is not a tuple, it returns one element with the entire signature. If the signature is an empty tuple, the result is []. This is useful for e. g. iterating over method parameters which are passed as a single Variant. - ''' + """ if signature == '()': return [] @@ -416,15 +386,12 @@ class Variant(GLib.Variant): # Array, dict, tuple if self.get_type_string().startswith('a') or self.get_type_string().startswith('('): return self.n_children() != 0 - if self.get_type_string() in ['v']: - # unpack works recursively, hence bool also works recursively - return bool(self.unpack()) - # Everything else is True - return True + # unpack works recursively, hence bool also works recursively + return bool(self.unpack()) def keys(self): if not self.get_type_string().startswith('a{'): - return TypeError, 'GVariant type %s is not a dictionary' % self.get_type_string() + raise TypeError('GVariant type %s is not a dictionary' % self.get_type_string()) res = [] for i in range(self.n_children()): @@ -433,16 +400,11 @@ class Variant(GLib.Variant): return res -@classmethod -def new_tuple(cls, *elements): - return variant_new_tuple(elements) - - def get_string(self): value, length = GLib.Variant.get_string(self) return value -setattr(Variant, 'new_tuple', new_tuple) + setattr(Variant, 'get_string', get_string) __all__.append('Variant') @@ -453,14 +415,18 @@ def markup_escape_text(text, length=-1): return GLib.markup_escape_text(text.decode('UTF-8'), length) else: return GLib.markup_escape_text(text, length) + + __all__.append('markup_escape_text') # backwards compatible names from old static bindings for n in ['DESKTOP', 'DOCUMENTS', 'DOWNLOAD', 'MUSIC', 'PICTURES', 'PUBLIC_SHARE', 'TEMPLATES', 'VIDEOS']: - globals()['USER_DIRECTORY_' + n] = getattr(GLib.UserDirectory, 'DIRECTORY_' + n) - __all__.append('USER_DIRECTORY_' + n) + attr = 'USER_DIRECTORY_' + n + deprecated_attr("GLib", attr, "GLib.UserDirectory.DIRECTORY_" + n) + globals()[attr] = getattr(GLib.UserDirectory, 'DIRECTORY_' + n) + __all__.append(attr) for n in ['ERR', 'HUP', 'IN', 'NVAL', 'OUT', 'PRI']: globals()['IO_' + n] = getattr(GLib.IOCondition, n) @@ -468,30 +434,53 @@ for n in ['ERR', 'HUP', 'IN', 'NVAL', 'OUT', 'PRI']: for n in ['APPEND', 'GET_MASK', 'IS_READABLE', 'IS_SEEKABLE', 'MASK', 'NONBLOCK', 'SET_MASK']: - globals()['IO_FLAG_' + n] = getattr(GLib.IOFlags, n) - __all__.append('IO_FLAG_' + n) + attr = 'IO_FLAG_' + n + deprecated_attr("GLib", attr, "GLib.IOFlags." + n) + globals()[attr] = getattr(GLib.IOFlags, n) + __all__.append(attr) + # spelling for the win IO_FLAG_IS_WRITEABLE = GLib.IOFlags.IS_WRITABLE +deprecated_attr("GLib", "IO_FLAG_IS_WRITEABLE", "GLib.IOFlags.IS_WRITABLE") __all__.append('IO_FLAG_IS_WRITEABLE') for n in ['AGAIN', 'EOF', 'ERROR', 'NORMAL']: - globals()['IO_STATUS_' + n] = getattr(GLib.IOStatus, n) - __all__.append('IO_STATUS_' + n) + attr = 'IO_STATUS_' + n + globals()[attr] = getattr(GLib.IOStatus, n) + deprecated_attr("GLib", attr, "GLib.IOStatus." + n) + __all__.append(attr) for n in ['CHILD_INHERITS_STDIN', 'DO_NOT_REAP_CHILD', 'FILE_AND_ARGV_ZERO', 'LEAVE_DESCRIPTORS_OPEN', 'SEARCH_PATH', 'STDERR_TO_DEV_NULL', 'STDOUT_TO_DEV_NULL']: - globals()['SPAWN_' + n] = getattr(GLib.SpawnFlags, n) - __all__.append('SPAWN_' + n) + attr = 'SPAWN_' + n + globals()[attr] = getattr(GLib.SpawnFlags, n) + deprecated_attr("GLib", attr, "GLib.SpawnFlags." + n) + __all__.append(attr) for n in ['HIDDEN', 'IN_MAIN', 'REVERSE', 'NO_ARG', 'FILENAME', 'OPTIONAL_ARG', 'NOALIAS']: - globals()['OPTION_FLAG_' + n] = getattr(GLib.OptionFlags, n) - __all__.append('OPTION_FLAG_' + n) + attr = 'OPTION_FLAG_' + n + globals()[attr] = getattr(GLib.OptionFlags, n) + deprecated_attr("GLib", attr, "GLib.OptionFlags." + n) + __all__.append(attr) for n in ['UNKNOWN_OPTION', 'BAD_VALUE', 'FAILED']: - globals()['OPTION_ERROR_' + n] = getattr(GLib.OptionError, n) - __all__.append('OPTION_ERROR_' + n) + attr = 'OPTION_ERROR_' + n + deprecated_attr("GLib", attr, "GLib.OptionError." + n) + globals()[attr] = getattr(GLib.OptionError, n) + __all__.append(attr) + + +# these are not currently exported in GLib gir, presumably because they are +# platform dependent; so get them from our static bindings +for name in ['G_MINFLOAT', 'G_MAXFLOAT', 'G_MINDOUBLE', 'G_MAXDOUBLE', + 'G_MINSHORT', 'G_MAXSHORT', 'G_MAXUSHORT', 'G_MININT', 'G_MAXINT', + 'G_MAXUINT', 'G_MINLONG', 'G_MAXLONG', 'G_MAXULONG', 'G_MAXSIZE', + 'G_MINSSIZE', 'G_MAXSSIZE', 'G_MINOFFSET', 'G_MAXOFFSET']: + attr = name.split("_", 1)[-1] + globals()[attr] = getattr(_gi, name) + __all__.append(attr) class MainLoop(GLib.MainLoop): @@ -499,28 +488,14 @@ class MainLoop(GLib.MainLoop): def __new__(cls, context=None): return GLib.MainLoop.new(context, False) - # Retain classic pygobject behaviour of quitting main loops on SIGINT def __init__(self, context=None): - def _handler(loop): - loop.quit() - loop._quit_by_sigint = True - if sys.platform != 'win32': - # compatibility shim, keep around until we depend on glib 2.36 - if hasattr(GLib, 'unix_signal_add'): - fn = GLib.unix_signal_add - else: - fn = GLib.unix_signal_add_full - self._signal_source = fn(GLib.PRIORITY_DEFAULT, signal.SIGINT, _handler, self) - - def __del__(self): - if hasattr(self, '_signal_source'): - GLib.source_remove(self._signal_source) + pass def run(self): - super(MainLoop, self).run() - if hasattr(self, '_quit_by_sigint'): - # caught by _main_loop_sigint_handler() - raise KeyboardInterrupt + with register_sigint_fallback(self.quit): + with wakeup_on_signal(): + super(MainLoop, self).run() + MainLoop = override(MainLoop) __all__.append('MainLoop') @@ -531,31 +506,34 @@ class MainContext(GLib.MainContext): def iteration(self, may_block=True): return super(MainContext, self).iteration(may_block) + MainContext = override(MainContext) __all__.append('MainContext') class Source(GLib.Source): def __new__(cls, *args, **kwargs): - # use our custom pyg_source_new() here as g_source_new() is not + # use our custom pygi_source_new() here as g_source_new() is not # bindable source = source_new() source.__class__ = cls setattr(source, '__pygi_custom_source', True) return source + def __init__(self, *args, **kwargs): + return super(Source, self).__init__() + def __del__(self): if hasattr(self, '__pygi_custom_source'): - self.unref() - - # Backwards compatible API for optional arguments - def attach(self, context=None): - id = super(Source, self).attach(context) - return id + self.destroy() + # XXX: We have to unref the underlying source while the Python + # wrapper is still valid, so the source can call into the + # wrapper methods for the finalized callback. + self._clear_boxed() def set_callback(self, fn, user_data=None): if hasattr(self, '__pygi_custom_source'): - # use our custom pyg_source_set_callback() if for a GSource object + # use our custom pygi_source_set_callback() if for a GSource object # with custom functions source_set_callback(self, fn, user_data) else: @@ -586,6 +564,7 @@ class Source(GLib.Source): can_recurse = property(__get_can_recurse, __set_can_recurse) + Source = override(Source) __all__.append('Source') @@ -601,6 +580,7 @@ class Idle(Source): if priority != GLib.PRIORITY_DEFAULT: self.set_priority(priority) + __all__.append('Idle') @@ -614,63 +594,48 @@ class Timeout(Source): if priority != GLib.PRIORITY_DEFAULT: self.set_priority(priority) -__all__.append('Timeout') - -def user_data_varargs_shim(callback, user_data, cb_num_args=0): - '''Adjust callback and user_data varargs for PyGTK backwards compatibility - - GLib only accepts exactly one user_data argument, but older pygtk - traditionally accepted zero or more for some specific functions. For "one - argument", use the actual user-supplied callback for efficiency; for all - others, rewire it to accept zero or more than one. - - Return the adjusted callback and the real user data to pass to GLib. - ''' - if len(user_data) == 1: - return (callback, user_data[0]) - - if cb_num_args == 0: - return (lambda data: callback(*data), user_data) - if cb_num_args == 2: - return (lambda a1, a2, data: callback(a1, a2, *data), user_data) - raise NotImplementedError('%i number of callback arguments not supported' % cb_num_args) +__all__.append('Timeout') # backwards compatible API def idle_add(function, *user_data, **kwargs): - (fn, data) = user_data_varargs_shim(function, user_data) priority = kwargs.get('priority', GLib.PRIORITY_DEFAULT_IDLE) - return GLib.idle_add(priority, fn, data) + return GLib.idle_add(priority, function, *user_data) + __all__.append('idle_add') def timeout_add(interval, function, *user_data, **kwargs): - (fn, data) = user_data_varargs_shim(function, user_data) priority = kwargs.get('priority', GLib.PRIORITY_DEFAULT) - return GLib.timeout_add(priority, interval, fn, data) + return GLib.timeout_add(priority, interval, function, *user_data) + __all__.append('timeout_add') def timeout_add_seconds(interval, function, *user_data, **kwargs): - (fn, data) = user_data_varargs_shim(function, user_data) priority = kwargs.get('priority', GLib.PRIORITY_DEFAULT) - return GLib.timeout_add_seconds(priority, interval, fn, data) + return GLib.timeout_add_seconds(priority, interval, function, *user_data) + __all__.append('timeout_add_seconds') -# The real GLib API is io_add_watch(IOChannel, priority, condition, callback, -# user_data). This needs to take into account several historical APIs: +# The GI GLib API uses g_io_add_watch_full renamed to g_io_add_watch with +# a signature of (channel, priority, condition, func, user_data). +# Prior to PyGObject 3.8, this function was statically bound with an API closer to the +# non-full version with a signature of: (fd, condition, func, *user_data) +# We need to support this until we are okay with breaking API in a way which is +# not backwards compatible. +# +# This needs to take into account several historical APIs: # - calling with an fd as first argument # - calling with a Python file object as first argument (we keep this one as # it's really convenient and does not change the number of arguments) # - calling without a priority as second argument -# and the usual "call without or multiple user_data", in which case the -# callback gets the same user data arguments. -def io_add_watch(channel, priority_, condition, *cb_and_user_data, **kwargs): +def _io_add_watch_get_args(channel, priority_, condition, *cb_and_user_data, **kwargs): if not isinstance(priority_, int) or isinstance(priority_, GLib.IOCondition): warnings.warn('Calling io_add_watch without priority as second argument is deprecated', PyGIDeprecationWarning) @@ -694,23 +659,33 @@ def io_add_watch(channel, priority_, condition, *cb_and_user_data, **kwargs): callback = cb_and_user_data[0] user_data = cb_and_user_data[1:] - (func, user_data) = user_data_varargs_shim(callback, user_data, 2) - # backwards compatibility: Allow calling with fd if isinstance(channel, int): - func_fdtransform = lambda _, cond, data: func(channel, cond, data) + func_fdtransform = lambda _, cond, *data: callback(channel, cond, *data) real_channel = GLib.IOChannel.unix_new(channel) + elif isinstance(channel, socket.socket) and sys.platform == 'win32': + func_fdtransform = lambda _, cond, *data: callback(channel, cond, *data) + real_channel = GLib.IOChannel.win32_new_socket(channel.fileno()) elif hasattr(channel, 'fileno'): # backwards compatibility: Allow calling with Python file - func_fdtransform = lambda _, cond, data: func(channel, cond, data) + func_fdtransform = lambda _, cond, *data: callback(channel, cond, *data) real_channel = GLib.IOChannel.unix_new(channel.fileno()) else: assert isinstance(channel, GLib.IOChannel) - func_fdtransform = func + func_fdtransform = callback real_channel = channel - return GLib.io_add_watch(real_channel, priority_, condition, - func_fdtransform, user_data) + return real_channel, priority_, condition, func_fdtransform, user_data + + +__all__.append('_io_add_watch_get_args') + + +def io_add_watch(*args, **kwargs): + """io_add_watch(channel, priority, condition, func, *user_data) -> event_source_id""" + channel, priority, condition, func, user_data = _io_add_watch_get_args(*args, **kwargs) + return GLib.io_add_watch(channel, priority, condition, func, *user_data) + __all__.append('io_add_watch') @@ -726,6 +701,9 @@ class IOChannel(GLib.IOChannel): return GLib.IOChannel.win32_new_fd(hwnd) raise TypeError('either a valid file descriptor, file name, or window handle must be supplied') + def __init__(self, *args, **kwargs): + return super(IOChannel, self).__init__() + def read(self, max_count=-1): return io_channel_read(self, max_count) @@ -790,6 +768,7 @@ class IOChannel(GLib.IOChannel): # Python 2.x compatibility next = __next__ + IOChannel = override(IOChannel) __all__.append('IOChannel') @@ -804,18 +783,19 @@ class PollFD(GLib.PollFD): self.fd = fd self.events = events + PollFD = override(PollFD) __all__.append('PollFD') -# The real GLib API is child_watch_add(priority, pid, callback, data). -# The old static bindings had the following API which we still need to support -# for a while: -# child_watch_add(pid, callback, data=None, priority=GLib.PRIORITY_DEFAULT) -# and the usual "call without user_data", in which case the callback does not -# get an user_data either. -def child_watch_add(priority_or_pid, pid_or_callback, *args, **kwargs): - _unspecified = object() +# The GI GLib API uses g_child_watch_add_full renamed to g_child_watch_add with +# a signature of (priority, pid, callback, data). +# Prior to PyGObject 3.8, this function was statically bound with an API closer to the +# non-full version with a signature of: (pid, callback, data=None, priority=GLib.PRIORITY_DEFAULT) +# We need to support this until we are okay with breaking API in a way which is +# not backwards compatible. +def _child_watch_add_get_args(priority_or_pid, pid_or_callback, *args, **kwargs): + user_data = [] if callable(pid_or_callback): warnings.warn('Calling child_watch_add without priority as first argument is deprecated', @@ -823,35 +803,44 @@ def child_watch_add(priority_or_pid, pid_or_callback, *args, **kwargs): pid = priority_or_pid callback = pid_or_callback if len(args) == 0: - user_data = kwargs.get('data', _unspecified) priority = kwargs.get('priority', GLib.PRIORITY_DEFAULT) elif len(args) == 1: - user_data = args[0] + user_data = args priority = kwargs.get('priority', GLib.PRIORITY_DEFAULT) elif len(args) == 2: - user_data = args[0] + user_data = [args[0]] priority = args[1] else: raise TypeError('expected at most 4 positional arguments') else: priority = priority_or_pid pid = pid_or_callback - if len(args) == 0 or not callable(args[0]): - raise TypeError('expected callback as third argument') - callback = args[0] - if len(args) == 1: - user_data = kwargs.get('data', _unspecified) + if 'function' in kwargs: + callback = kwargs['function'] + user_data = args + elif len(args) > 0 and callable(args[0]): + callback = args[0] + user_data = args[1:] else: - user_data = args[1] + raise TypeError('expected callback as third argument') + + if 'data' in kwargs: + if user_data: + raise TypeError('got multiple values for "data" argument') + user_data = (kwargs['data'],) + + return priority, pid, callback, user_data - if user_data is _unspecified: - # we have to call the callback without the user_data argument - func = lambda pid, status, data: callback(pid, status) - user_data = None - else: - func = callback - return GLib.child_watch_add(priority, pid, func, user_data) +# we need this to be accessible for unit testing +__all__.append('_child_watch_add_get_args') + + +def child_watch_add(*args, **kwargs): + """child_watch_add(priority, pid, function, *data)""" + priority, pid, function, data = _child_watch_add_get_args(*args, **kwargs) + return GLib.child_watch_add(priority, pid, function, *data) + __all__.append('child_watch_add') @@ -859,6 +848,7 @@ __all__.append('child_watch_add') def get_current_time(): return GLib.get_real_time() * 0.000001 + get_current_time = deprecated(get_current_time, 'GLib.get_real_time()') __all__.append('get_current_time') @@ -869,21 +859,22 @@ __all__.append('get_current_time') def filename_from_utf8(utf8string, len=-1): return GLib.filename_from_utf8(utf8string, len)[0] -__all__.append('filename_from_utf8') +__all__.append('filename_from_utf8') -# backwards compatible API for renamed function -if not hasattr(GLib, 'unix_signal_add_full'): - def add_full_compat(*args): - warnings.warn('GLib.unix_signal_add_full() was renamed to GLib.unix_signal_add()', - PyGIDeprecationWarning) - return GLib.unix_signal_add(*args) - GLib.unix_signal_add_full = add_full_compat +if hasattr(GLib, "unix_signal_add"): + unix_signal_add_full = GLib.unix_signal_add + __all__.append('unix_signal_add_full') + deprecated_attr("GLib", "unix_signal_add_full", "GLib.unix_signal_add") # obsolete constants for backwards compatibility glib_version = (GLib.MAJOR_VERSION, GLib.MINOR_VERSION, GLib.MICRO_VERSION) __all__.append('glib_version') +deprecated_attr("GLib", "glib_version", + "(GLib.MAJOR_VERSION, GLib.MINOR_VERSION, GLib.MICRO_VERSION)") + pyglib_version = version_info __all__.append('pyglib_version') +deprecated_attr("GLib", "pyglib_version", "gi.version_info") diff --git a/gi/overrides/GObject.py b/gi/overrides/GObject.py index b3aad47..823c0b0 100644 --- a/gi/overrides/GObject.py +++ b/gi/overrides/GObject.py @@ -21,28 +21,26 @@ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 # USA -import sys -import warnings import functools +import warnings from collections import namedtuple -import gi.overrides import gi.module -from gi.overrides import override +from gi.overrides import override, deprecated_attr from gi.repository import GLib from gi import PyGIDeprecationWarning +from gi import _propertyhelper as propertyhelper +from gi import _signalhelper as signalhelper +from gi import _gi -from gi._gobject import _gobject -from gi._gobject import propertyhelper -from gi._gobject import signalhelper GObjectModule = gi.module.get_introspection_module('GObject') __all__ = [] -from gi._glib import option -sys.modules['gi._gobject.option'] = option +from gi import _option as option +option = option # API aliases for backwards compatibility @@ -56,10 +54,11 @@ for name in ['markup_escape_text', 'get_application_name', 'idle_add', 'timeout_add', 'timeout_add_seconds', 'io_add_watch', 'child_watch_add', 'get_current_time', 'spawn_async']: - globals()[name] = gi.overrides.deprecated(getattr(GLib, name), 'GLib.' + name) + globals()[name] = getattr(GLib, name) + deprecated_attr("GObject", name, "GLib." + name) __all__.append(name) -# constants are also deprecated, but cannot mark them as such +# deprecated constants for name in ['PRIORITY_DEFAULT', 'PRIORITY_DEFAULT_IDLE', 'PRIORITY_HIGH', 'PRIORITY_HIGH_IDLE', 'PRIORITY_LOW', 'IO_IN', 'IO_OUT', 'IO_PRI', 'IO_ERR', 'IO_HUP', 'IO_NVAL', @@ -77,25 +76,21 @@ for name in ['PRIORITY_DEFAULT', 'PRIORITY_DEFAULT_IDLE', 'PRIORITY_HIGH', 'OPTION_FLAG_NOALIAS', 'OPTION_ERROR_UNKNOWN_OPTION', 'OPTION_ERROR_BAD_VALUE', 'OPTION_ERROR_FAILED', 'OPTION_REMAINING', 'glib_version']: - globals()[name] = getattr(GLib, name) + with warnings.catch_warnings(): + # TODO: this uses deprecated Glib attributes, silence for now + warnings.simplefilter('ignore', PyGIDeprecationWarning) + globals()[name] = getattr(GLib, name) + deprecated_attr("GObject", name, "GLib." + name) __all__.append(name) -G_MININT8 = GLib.MININT8 -G_MAXINT8 = GLib.MAXINT8 -G_MAXUINT8 = GLib.MAXUINT8 -G_MININT16 = GLib.MININT16 -G_MAXINT16 = GLib.MAXINT16 -G_MAXUINT16 = GLib.MAXUINT16 -G_MININT32 = GLib.MININT32 -G_MAXINT32 = GLib.MAXINT32 -G_MAXUINT32 = GLib.MAXUINT32 -G_MININT64 = GLib.MININT64 -G_MAXINT64 = GLib.MAXINT64 -G_MAXUINT64 = GLib.MAXUINT64 -__all__ += ['G_MININT8', 'G_MAXINT8', 'G_MAXUINT8', 'G_MININT16', - 'G_MAXINT16', 'G_MAXUINT16', 'G_MININT32', 'G_MAXINT32', - 'G_MAXUINT32', 'G_MININT64', 'G_MAXINT64', 'G_MAXUINT64'] +for name in ['G_MININT8', 'G_MAXINT8', 'G_MAXUINT8', 'G_MININT16', + 'G_MAXINT16', 'G_MAXUINT16', 'G_MININT32', 'G_MAXINT32', + 'G_MAXUINT32', 'G_MININT64', 'G_MAXINT64', 'G_MAXUINT64']: + new_name = name.split("_", 1)[-1] + globals()[name] = getattr(GLib, new_name) + deprecated_attr("GObject", name, "GLib." + new_name) + __all__.append(name) # these are not currently exported in GLib gir, presumably because they are # platform dependent; so get them from our static bindings @@ -103,7 +98,9 @@ for name in ['G_MINFLOAT', 'G_MAXFLOAT', 'G_MINDOUBLE', 'G_MAXDOUBLE', 'G_MINSHORT', 'G_MAXSHORT', 'G_MAXUSHORT', 'G_MININT', 'G_MAXINT', 'G_MAXUINT', 'G_MINLONG', 'G_MAXLONG', 'G_MAXULONG', 'G_MAXSIZE', 'G_MINSSIZE', 'G_MAXSSIZE', 'G_MINOFFSET', 'G_MAXOFFSET']: - globals()[name] = getattr(_gobject, name) + new_name = name.split("_", 1)[-1] + globals()[name] = getattr(GLib, new_name) + deprecated_attr("GObject", name, "GLib." + new_name) __all__.append(name) @@ -145,69 +142,64 @@ __all__ += ['TYPE_INVALID', 'TYPE_NONE', 'TYPE_INTERFACE', 'TYPE_CHAR', # Deprecated, use GLib directly -Pid = GLib.Pid -GError = GLib.GError -OptionGroup = GLib.OptionGroup -OptionContext = GLib.OptionContext -__all__ += ['Pid', 'GError', 'OptionGroup', 'OptionContext'] +for name in ['Pid', 'GError', 'OptionGroup', 'OptionContext']: + globals()[name] = getattr(GLib, name) + deprecated_attr("GObject", name, "GLib." + name) + __all__.append(name) # Deprecated, use: GObject.ParamFlags.* directly -PARAM_CONSTRUCT = GObjectModule.ParamFlags.CONSTRUCT -PARAM_CONSTRUCT_ONLY = GObjectModule.ParamFlags.CONSTRUCT_ONLY -PARAM_LAX_VALIDATION = GObjectModule.ParamFlags.LAX_VALIDATION -PARAM_READABLE = GObjectModule.ParamFlags.READABLE -PARAM_WRITABLE = GObjectModule.ParamFlags.WRITABLE +for name in ['PARAM_CONSTRUCT', 'PARAM_CONSTRUCT_ONLY', 'PARAM_LAX_VALIDATION', + 'PARAM_READABLE', 'PARAM_WRITABLE']: + new_name = name.split("_", 1)[-1] + globals()[name] = getattr(GObjectModule.ParamFlags, new_name) + deprecated_attr("GObject", name, "GObject.ParamFlags." + new_name) + __all__.append(name) + # PARAM_READWRITE should come from the gi module but cannot due to: -# https://bugzilla.gnome.org/show_bug.cgi?id=687615 -PARAM_READWRITE = PARAM_READABLE | PARAM_WRITABLE -__all__ += ['PARAM_CONSTRUCT', 'PARAM_CONSTRUCT_ONLY', 'PARAM_LAX_VALIDATION', - 'PARAM_READABLE', 'PARAM_WRITABLE', 'PARAM_READWRITE'] +# https://gitlab.gnome.org/GNOME/gobject-introspection/issues/75 +PARAM_READWRITE = GObjectModule.ParamFlags.READABLE | \ + GObjectModule.ParamFlags.WRITABLE +deprecated_attr("GObject", "PARAM_READWRITE", "GObject.ParamFlags.READWRITE") +__all__.append("PARAM_READWRITE") # Deprecated, use: GObject.SignalFlags.* directly -SIGNAL_ACTION = GObjectModule.SignalFlags.ACTION -SIGNAL_DETAILED = GObjectModule.SignalFlags.DETAILED -SIGNAL_NO_HOOKS = GObjectModule.SignalFlags.NO_HOOKS -SIGNAL_NO_RECURSE = GObjectModule.SignalFlags.NO_RECURSE -SIGNAL_RUN_CLEANUP = GObjectModule.SignalFlags.RUN_CLEANUP -SIGNAL_RUN_FIRST = GObjectModule.SignalFlags.RUN_FIRST -SIGNAL_RUN_LAST = GObjectModule.SignalFlags.RUN_LAST -__all__ += ['SIGNAL_ACTION', 'SIGNAL_DETAILED', 'SIGNAL_NO_HOOKS', - 'SIGNAL_NO_RECURSE', 'SIGNAL_RUN_CLEANUP', 'SIGNAL_RUN_FIRST', - 'SIGNAL_RUN_LAST'] - +for name in ['SIGNAL_ACTION', 'SIGNAL_DETAILED', 'SIGNAL_NO_HOOKS', + 'SIGNAL_NO_RECURSE', 'SIGNAL_RUN_CLEANUP', 'SIGNAL_RUN_FIRST', + 'SIGNAL_RUN_LAST']: + new_name = name.split("_", 1)[-1] + globals()[name] = getattr(GObjectModule.SignalFlags, new_name) + deprecated_attr("GObject", name, "GObject.SignalFlags." + new_name) + __all__.append(name) # Static types -GBoxed = _gobject.GBoxed -GEnum = _gobject.GEnum -GFlags = _gobject.GFlags -GInterface = _gobject.GInterface -GObject = _gobject.GObject -GObjectWeakRef = _gobject.GObjectWeakRef -GParamSpec = _gobject.GParamSpec -GPointer = _gobject.GPointer -GType = _gobject.GType -Warning = _gobject.Warning +GBoxed = _gi.GBoxed +GEnum = _gi.GEnum +GFlags = _gi.GFlags +GInterface = _gi.GInterface +GObject = _gi.GObject +GObjectWeakRef = _gi.GObjectWeakRef +GParamSpec = _gi.GParamSpec +GPointer = _gi.GPointer +GType = _gi.GType +Warning = _gi.Warning __all__ += ['GBoxed', 'GEnum', 'GFlags', 'GInterface', 'GObject', 'GObjectWeakRef', 'GParamSpec', 'GPointer', 'GType', 'Warning'] -features = _gobject.features -list_properties = _gobject.list_properties -new = _gobject.new -pygobject_version = _gobject.pygobject_version +features = {'generic-c-marshaller': True} +list_properties = _gi.list_properties +new = _gi.new +pygobject_version = _gi.pygobject_version threads_init = GLib.threads_init -type_register = _gobject.type_register +type_register = _gi.type_register __all__ += ['features', 'list_properties', 'new', 'pygobject_version', 'threads_init', 'type_register'] class Value(GObjectModule.Value): - def __new__(cls, *args, **kwargs): - return GObjectModule.Value.__new__(cls) - def __init__(self, value_type=None, py_value=None): GObjectModule.Value.__init__(self) if value_type is not None: @@ -215,136 +207,91 @@ class Value(GObjectModule.Value): if py_value is not None: self.set_value(py_value) - def __del__(self): - if self._free_on_dealloc and self.g_type != TYPE_INVALID: - self.unset() + @property + def __g_type(self): + # XXX: This is the same as self.g_type, but the field marshalling + # code is currently very slow. + return _gi._gvalue_get_type(self) def set_boxed(self, boxed): + if not self.__g_type.is_a(TYPE_BOXED): + warnings.warn('Calling set_boxed() on a non-boxed type deprecated', + PyGIDeprecationWarning, stacklevel=2) # Workaround the introspection marshalers inability to know # these methods should be marshaling boxed types. This is because # the type information is stored on the GValue. - _gobject._gvalue_set(self, boxed) + _gi._gvalue_set(self, boxed) def get_boxed(self): - return _gobject._gvalue_get(self) + if not self.__g_type.is_a(TYPE_BOXED): + warnings.warn('Calling get_boxed() on a non-boxed type deprecated', + PyGIDeprecationWarning, stacklevel=2) + return _gi._gvalue_get(self) def set_value(self, py_value): - gtype = self.g_type + gtype = self.__g_type - if gtype == _gobject.TYPE_INVALID: - raise TypeError("GObject.Value needs to be initialized first") - elif gtype == TYPE_BOOLEAN: - self.set_boolean(py_value) - elif gtype == TYPE_CHAR: + if gtype == TYPE_CHAR: self.set_char(py_value) elif gtype == TYPE_UCHAR: self.set_uchar(py_value) - elif gtype == TYPE_INT: - self.set_int(py_value) - elif gtype == TYPE_UINT: - self.set_uint(py_value) - elif gtype == TYPE_LONG: - self.set_long(py_value) - elif gtype == TYPE_ULONG: - self.set_ulong(py_value) - elif gtype == TYPE_INT64: - self.set_int64(py_value) - elif gtype == TYPE_UINT64: - self.set_uint64(py_value) - elif gtype == TYPE_FLOAT: - self.set_float(py_value) - elif gtype == TYPE_DOUBLE: - self.set_double(py_value) elif gtype == TYPE_STRING: - if isinstance(py_value, str): - py_value = str(py_value) - elif sys.version_info < (3, 0): - if isinstance(py_value, unicode): - py_value = py_value.encode('UTF-8') - else: - raise ValueError("Expected string or unicode but got %s%s" % - (py_value, type(py_value))) - else: - raise ValueError("Expected string but got %s%s" % - (py_value, type(py_value))) - self.set_string(py_value) + if not isinstance(py_value, str) and py_value is not None: + raise TypeError("Expected string but got %s%s" % + (py_value, type(py_value))) + _gi._gvalue_set(self, py_value) elif gtype == TYPE_PARAM: self.set_param(py_value) - elif gtype.is_a(TYPE_ENUM): - self.set_enum(py_value) elif gtype.is_a(TYPE_FLAGS): self.set_flags(py_value) - elif gtype.is_a(TYPE_BOXED): - self.set_boxed(py_value) elif gtype == TYPE_POINTER: self.set_pointer(py_value) - elif gtype.is_a(TYPE_OBJECT): - self.set_object(py_value) - elif gtype == TYPE_UNICHAR: - self.set_uint(int(py_value)) - # elif gtype == TYPE_OVERRIDE: - # pass elif gtype == TYPE_GTYPE: self.set_gtype(py_value) elif gtype == TYPE_VARIANT: self.set_variant(py_value) - elif gtype == TYPE_PYOBJECT: - self.set_boxed(py_value) else: - raise TypeError("Unknown value type %s" % gtype) + # Fall back to _gvalue_set which handles some more cases + # like fundamentals for which a converter is registered + try: + _gi._gvalue_set(self, py_value) + except TypeError: + if gtype == TYPE_INVALID: + raise TypeError("GObject.Value needs to be initialized first") + raise def get_value(self): - gtype = self.g_type + gtype = self.__g_type - if gtype == TYPE_BOOLEAN: - return self.get_boolean() - elif gtype == TYPE_CHAR: + if gtype == TYPE_CHAR: return self.get_char() elif gtype == TYPE_UCHAR: return self.get_uchar() - elif gtype == TYPE_INT: - return self.get_int() - elif gtype == TYPE_UINT: - return self.get_uint() - elif gtype == TYPE_LONG: - return self.get_long() - elif gtype == TYPE_ULONG: - return self.get_ulong() - elif gtype == TYPE_INT64: - return self.get_int64() - elif gtype == TYPE_UINT64: - return self.get_uint64() - elif gtype == TYPE_FLOAT: - return self.get_float() - elif gtype == TYPE_DOUBLE: - return self.get_double() - elif gtype == TYPE_STRING: - return self.get_string() elif gtype == TYPE_PARAM: return self.get_param() elif gtype.is_a(TYPE_ENUM): return self.get_enum() elif gtype.is_a(TYPE_FLAGS): return self.get_flags() - elif gtype.is_a(TYPE_BOXED): - return self.get_boxed() elif gtype == TYPE_POINTER: return self.get_pointer() - elif gtype.is_a(TYPE_OBJECT): - return self.get_object() - elif gtype == TYPE_UNICHAR: - return self.get_uint() elif gtype == TYPE_GTYPE: return self.get_gtype() elif gtype == TYPE_VARIANT: - return self.get_variant() - elif gtype == TYPE_PYOBJECT: - pass + # get_variant was missing annotations + # https://gitlab.gnome.org/GNOME/glib/merge_requests/492 + return self.dup_variant() else: - return None + try: + return _gi._gvalue_get(self) + except TypeError: + if gtype == TYPE_INVALID: + return None + raise def __repr__(self): - return '<Value (%s) %s>' % (self.g_type.name, self.get_value()) + return '<Value (%s) %s>' % (self.__g_type.name, self.get_value()) + Value = override(Value) __all__.append('Value') @@ -356,6 +303,7 @@ def type_from_name(name): raise RuntimeError('unknown type name: %s' % name) return type_ + __all__.append('type_from_name') @@ -365,6 +313,7 @@ def type_parent(type_): raise RuntimeError('no parent for type') return parent + __all__.append('type_parent') @@ -379,6 +328,7 @@ def signal_list_ids(type_): _validate_type_for_signal_method(type_) return GObjectModule.signal_list_ids(type_) + __all__.append('signal_list_ids') @@ -386,6 +336,7 @@ def signal_list_names(type_): ids = signal_list_ids(type_) return tuple(GObjectModule.signal_name(i) for i in ids) + __all__.append('signal_list_names') @@ -393,51 +344,40 @@ def signal_lookup(name, type_): _validate_type_for_signal_method(type_) return GObjectModule.signal_lookup(name, type_) + __all__.append('signal_lookup') +SignalQuery = namedtuple('SignalQuery', + ['signal_id', + 'signal_name', + 'itype', + 'signal_flags', + 'return_type', + # n_params', + 'param_types']) + + def signal_query(id_or_name, type_=None): - SignalQuery = namedtuple('SignalQuery', - ['signal_id', - 'signal_name', - 'itype', - 'signal_flags', - 'return_type', - # n_params', - 'param_types']) - - # signal_query needs to use a static method until the following bugs are fixed: - # https://bugzilla.gnome.org/show_bug.cgi?id=687550 - # https://bugzilla.gnome.org/show_bug.cgi?id=687545 - # https://bugzilla.gnome.org/show_bug.cgi?id=687541 if type_ is not None: id_or_name = signal_lookup(id_or_name, type_) - res = _gobject.signal_query(id_or_name) - if res is None: - return None - - # Return a named tuple which allows indexing like the static bindings - # along with field like access of the gi struct. - # Note however that the n_params was not returned from the static bindings. - return SignalQuery(*res) - -__all__.append('signal_query') + res = GObjectModule.signal_query(id_or_name) + assert res is not None + if res.signal_id == 0: + return None -# Check needed for glib versions which annotate signal related methods -# with a void pointer instead of GObject.Object. -# See: https://bugzilla.gnome.org/show_bug.cgi?id=685387 -_is_first_signal_arg_void = GObjectModule.signal_stop_emission.get_arguments()[0].get_pytype_hint() == 'void' + # Return a named tuple to allows indexing which is compatible with the + # static bindings along with field like access of the gi struct. + # Note however that the n_params was not returned from the static bindings + # so we must skip over it. + return SignalQuery(res.signal_id, res.signal_name, res.itype, + res.signal_flags, res.return_type, + tuple(res.param_types)) -def _get_instance_for_signal(obj): - if not _is_first_signal_arg_void: - return obj - elif isinstance(obj, GObjectModule.Object): - return obj.__gpointer__ - else: - raise TypeError('Unsupported object "%s" for signal function' % obj) +__all__.append('signal_query') class _HandlerBlockManager(object): @@ -449,75 +389,43 @@ class _HandlerBlockManager(object): pass def __exit__(self, exc_type, exc_value, traceback): - signal_handler_unblock(self.obj, self.handler_id) + GObjectModule.signal_handler_unblock(self.obj, self.handler_id) def signal_handler_block(obj, handler_id): - """Blocks the signal handler from being invoked until handler_unblock() is called. + """Blocks the signal handler from being invoked until + handler_unblock() is called. - Returns a context manager which optionally can be used to - automatically unblock the handler: + :param GObject.Object obj: + Object instance to block handlers for. + :param int handler_id: + Id of signal to block. + :returns: + A context manager which optionally can be used to + automatically unblock the handler: - with GObject.signal_handler_block(obj, id): - pass + .. code-block:: python + + with GObject.signal_handler_block(obj, id): + pass """ - GObjectModule.signal_handler_block(_get_instance_for_signal(obj), handler_id) + GObjectModule.signal_handler_block(obj, handler_id) return _HandlerBlockManager(obj, handler_id) -__all__.append('signal_handler_block') - -if _is_first_signal_arg_void: - # The following functions wrap GI functions but coerce the first arg into - # something compatible with gpointer - - def _wrap_signal_func(func): - @functools.wraps(func) - def wrapper(obj, *args, **kwargs): - return func(_get_instance_for_signal(obj), *args, **kwargs) - return wrapper - - signal_handler_unblock = _wrap_signal_func(GObjectModule.signal_handler_unblock) - signal_handler_disconnect = _wrap_signal_func(GObjectModule.signal_handler_disconnect) - signal_handler_is_connected = _wrap_signal_func(GObjectModule.signal_handler_is_connected) - signal_stop_emission = _wrap_signal_func(GObjectModule.signal_stop_emission) - signal_stop_emission_by_name = _wrap_signal_func(GObjectModule.signal_stop_emission_by_name) - signal_has_handler_pending = _wrap_signal_func(GObjectModule.signal_has_handler_pending) - signal_get_invocation_hint = _wrap_signal_func(GObjectModule.signal_get_invocation_hint) - signal_connect_closure = _wrap_signal_func(GObjectModule.signal_connect_closure) - signal_connect_closure_by_id = _wrap_signal_func(GObjectModule.signal_connect_closure_by_id) - signal_handler_find = _wrap_signal_func(GObjectModule.signal_handler_find) - signal_handlers_destroy = _wrap_signal_func(GObjectModule.signal_handlers_destroy) - signal_handlers_block_matched = _wrap_signal_func(GObjectModule.signal_handlers_block_matched) - signal_handlers_unblock_matched = _wrap_signal_func(GObjectModule.signal_handlers_unblock_matched) - signal_handlers_disconnect_matched = _wrap_signal_func(GObjectModule.signal_handlers_disconnect_matched) - - __all__ += ['signal_handler_unblock', - 'signal_handler_disconnect', 'signal_handler_is_connected', - 'signal_stop_emission', 'signal_stop_emission_by_name', - 'signal_has_handler_pending', 'signal_get_invocation_hint', - 'signal_connect_closure', 'signal_connect_closure_by_id', - 'signal_handler_find', 'signal_handlers_destroy', - 'signal_handlers_block_matched', 'signal_handlers_unblock_matched', - 'signal_handlers_disconnect_matched'] -else: - # First signal arg is GObject.Object but we need these as globals for - # our GObject.Object class override below - signal_handler_disconnect = GObjectModule.signal_handler_disconnect - signal_handler_unblock = GObjectModule.signal_handler_unblock - signal_handler_disconnect = GObjectModule.signal_handler_disconnect - signal_handler_is_connected = GObjectModule.signal_handler_is_connected - signal_stop_emission_by_name = GObjectModule.signal_stop_emission_by_name +__all__.append('signal_handler_block') def signal_parse_name(detailed_signal, itype, force_detail_quark): """Parse a detailed signal name into (signal_id, detail). - :Raises ValueError: - If the given signal is unknown. - - :Returns: + :param str detailed_signal: + Signal name which can include detail. + For example: "notify:prop_name" + :returns: Tuple of (signal_id, detail) + :raises ValueError: + If the given signal is unknown. """ res, signal_id, detail = GObjectModule.signal_parse_name(detailed_signal, itype, force_detail_quark) @@ -526,6 +434,7 @@ def signal_parse_name(detailed_signal, itype, force_detail_quark): else: raise ValueError('%s: unknown signal name: %s' % (itype, detailed_signal)) + __all__.append('signal_parse_name') @@ -533,6 +442,7 @@ def remove_emission_hook(obj, detailed_signal, hook_id): signal_id, detail = signal_parse_name(detailed_signal, obj, True) GObjectModule.signal_remove_emission_hook(signal_id, hook_id) + __all__.append('remove_emission_hook') @@ -543,6 +453,7 @@ def signal_accumulator_first_wins(ihint, return_accu, handler_return, user_data= # Stop emission but return the result of the last handler return (False, handler_return) + __all__.append('signal_accumulator_first_wins') @@ -550,13 +461,14 @@ def signal_accumulator_true_handled(ihint, return_accu, handler_return, user_dat # Stop emission if the last handler returns True return (not handler_return, handler_return) + __all__.append('signal_accumulator_true_handled') # Statically bound signal functions which need to clobber GI (for now) -add_emission_hook = _gobject.add_emission_hook -signal_new = _gobject.signal_new +add_emission_hook = _gi.add_emission_hook +signal_new = _gi.signal_new __all__ += ['add_emission_hook', 'signal_new'] @@ -608,7 +520,6 @@ class Object(GObjectModule.Object): interface_install_property = _unsupported_method interface_list_properties = _unsupported_method notify_by_pspec = _unsupported_method - run_dispose = _unsupported_method watch_closure = _unsupported_method # Make all reference management methods private but still accessible. @@ -624,49 +535,89 @@ class Object(GObjectModule.Object): # The following methods are static APIs which need to leap frog the # gi methods until we verify the gi methods can replace them. - get_property = _gobject.GObject.get_property - get_properties = _gobject.GObject.get_properties - set_property = _gobject.GObject.set_property - set_properties = _gobject.GObject.set_properties - bind_property = _gobject.GObject.bind_property - connect = _gobject.GObject.connect - connect_after = _gobject.GObject.connect_after - connect_object = _gobject.GObject.connect_object - connect_object_after = _gobject.GObject.connect_object_after - disconnect_by_func = _gobject.GObject.disconnect_by_func - handler_block_by_func = _gobject.GObject.handler_block_by_func - handler_unblock_by_func = _gobject.GObject.handler_unblock_by_func - emit = _gobject.GObject.emit - chain = _gobject.GObject.chain - weak_ref = _gobject.GObject.weak_ref - __copy__ = _gobject.GObject.__copy__ - __deepcopy__ = _gobject.GObject.__deepcopy__ + get_property = _gi.GObject.get_property + get_properties = _gi.GObject.get_properties + set_property = _gi.GObject.set_property + set_properties = _gi.GObject.set_properties + bind_property = _gi.GObject.bind_property + connect = _gi.GObject.connect + connect_after = _gi.GObject.connect_after + connect_object = _gi.GObject.connect_object + connect_object_after = _gi.GObject.connect_object_after + disconnect_by_func = _gi.GObject.disconnect_by_func + handler_block_by_func = _gi.GObject.handler_block_by_func + handler_unblock_by_func = _gi.GObject.handler_unblock_by_func + emit = _gi.GObject.emit + chain = _gi.GObject.chain + weak_ref = _gi.GObject.weak_ref + __copy__ = _gi.GObject.__copy__ + __deepcopy__ = _gi.GObject.__deepcopy__ def freeze_notify(self): """Freezes the object's property-changed notification queue. + :returns: + A context manager which optionally can be used to + automatically thaw notifications. + This will freeze the object so that "notify" signals are blocked until the thaw_notify() method is called. - Returns a context manager which optionally can be used to - automatically thaw notifications: + .. code-block:: python - with obj.freeze_notify(): - pass + with obj.freeze_notify(): + pass """ super(Object, self).freeze_notify() return _FreezeNotifyManager(self) + def connect_data(self, detailed_signal, handler, *data, **kwargs): + """Connect a callback to the given signal with optional user data. + + :param str detailed_signal: + A detailed signal to connect to. + :param callable handler: + Callback handler to connect to the signal. + :param *data: + Variable data which is passed through to the signal handler. + :param GObject.ConnectFlags connect_flags: + Flags used for connection options. + :returns: + A signal id which can be used with disconnect. + """ + flags = kwargs.get('connect_flags', 0) + if flags & GObjectModule.ConnectFlags.AFTER: + connect_func = _gi.GObject.connect_after + else: + connect_func = _gi.GObject.connect + + if flags & GObjectModule.ConnectFlags.SWAPPED: + if len(data) != 1: + raise ValueError('Using GObject.ConnectFlags.SWAPPED requires exactly ' + 'one argument for user data, got: %s' % [data]) + + def new_handler(obj, *args): + # Swap obj with the last element in args which will be the user + # data passed to the connect function. + args = list(args) + swap = args.pop() + args = args + [obj] + return handler(swap, *args) + else: + new_handler = handler + + return connect_func(self, detailed_signal, new_handler, *data) + # # Aliases # - disconnect = _signalmethod(signal_handler_disconnect) - handler_block = _signalmethod(signal_handler_block) - handler_unblock = _signalmethod(signal_handler_unblock) - handler_disconnect = _signalmethod(signal_handler_disconnect) - handler_is_connected = _signalmethod(signal_handler_is_connected) - stop_emission_by_name = _signalmethod(signal_stop_emission_by_name) + handler_block = signal_handler_block + handler_unblock = _signalmethod(GObjectModule.signal_handler_unblock) + disconnect = _signalmethod(GObjectModule.signal_handler_disconnect) + handler_disconnect = _signalmethod(GObjectModule.signal_handler_disconnect) + handler_is_connected = _signalmethod(GObjectModule.signal_handler_is_connected) + stop_emission_by_name = _signalmethod(GObjectModule.signal_stop_emission_by_name) # # Deprecated Methods @@ -675,7 +626,7 @@ class Object(GObjectModule.Object): def stop_emission(self, detailed_signal): """Deprecated, please use stop_emission_by_name.""" warnings.warn(self.stop_emission.__doc__, PyGIDeprecationWarning, stacklevel=2) - return signal_stop_emission_by_name(self, detailed_signal) + return self.stop_emission_by_name(detailed_signal) emit_stop_by_name = stop_emission @@ -685,10 +636,34 @@ GObject = Object __all__ += ['Object', 'GObject'] +class Binding(GObjectModule.Binding): + def __call__(self): + warnings.warn('Using parentheses (binding()) to retrieve the Binding object is no ' + 'longer needed because the binding is returned directly from "bind_property.', + PyGIDeprecationWarning, stacklevel=2) + return self + + def unbind(self): + # Fixed in newer glib + if (GLib.MAJOR_VERSION, GLib.MINOR_VERSION, GLib.MICRO_VERSION) >= (2, 57, 3): + return super(Binding, self).unbind() + + if hasattr(self, '_unbound'): + raise ValueError('binding has already been cleared out') + else: + setattr(self, '_unbound', True) + super(Binding, self).unbind() + + +Binding = override(Binding) +__all__.append('Binding') + + Property = propertyhelper.Property Signal = signalhelper.Signal SignalOverride = signalhelper.SignalOverride # Deprecated naming "property" available for backwards compatibility. # Keep this at the end of the file to avoid clobbering the builtin. property = Property +deprecated_attr("GObject", "property", "GObject.Property") __all__ += ['Property', 'Signal', 'SignalOverride', 'property'] diff --git a/gi/overrides/Gdk.py b/gi/overrides/Gdk.py index 14edc70..73f309f 100644 --- a/gi/overrides/Gdk.py +++ b/gi/overrides/Gdk.py @@ -19,60 +19,80 @@ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 # USA +import sys +import warnings + from ..overrides import override, strip_boolean_result from ..module import get_introspection_module - -import sys +from gi import PyGIDeprecationWarning, require_version Gdk = get_introspection_module('Gdk') +GDK2 = Gdk._version == '2.0' +GDK3 = Gdk._version == '3.0' +GDK4 = Gdk._version == '4.0' __all__ = [] -class Color(Gdk.Color): - MAX_VALUE = 65535 +# https://bugzilla.gnome.org/show_bug.cgi?id=673396 +try: + require_version("GdkX11", Gdk._version) + from gi.repository import GdkX11 + GdkX11 # pyflakes +except (ValueError, ImportError): + pass - def __init__(self, red, green, blue): - Gdk.Color.__init__(self) - self.red = red - self.green = green - self.blue = blue +if GDK2 or GDK3: + # Gdk.Color was deprecated since 3.14 and dropped in Gtk-4.0 + class Color(Gdk.Color): + MAX_VALUE = 65535 + + def __init__(self, red, green, blue): + Gdk.Color.__init__(self) + self.red = red + self.green = green + self.blue = blue - def __new__(cls, *args, **kwargs): - return Gdk.Color.__new__(cls) + def __eq__(self, other): + if not isinstance(other, Gdk.Color): + return False + return self.equal(other) - def __eq__(self, other): - return self.equal(other) + # This is required (even when __eq__ is defined) in order + # for != operator to work as expected + def __ne__(self, other): + return not self == other - def __repr__(self): - return '<Gdk.Color(red=%d, green=%d, blue=%d)>' % (self.red, self.green, self.blue) + def __repr__(self): + return 'Gdk.Color(red=%d, green=%d, blue=%d)' % (self.red, self.green, self.blue) - red_float = property(fget=lambda self: self.red / float(self.MAX_VALUE), - fset=lambda self, v: setattr(self, 'red', int(v * self.MAX_VALUE))) + red_float = property(fget=lambda self: self.red / float(self.MAX_VALUE), + fset=lambda self, v: setattr(self, 'red', int(v * self.MAX_VALUE))) - green_float = property(fget=lambda self: self.green / float(self.MAX_VALUE), - fset=lambda self, v: setattr(self, 'green', int(v * self.MAX_VALUE))) + green_float = property(fget=lambda self: self.green / float(self.MAX_VALUE), + fset=lambda self, v: setattr(self, 'green', int(v * self.MAX_VALUE))) - blue_float = property(fget=lambda self: self.blue / float(self.MAX_VALUE), - fset=lambda self, v: setattr(self, 'blue', int(v * self.MAX_VALUE))) + blue_float = property(fget=lambda self: self.blue / float(self.MAX_VALUE), + fset=lambda self, v: setattr(self, 'blue', int(v * self.MAX_VALUE))) - def to_floats(self): - """Return (red_float, green_float, blue_float) triple.""" + def to_floats(self): + """Return (red_float, green_float, blue_float) triple.""" - return (self.red_float, self.green_float, self.blue_float) + return (self.red_float, self.green_float, self.blue_float) - @staticmethod - def from_floats(red, green, blue): - """Return a new Color object from red/green/blue values from 0.0 to 1.0.""" + @staticmethod + def from_floats(red, green, blue): + """Return a new Color object from red/green/blue values from 0.0 to 1.0.""" - return Color(int(red * Color.MAX_VALUE), - int(green * Color.MAX_VALUE), - int(blue * Color.MAX_VALUE)) + return Color(int(red * Color.MAX_VALUE), + int(green * Color.MAX_VALUE), + int(blue * Color.MAX_VALUE)) -Color = override(Color) -__all__.append('Color') + Color = override(Color) + __all__.append('Color') -if Gdk._version == '3.0': +if GDK3: + # Introduced since Gtk-3.0 class RGBA(Gdk.RGBA): def __init__(self, red=1.0, green=1.0, blue=1.0, alpha=1.0): Gdk.RGBA.__init__(self) @@ -81,14 +101,18 @@ if Gdk._version == '3.0': self.blue = blue self.alpha = alpha - def __new__(cls, *args, **kwargs): - return Gdk.RGBA.__new__(cls) - def __eq__(self, other): + if not isinstance(other, Gdk.RGBA): + return False return self.equal(other) + # This is required (even when __eq__ is defined) in order + # for != operator to work as expected + def __ne__(self, other): + return not self == other + def __repr__(self): - return '<Gdk.Color(red=%f, green=%f, blue=%f, alpha=%f)>' % (self.red, self.green, self.blue, self.alpha) + return 'Gdk.RGBA(red=%f, green=%f, blue=%f, alpha=%f)' % (self.red, self.green, self.blue, self.alpha) def __iter__(self): """Iterator which allows easy conversion to tuple and list types.""" @@ -114,7 +138,7 @@ if Gdk._version == '3.0': RGBA = override(RGBA) __all__.append('RGBA') -if Gdk._version == '2.0': +if GDK2: class Rectangle(Gdk.Rectangle): def __init__(self, x, y, width, height): @@ -124,28 +148,37 @@ if Gdk._version == '2.0': self.width = width self.height = height - def __new__(cls, *args, **kwargs): - return Gdk.Rectangle.__new__(cls) - def __repr__(self): - return '<Gdk.Rectangle(x=%d, y=%d, width=%d, height=%d)>' % (self.x, self.y, self.height, self.width) + return 'Gdk.Rectangle(x=%d, y=%d, width=%d, height=%d)' % (self.x, self.y, self.height, self.width) Rectangle = override(Rectangle) __all__.append('Rectangle') -else: - from gi.repository import cairo as _cairo - Rectangle = _cairo.RectangleInt - - __all__.append('Rectangle') - -if Gdk._version == '2.0': +elif GDK3: + # Newer GTK/gobject-introspection (3.17.x) include GdkRectangle in the + # typelib. See https://bugzilla.gnome.org/show_bug.cgi?id=748832 and + # https://bugzilla.gnome.org/show_bug.cgi?id=748833 + if not hasattr(Gdk, 'Rectangle'): + from gi.repository import cairo as _cairo + Rectangle = _cairo.RectangleInt + + __all__.append('Rectangle') + else: + # https://bugzilla.gnome.org/show_bug.cgi?id=756364 + # These methods used to be functions, keep aliases for backwards compat + rectangle_intersect = Gdk.Rectangle.intersect + rectangle_union = Gdk.Rectangle.union + + __all__.append('rectangle_intersect') + __all__.append('rectangle_union') + +if GDK2: class Drawable(Gdk.Drawable): def cairo_create(self): return Gdk.cairo_create(self) Drawable = override(Drawable) __all__.append('Drawable') -else: +elif GDK3: class Window(Gdk.Window): def __new__(cls, parent, attributes, attributes_mask): # Gdk.Window had to be made abstract, @@ -161,195 +194,243 @@ else: Window = override(Window) __all__.append('Window') -Gdk.EventType._2BUTTON_PRESS = getattr(Gdk.EventType, "2BUTTON_PRESS") -Gdk.EventType._3BUTTON_PRESS = getattr(Gdk.EventType, "3BUTTON_PRESS") - - -class Event(Gdk.Event): - _UNION_MEMBERS = { - Gdk.EventType.DELETE: 'any', - Gdk.EventType.DESTROY: 'any', - Gdk.EventType.EXPOSE: 'expose', - Gdk.EventType.MOTION_NOTIFY: 'motion', - Gdk.EventType.BUTTON_PRESS: 'button', - Gdk.EventType._2BUTTON_PRESS: 'button', - Gdk.EventType._3BUTTON_PRESS: 'button', - Gdk.EventType.BUTTON_RELEASE: 'button', - Gdk.EventType.KEY_PRESS: 'key', - Gdk.EventType.KEY_RELEASE: 'key', - Gdk.EventType.ENTER_NOTIFY: 'crossing', - Gdk.EventType.LEAVE_NOTIFY: 'crossing', - Gdk.EventType.FOCUS_CHANGE: 'focus_change', - Gdk.EventType.CONFIGURE: 'configure', - Gdk.EventType.MAP: 'any', - Gdk.EventType.UNMAP: 'any', - Gdk.EventType.PROPERTY_NOTIFY: 'property', - Gdk.EventType.SELECTION_CLEAR: 'selection', - Gdk.EventType.SELECTION_REQUEST: 'selection', - Gdk.EventType.SELECTION_NOTIFY: 'selection', - Gdk.EventType.PROXIMITY_IN: 'proximity', - Gdk.EventType.PROXIMITY_OUT: 'proximity', - Gdk.EventType.DRAG_ENTER: 'dnd', - Gdk.EventType.DRAG_LEAVE: 'dnd', - Gdk.EventType.DRAG_MOTION: 'dnd', - Gdk.EventType.DRAG_STATUS: 'dnd', - Gdk.EventType.DROP_START: 'dnd', - Gdk.EventType.DROP_FINISHED: 'dnd', - Gdk.EventType.CLIENT_EVENT: 'client', - Gdk.EventType.VISIBILITY_NOTIFY: 'visibility', - } - - if Gdk._version == '2.0': - _UNION_MEMBERS[Gdk.EventType.NO_EXPOSE] = 'no_expose' - - def __new__(cls, *args, **kwargs): - return Gdk.Event.__new__(cls) - - def __getattr__(self, name): - real_event = getattr(self, '_UNION_MEMBERS').get(self.type) - if real_event: - return getattr(getattr(self, real_event), name) - else: - raise AttributeError("'%s' object has no attribute '%s'" % (self.__class__.__name__, name)) - -Event = override(Event) -__all__.append('Event') - -# manually bind GdkEvent members to GdkEvent - -modname = globals()['__name__'] -module = sys.modules[modname] - -# right now we can't get the type_info from the -# field info so manually list the class names -event_member_classes = ['EventAny', - 'EventExpose', - 'EventVisibility', - 'EventMotion', - 'EventButton', - 'EventScroll', - 'EventKey', - 'EventCrossing', - 'EventFocus', - 'EventConfigure', - 'EventProperty', - 'EventSelection', - 'EventOwnerChange', - 'EventProximity', - 'EventDND', - 'EventWindowState', - 'EventSetting', - 'EventGrabBroken'] - -if Gdk._version == '2.0': - event_member_classes.append('EventNoExpose') - -# whitelist all methods that have a success return we want to mask -gsuccess_mask_funcs = ['get_state', - 'get_axis', - 'get_coords', - 'get_root_coords'] - - -for event_class in event_member_classes: - override_class = type(event_class, (getattr(Gdk, event_class),), {}) - # add the event methods - for method_info in Gdk.Event.__info__.get_methods(): - name = method_info.get_name() - event_method = getattr(Gdk.Event, name) - # python2 we need to use the __func__ attr to avoid internal - # instance checks - event_method = getattr(event_method, '__func__', event_method) - - # use the _gsuccess_mask decorator if this method is whitelisted - if name in gsuccess_mask_funcs: - event_method = strip_boolean_result(event_method) - setattr(override_class, name, event_method) - - setattr(module, event_class, override_class) - __all__.append(event_class) - -# end GdkEvent overrides - - -class DragContext(Gdk.DragContext): - def finish(self, success, del_, time): - Gtk = get_introspection_module('Gtk') - Gtk.drag_finish(self, success, del_, time) - -DragContext = override(DragContext) -__all__.append('DragContext') - - -class Cursor(Gdk.Cursor): - def __new__(cls, *args, **kwds): - arg_len = len(args) - kwd_len = len(kwds) - total_len = arg_len + kwd_len - - def _new(cursor_type): - return cls.new(cursor_type) - - def _new_for_display(display, cursor_type): - return cls.new_for_display(display, cursor_type) - - def _new_from_pixbuf(display, pixbuf, x, y): - return cls.new_from_pixbuf(display, pixbuf, x, y) - - def _new_from_pixmap(source, mask, fg, bg, x, y): - return cls.new_from_pixmap(source, mask, fg, bg, x, y) - - _constructor = None - if total_len == 1: - _constructor = _new - elif total_len == 2: - _constructor = _new_for_display - elif total_len == 4: - _constructor = _new_from_pixbuf - elif total_len == 6: - if Gdk._version != '2.0': - # pixmaps don't exist in Gdk 3.0 - raise ValueError("Wrong number of parameters") - _constructor = _new_from_pixmap - else: - raise ValueError("Wrong number of parameters") - - return _constructor(*args, **kwds) - - def __init__(self, *args, **kwargs): - Gdk.Cursor.__init__(self) - -Cursor = override(Cursor) -__all__.append('Cursor') - -color_parse = strip_boolean_result(Gdk.color_parse) -__all__.append('color_parse') +if GDK2 or GDK3: + Gdk.EventType._2BUTTON_PRESS = getattr(Gdk.EventType, "2BUTTON_PRESS") + Gdk.EventType._3BUTTON_PRESS = getattr(Gdk.EventType, "3BUTTON_PRESS") + + class Event(Gdk.Event): + _UNION_MEMBERS = { + Gdk.EventType.DELETE: 'any', + Gdk.EventType.DESTROY: 'any', + Gdk.EventType.MOTION_NOTIFY: 'motion', + Gdk.EventType.BUTTON_PRESS: 'button', + Gdk.EventType.BUTTON_RELEASE: 'button', + Gdk.EventType.KEY_PRESS: 'key', + Gdk.EventType.KEY_RELEASE: 'key', + Gdk.EventType.ENTER_NOTIFY: 'crossing', + Gdk.EventType.LEAVE_NOTIFY: 'crossing', + Gdk.EventType.FOCUS_CHANGE: 'focus_change', + Gdk.EventType.CONFIGURE: 'configure', + Gdk.EventType.PROXIMITY_IN: 'proximity', + Gdk.EventType.PROXIMITY_OUT: 'proximity', + Gdk.EventType.DRAG_ENTER: 'dnd', + Gdk.EventType.DRAG_LEAVE: 'dnd', + Gdk.EventType.DRAG_MOTION: 'dnd', + Gdk.EventType.DROP_START: 'dnd', + Gdk.EventType._2BUTTON_PRESS: 'button', + Gdk.EventType._3BUTTON_PRESS: 'button', + Gdk.EventType.PROPERTY_NOTIFY: 'property', + Gdk.EventType.SELECTION_CLEAR: 'selection', + Gdk.EventType.SELECTION_REQUEST: 'selection', + Gdk.EventType.SELECTION_NOTIFY: 'selection', + Gdk.EventType.DRAG_STATUS: 'dnd', + Gdk.EventType.DROP_FINISHED: 'dnd', + Gdk.EventType.CLIENT_EVENT: 'client', + Gdk.EventType.VISIBILITY_NOTIFY: 'visibility', + Gdk.EventType.SCROLL: 'scroll', + Gdk.EventType.EXPOSE: 'expose', + Gdk.EventType.MAP: 'any', + Gdk.EventType.UNMAP: 'any', + } + + if GDK2: + _UNION_MEMBERS[Gdk.EventType.NO_EXPOSE] = 'no_expose' + + if hasattr(Gdk.EventType, 'TOUCH_BEGIN'): + _UNION_MEMBERS.update( + { + Gdk.EventType.TOUCH_BEGIN: 'touch', + Gdk.EventType.TOUCH_UPDATE: 'touch', + Gdk.EventType.TOUCH_END: 'touch', + Gdk.EventType.TOUCH_CANCEL: 'touch', + }) + + def __getattr__(self, name): + real_event = getattr(self, '_UNION_MEMBERS').get(self.type) + if real_event: + return getattr(getattr(self, real_event), name) + else: + raise AttributeError("'%s' object has no attribute '%s'" % (self.__class__.__name__, name)) + + def __setattr__(self, name, value): + real_event = getattr(self, '_UNION_MEMBERS').get(self.type) + if real_event: + setattr(getattr(self, real_event), name, value) + else: + Gdk.Event.__setattr__(self, name, value) + def __repr__(self): + base_repr = Gdk.Event.__repr__(self).strip("><") + return "<%s type=%r>" % (base_repr, self.type) + + Event = override(Event) + __all__.append('Event') + + # manually bind GdkEvent members to GdkEvent + + modname = globals()['__name__'] + module = sys.modules[modname] + + # right now we can't get the type_info from the + # field info so manually list the class names + event_member_classes = ['EventAny', + 'EventExpose', + 'EventMotion', + 'EventButton', + 'EventScroll', + 'EventKey', + 'EventCrossing', + 'EventFocus', + 'EventConfigure', + 'EventProximity', + 'EventDND', + 'EventSetting', + 'EventGrabBroken', + 'EventVisibility', + 'EventProperty', + 'EventSelection', + 'EventOwnerChange', + 'EventWindowState', + 'EventVisibility'] + + if GDK2: + event_member_classes.append('EventNoExpose') + + if hasattr(Gdk, 'EventTouch'): + event_member_classes.append('EventTouch') + + # whitelist all methods that have a success return we want to mask + gsuccess_mask_funcs = ['get_state', + 'get_axis', + 'get_coords', + 'get_root_coords'] + + for event_class in event_member_classes: + override_class = type(event_class, (getattr(Gdk, event_class),), {}) + # add the event methods + for method_info in Gdk.Event.__info__.get_methods(): + name = method_info.get_name() + event_method = getattr(Gdk.Event, name) + + # use the _gsuccess_mask decorator if this method is whitelisted + if name in gsuccess_mask_funcs: + event_method = strip_boolean_result(event_method) + setattr(override_class, name, event_method) + + setattr(module, event_class, override_class) + __all__.append(event_class) + + # end GdkEvent overrides + + class DragContext(Gdk.DragContext): + def finish(self, success, del_, time): + Gtk = get_introspection_module('Gtk') + Gtk.drag_finish(self, success, del_, time) + + DragContext = override(DragContext) + __all__.append('DragContext') + + class Cursor(Gdk.Cursor): + + def __new__(cls, *args, **kwds): + arg_len = len(args) + kwd_len = len(kwds) + total_len = arg_len + kwd_len + + if total_len == 1: + # Since g_object_newv (super.__new__) does not seem valid for + # direct use with GdkCursor, we must assume usage of at least + # one of the C constructors to be valid. + return cls.new(*args, **kwds) + + elif total_len == 2: + warnings.warn('Calling "Gdk.Cursor(display, cursor_type)" has been deprecated. ' + 'Please use Gdk.Cursor.new_for_display(display, cursor_type). ' + 'See: https://wiki.gnome.org/PyGObject/InitializerDeprecations', + PyGIDeprecationWarning) + return cls.new_for_display(*args, **kwds) + + elif total_len == 4: + warnings.warn('Calling "Gdk.Cursor(display, pixbuf, x, y)" has been deprecated. ' + 'Please use Gdk.Cursor.new_from_pixbuf(display, pixbuf, x, y). ' + 'See: https://wiki.gnome.org/PyGObject/InitializerDeprecations', + PyGIDeprecationWarning) + return cls.new_from_pixbuf(*args, **kwds) + + elif total_len == 6: + if not GDK2: + # pixmaps don't exist in Gdk 3.0 + raise ValueError("Wrong number of parameters") + + warnings.warn('Calling "Gdk.Cursor(source, mask, fg, bg, x, y)" has been deprecated. ' + 'Please use Gdk.Cursor.new_from_pixmap(source, mask, fg, bg, x, y). ' + 'See: https://wiki.gnome.org/PyGObject/InitializerDeprecations', + PyGIDeprecationWarning) + return cls.new_from_pixmap(*args, **kwds) + + else: + raise ValueError("Wrong number of parameters") -# Note, we cannot override the entire class as Gdk.Atom has no gtype, so just -# hack some individual methods -def _gdk_atom_str(atom): - n = atom.name() - if n: - return n - # fall back to atom index - return 'Gdk.Atom<%i>' % hash(atom) + Cursor = override(Cursor) + __all__.append('Cursor') + + # Gdk.Color was deprecated since 3.14 and dropped in Gtk-4.0 + color_parse = strip_boolean_result(Gdk.color_parse) + __all__.append('color_parse') + + # Note, we cannot override the entire class as Gdk.Atom has no gtype, so just + # hack some individual methods + def _gdk_atom_str(atom): + n = atom.name() + if n: + return n + # fall back to atom index + return 'Gdk.Atom<%i>' % hash(atom) + + def _gdk_atom_repr(atom): + n = atom.name() + if n: + return 'Gdk.Atom.intern("%s", False)' % n + # fall back to atom index + return '<Gdk.Atom(%i)>' % hash(atom) + + Gdk.Atom.__str__ = _gdk_atom_str + Gdk.Atom.__repr__ = _gdk_atom_repr + + +if GDK4: + from gi.repository import Gio + + class FileList(Gdk.FileList): + + if hasattr(Gdk.FileList, "new_from_list"): + def __new__(cls, files): + files_list = [] + if isinstance(files, (tuple, list)): + for f in files: + if isinstance(f, Gio.File): + files_list.append(f) + else: + raise TypeError('Constructor requires a list or tuple of Gio.File instances') + else: + raise TypeError('Constructor requires a list or tuple of Gio.File instances') + return Gdk.FileList.new_from_list(files) + def __iter__(self): + return iter(self.get_files()) -def _gdk_atom_repr(atom): - n = atom.name() - if n: - return 'Gdk.Atom<%s>' % n - # fall back to atom index - return 'Gdk.Atom<%i>' % hash(atom) + def __len__(self): + return len(self.get_files()) + def __getitem__(self, index): + return self.get_files()[index] -Gdk.Atom.__str__ = _gdk_atom_str -Gdk.Atom.__repr__ = _gdk_atom_repr + FileList = override(FileList) + __all__.append('FileList') # constants -if Gdk._version >= '3.0': +if GDK3: SELECTION_PRIMARY = Gdk.atom_intern('PRIMARY', True) __all__.append('SELECTION_PRIMARY') @@ -398,6 +479,6 @@ if Gdk._version >= '3.0': SELECTION_TYPE_STRING = Gdk.atom_intern('STRING', True) __all__.append('SELECTION_TYPE_STRING') -import sys - -initialized, argv = Gdk.init_check(sys.argv) +if GDK2 or GDK3: + import sys + initialized, argv = Gdk.init_check(sys.argv) diff --git a/gi/overrides/GdkPixbuf.py b/gi/overrides/GdkPixbuf.py new file mode 100644 index 0000000..0f6cd75 --- /dev/null +++ b/gi/overrides/GdkPixbuf.py @@ -0,0 +1,53 @@ +# Copyright 2018 Christoph Reiter <reiter.christoph@gmail.com> +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# This library is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +# Lesser General Public License for more details. +# +# You should have received a copy of the GNU Lesser General Public +# License along with this library; if not, write to the Free Software +# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 +# USA + +import warnings + +from gi import PyGIDeprecationWarning +from gi.repository import GLib + +from ..overrides import override +from ..module import get_introspection_module + + +GdkPixbuf = get_introspection_module('GdkPixbuf') +__all__ = [] + + +@override +class Pixbuf(GdkPixbuf.Pixbuf): + + @classmethod + def new_from_data( + cls, data, colorspace, has_alpha, bits_per_sample, + width, height, rowstride, + destroy_fn=None, *destroy_fn_data): + + if destroy_fn is not None: + w = PyGIDeprecationWarning("destroy_fn argument deprecated") + warnings.warn(w) + if destroy_fn_data: + w = PyGIDeprecationWarning("destroy_fn_data argument deprecated") + warnings.warn(w) + + data = GLib.Bytes.new(data) + return cls.new_from_bytes( + data, colorspace, has_alpha, bits_per_sample, + width, height, rowstride) + + +__all__.append('Pixbuf') diff --git a/gi/overrides/Gio.py b/gi/overrides/Gio.py index 6ecd1c4..c807fe0 100644 --- a/gi/overrides/Gio.py +++ b/gi/overrides/Gio.py @@ -18,8 +18,12 @@ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 # USA -from ..overrides import override +import warnings + +from .._ossighelper import wakeup_on_signal, register_sigint_fallback +from ..overrides import override, deprecated_init, wrap_list_store_sort_func from ..module import get_introspection_module +from gi import PyGIWarning from gi.repository import GLib @@ -30,6 +34,171 @@ Gio = get_introspection_module('Gio') __all__ = [] +class Application(Gio.Application): + + def run(self, *args, **kwargs): + with register_sigint_fallback(self.quit): + with wakeup_on_signal(): + return Gio.Application.run(self, *args, **kwargs) + + +Application = override(Application) +__all__.append('Application') + + +def _warn_init(cls, instead=None): + + def new_init(self, *args, **kwargs): + super(cls, self).__init__(*args, **kwargs) + name = cls.__module__.rsplit(".", 1)[-1] + "." + cls.__name__ + if instead: + warnings.warn( + ("%s shouldn't be instantiated directly, " + "use %s instead." % (name, instead)), + PyGIWarning, stacklevel=2) + else: + warnings.warn( + "%s shouldn't be instantiated directly." % (name,), + PyGIWarning, stacklevel=2) + + return new_init + + +@override +class VolumeMonitor(Gio.VolumeMonitor): + # https://bugzilla.gnome.org/show_bug.cgi?id=744690 + __init__ = _warn_init(Gio.VolumeMonitor, "Gio.VolumeMonitor.get()") + + +__all__.append('VolumeMonitor') + + +@override +class DBusAnnotationInfo(Gio.DBusAnnotationInfo): + __init__ = _warn_init(Gio.DBusAnnotationInfo) + + +__all__.append('DBusAnnotationInfo') + + +@override +class DBusArgInfo(Gio.DBusArgInfo): + __init__ = _warn_init(Gio.DBusArgInfo) + + +__all__.append('DBusArgInfo') + + +@override +class DBusMethodInfo(Gio.DBusMethodInfo): + __init__ = _warn_init(Gio.DBusMethodInfo) + + +__all__.append('DBusMethodInfo') + + +@override +class DBusSignalInfo(Gio.DBusSignalInfo): + __init__ = _warn_init(Gio.DBusSignalInfo) + + +__all__.append('DBusSignalInfo') + + +@override +class DBusInterfaceInfo(Gio.DBusInterfaceInfo): + __init__ = _warn_init(Gio.DBusInterfaceInfo) + + +__all__.append('DBusInterfaceInfo') + + +@override +class DBusNodeInfo(Gio.DBusNodeInfo): + __init__ = _warn_init(Gio.DBusNodeInfo) + + +__all__.append('DBusNodeInfo') + + +class ActionMap(Gio.ActionMap): + def add_action_entries(self, entries, user_data=None): + """ + The add_action_entries() method is a convenience function for creating + multiple Gio.SimpleAction instances and adding them to a Gio.ActionMap. + Each action is constructed as per one entry. + + :param list entries: + List of entry tuples for add_action() method. The entry tuple can + vary in size with the following information: + + * The name of the action. Must be specified. + * The callback to connect to the "activate" signal of the + action. Since GLib 2.40, this can be None for stateful + actions, in which case the default handler is used. For + boolean-stated actions with no parameter, this is a toggle. + For other state types (and parameter type equal to the state + type) this will be a function that just calls change_state + (which you should provide). + * The type of the parameter that must be passed to the activate + function for this action, given as a single GLib.Variant type + string (or None for no parameter) + * The initial state for this action, given in GLib.Variant text + format. The state is parsed with no extra type information, so + type tags must be added to the string if they are necessary. + Stateless actions should give None here. + * The callback to connect to the "change-state" signal of the + action. All stateful actions should provide a handler here; + stateless actions should not. + + :param user_data: + The user data for signal connections, or None + """ + try: + iter(entries) + except (TypeError): + raise TypeError('entries must be iterable') + + def _process_action(name, activate=None, parameter_type=None, + state=None, change_state=None): + if parameter_type: + if not GLib.VariantType.string_is_valid(parameter_type): + raise TypeError("The type string '%s' given as the " + "parameter type for action '%s' is " + "not a valid GVariant type string. " % + (parameter_type, name)) + variant_parameter = GLib.VariantType.new(parameter_type) + else: + variant_parameter = None + + if state is not None: + # stateful action + variant_state = GLib.Variant.parse(None, state, None, None) + action = Gio.SimpleAction.new_stateful(name, variant_parameter, + variant_state) + if change_state is not None: + action.connect('change-state', change_state, user_data) + else: + # stateless action + if change_state is not None: + raise ValueError("Stateless action '%s' should give " + "None for 'change_state', not '%s'." % + (name, change_state)) + action = Gio.SimpleAction(name=name, parameter_type=variant_parameter) + + if activate is not None: + action.connect('activate', activate, user_data) + self.add_action(action) + + for entry in entries: + # using inner function above since entries can leave out optional arguments + _process_action(*entry) + + +ActionMap = override(ActionMap) +__all__.append('ActionMap') + + class FileEnumerator(Gio.FileEnumerator): def __iter__(self): return self @@ -63,8 +232,8 @@ __all__.append('MenuItem') class Settings(Gio.Settings): '''Provide dictionary-like access to GLib.Settings.''' - def __init__(self, schema, path=None, backend=None, **kwargs): - Gio.Settings.__init__(self, schema=schema, backend=backend, path=path, **kwargs) + __init__ = deprecated_init(Gio.Settings.__init__, + arg_names=('schema', 'path', 'backend')) def __contains__(self, key): return key in self.list_keys() @@ -72,6 +241,10 @@ class Settings(Gio.Settings): def __len__(self): return len(self.list_keys()) + def __iter__(self): + for key in self.list_keys(): + yield key + def __bool__(self): # for "if mysettings" we don't want a dictionary-like test here, just # if the object isn't None @@ -82,14 +255,14 @@ class Settings(Gio.Settings): def __getitem__(self, key): # get_value() aborts the program on an unknown key - if not key in self: + if key not in self: raise KeyError('unknown key: %r' % (key,)) return self.get_value(key).unpack() def __setitem__(self, key, value): # set_value() aborts the program on an unknown key - if not key in self: + if key not in self: raise KeyError('unknown key: %r' % (key,)) # determine type string of this key @@ -108,6 +281,13 @@ class Settings(Gio.Settings): allowed = v.unpack() if value not in allowed: raise ValueError('value %s is not an allowed enum (%s)' % (value, allowed)) + elif type_ == 'range': + tuple_ = v.get_child_value(0) + type_str = tuple_.get_child_value(0).get_type_string() + min_, max_ = tuple_.unpack() + if value < min_ or value > max_: + raise ValueError( + 'value %s not in range (%s - %s)' % (value, min_, max_)) else: raise NotImplementedError('Cannot handle allowed type range class ' + str(type_)) @@ -116,6 +296,7 @@ class Settings(Gio.Settings): def keys(self): return self.list_keys() + Settings = override(Settings) __all__.append('Settings') @@ -235,5 +416,135 @@ class DBusProxy(Gio.DBusProxy): def __getattr__(self, name): return _DBusProxyMethodCall(self, name) + DBusProxy = override(DBusProxy) __all__.append('DBusProxy') + + +class ListModel(Gio.ListModel): + + def __getitem__(self, key): + if isinstance(key, slice): + return [self.get_item(i) for i in range(*key.indices(len(self)))] + elif isinstance(key, int): + if key < 0: + key += len(self) + if key < 0: + raise IndexError + ret = self.get_item(key) + if ret is None: + raise IndexError + return ret + else: + raise TypeError + + def __contains__(self, item): + pytype = self.get_item_type().pytype + if not isinstance(item, pytype): + raise TypeError( + "Expected type %s.%s" % (pytype.__module__, pytype.__name__)) + for i in self: + if i == item: + return True + return False + + def __len__(self): + return self.get_n_items() + + def __iter__(self): + for i in range(len(self)): + yield self.get_item(i) + + +ListModel = override(ListModel) +__all__.append('ListModel') + + +if (GLib.MAJOR_VERSION, GLib.MINOR_VERSION, GLib.MICRO_VERSION) < (2, 57, 1): + # The "additions" functionality in splice() was broken in older glib + # https://bugzilla.gnome.org/show_bug.cgi?id=795307 + # This is a slower fallback which emits a signal per added item + def _list_store_splice(self, position, n_removals, additions): + self.splice(position, n_removals, []) + for v in reversed(additions): + self.insert(position, v) +else: + def _list_store_splice(self, position, n_removals, additions): + self.splice(position, n_removals, additions) + + +class ListStore(Gio.ListStore): + + def sort(self, compare_func, *user_data): + compare_func = wrap_list_store_sort_func(compare_func) + return super(ListStore, self).sort(compare_func, *user_data) + + def insert_sorted(self, item, compare_func, *user_data): + compare_func = wrap_list_store_sort_func(compare_func) + return super(ListStore, self).insert_sorted( + item, compare_func, *user_data) + + def __delitem__(self, key): + if isinstance(key, slice): + start, stop, step = key.indices(len(self)) + if step == 1: + _list_store_splice(self, start, max(stop - start, 0), []) + elif step == -1: + _list_store_splice(self, stop + 1, max(start - stop, 0), []) + else: + for i in sorted(range(start, stop, step), reverse=True): + self.remove(i) + elif isinstance(key, int): + if key < 0: + key += len(self) + if key < 0 or key >= len(self): + raise IndexError + self.remove(key) + else: + raise TypeError + + def __setitem__(self, key, value): + if isinstance(key, slice): + pytype = self.get_item_type().pytype + valuelist = [] + for v in value: + if not isinstance(v, pytype): + raise TypeError( + "Expected type %s.%s" % ( + pytype.__module__, pytype.__name__)) + valuelist.append(v) + + start, stop, step = key.indices(len(self)) + if step == 1: + _list_store_splice( + self, start, max(stop - start, 0), valuelist) + else: + indices = list(range(start, stop, step)) + if len(indices) != len(valuelist): + raise ValueError + + if step == -1: + _list_store_splice( + self, stop + 1, max(start - stop, 0), valuelist[::-1]) + else: + for i, v in zip(indices, valuelist): + _list_store_splice(self, i, 1, [v]) + elif isinstance(key, int): + if key < 0: + key += len(self) + if key < 0 or key >= len(self): + raise IndexError + + pytype = self.get_item_type().pytype + if not isinstance(value, pytype): + raise TypeError( + "Expected type %s.%s" % ( + pytype.__module__, pytype.__name__)) + + _list_store_splice(self, key, 1, [value]) + else: + raise TypeError + + +ListStore = override(ListStore) +__all__.append('ListStore') diff --git a/gi/overrides/Gtk.py b/gi/overrides/Gtk.py index 5899596..f75da7b 100644 --- a/gi/overrides/Gtk.py +++ b/gi/overrides/Gtk.py @@ -19,96 +19,177 @@ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 # USA -import collections import sys +import warnings + from gi.repository import GObject -from ..overrides import override, strip_boolean_result +from .._ossighelper import wakeup_on_signal, register_sigint_fallback +from .._gtktemplate import Template, _extract_handler_and_args +from ..overrides import (override, strip_boolean_result, deprecated_init, + wrap_list_store_sort_func) from ..module import get_introspection_module from gi import PyGIDeprecationWarning -if sys.version_info >= (3, 0): - _basestring = str - _callable = lambda c: hasattr(c, '__call__') -else: - _basestring = basestring - _callable = callable Gtk = get_introspection_module('Gtk') +GTK3 = Gtk._version == '3.0' +GTK4 = Gtk._version == '4.0' __all__ = [] -if Gtk._version == '2.0': - import warnings - warn_msg = "You have imported the Gtk 2.0 module. Because Gtk 2.0 \ -was not designed for use with introspection some of the \ -interfaces and API will fail. As such this is not supported \ -by the pygobject development team and we encourage you to \ -port your app to Gtk 3 or greater. PyGTK is the recomended \ -python module to use with Gtk 2.0" - warnings.warn(warn_msg, RuntimeWarning) +Template = Template +__all__.append('Template') + +# Exposed for unit-testing. +_extract_handler_and_args = _extract_handler_and_args +__all__.append('_extract_handler_and_args') + + +class PyGTKDeprecationWarning(PyGIDeprecationWarning): + pass + + +__all__.append('PyGTKDeprecationWarning') + + +if GTK3: + def _construct_target_list(targets): + """Create a list of TargetEntry items from a list of tuples in the form (target, flags, info) + + The list can also contain existing TargetEntry items in which case the existing entry + is re-used in the return list. + """ + target_entries = [] + for entry in targets: + if not isinstance(entry, Gtk.TargetEntry): + entry = Gtk.TargetEntry.new(*entry) + target_entries.append(entry) + return target_entries + + __all__.append('_construct_target_list') + + +def _builder_connect_callback(builder, gobj, signal_name, handler_name, connect_obj, flags, obj_or_map): + handler, args = _extract_handler_and_args(obj_or_map, handler_name) + + after = flags & GObject.ConnectFlags.AFTER + if connect_obj is not None: + if after: + gobj.connect_object_after(signal_name, handler, connect_obj, *args) + else: + gobj.connect_object(signal_name, handler, connect_obj, *args) + else: + if after: + gobj.connect_after(signal_name, handler, *args) + else: + gobj.connect(signal_name, handler, *args) -def _construct_target_list(targets): - """Create a list of TargetEntry items from a list of tuples in the form (target, flags, info) +class _FreezeNotifyManager(object): + def __init__(self, obj): + self.obj = obj - The list can also contain existing TargetEntry items in which case the existing entry - is re-used in the return list. - """ - target_entries = [] - for entry in targets: - if not isinstance(entry, Gtk.TargetEntry): - entry = Gtk.TargetEntry.new(*entry) - target_entries.append(entry) - return target_entries + def __enter__(self): + pass -__all__.append('_construct_target_list') + def __exit__(self, exc_type, exc_value, traceback): + self.obj.thaw_child_notify() class Widget(Gtk.Widget): translate_coordinates = strip_boolean_result(Gtk.Widget.translate_coordinates) - def render_icon(self, stock_id, size, detail=None): - return super(Widget, self).render_icon(stock_id, size, detail) - - def drag_dest_set_target_list(self, target_list): - if not isinstance(target_list, Gtk.TargetList): - target_list = Gtk.TargetList.new(_construct_target_list(target_list)) - super(Widget, self).drag_dest_set_target_list(target_list) + if GTK4: + def __contains__(self, child): + return child in list(self) + + def __iter__(self): + child = self.get_first_child() + while child: + yield child + child = child.get_next_sibling() + + if GTK3: + def freeze_child_notify(self): + super(Widget, self).freeze_child_notify() + return _FreezeNotifyManager(self) + + if GTK3: + def drag_dest_set_target_list(self, target_list): + if (target_list is not None) and (not isinstance(target_list, Gtk.TargetList)): + target_list = Gtk.TargetList.new(_construct_target_list(target_list)) + super(Widget, self).drag_dest_set_target_list(target_list) + + if GTK3: + def drag_source_set_target_list(self, target_list): + if (target_list is not None) and (not isinstance(target_list, Gtk.TargetList)): + target_list = Gtk.TargetList.new(_construct_target_list(target_list)) + super(Widget, self).drag_source_set_target_list(target_list) + + if GTK3: + def style_get_property(self, property_name, value=None): + if value is None: + prop = self.find_style_property(property_name) + if prop is None: + raise ValueError('Class "%s" does not contain style property "%s"' % + (self, property_name)) + value = GObject.Value(prop.value_type) - def drag_source_set_target_list(self, target_list): - if not isinstance(target_list, Gtk.TargetList): - target_list = Gtk.TargetList.new(_construct_target_list(target_list)) - super(Widget, self).drag_source_set_target_list(target_list) + Gtk.Widget.style_get_property(self, property_name, value) + return value.get_value() Widget = override(Widget) __all__.append('Widget') -class Container(Gtk.Container, Widget): +if GTK3: + class Container(Gtk.Container, Widget): - def __len__(self): - return len(self.get_children()) + def __len__(self): + return len(self.get_children()) - def __contains__(self, child): - return child in self.get_children() + def __contains__(self, child): + return child in self.get_children() - def __iter__(self): - return iter(self.get_children()) + def __iter__(self): + return iter(self.get_children()) - def __bool__(self): - return True + def __bool__(self): + return True + + # alias for Python 2.x object protocol + __nonzero__ = __bool__ + + def child_get_property(self, child, property_name, value=None): + if value is None: + prop = self.find_child_property(property_name) + if prop is None: + raise ValueError('Class "%s" does not contain child property "%s"' % + (self, property_name)) + value = GObject.Value(prop.value_type) + + Gtk.Container.child_get_property(self, child, property_name, value) + return value.get_value() - # alias for Python 2.x object protocol - __nonzero__ = __bool__ + def child_get(self, child, *prop_names): + """Returns a list of child property values for the given names.""" + return [self.child_get_property(child, name) for name in prop_names] - get_focus_chain = strip_boolean_result(Gtk.Container.get_focus_chain) + def child_set(self, child, **kwargs): + """Set a child properties on the given child to key/value pairs.""" + for name, value in kwargs.items(): + name = name.replace('_', '-') + self.child_set_property(child, name, value) + get_focus_chain = strip_boolean_result(Gtk.Container.get_focus_chain) -Container = override(Container) -__all__.append('Container') + Container = override(Container) + __all__.append('Container') +else: + Container = object class Editable(Gtk.Editable): @@ -123,306 +204,288 @@ Editable = override(Editable) __all__.append("Editable") -class Action(Gtk.Action): - def __init__(self, name, label, tooltip, stock_id, **kwds): - Gtk.Action.__init__(self, name=name, label=label, tooltip=tooltip, stock_id=stock_id, **kwds) +if GTK3: + class Action(Gtk.Action): + __init__ = deprecated_init(Gtk.Action.__init__, + arg_names=('name', 'label', 'tooltip', 'stock_id'), + category=PyGTKDeprecationWarning) + + Action = override(Action) + __all__.append("Action") + + class RadioAction(Gtk.RadioAction): + __init__ = deprecated_init(Gtk.RadioAction.__init__, + arg_names=('name', 'label', 'tooltip', 'stock_id', 'value'), + category=PyGTKDeprecationWarning) + + RadioAction = override(RadioAction) + __all__.append("RadioAction") + + class ActionGroup(Gtk.ActionGroup): + __init__ = deprecated_init(Gtk.ActionGroup.__init__, + arg_names=('name',), + category=PyGTKDeprecationWarning) + + def add_actions(self, entries, user_data=None): + """ + The add_actions() method is a convenience method that creates a number + of gtk.Action objects based on the information in the list of action + entry tuples contained in entries and adds them to the action group. + The entry tuples can vary in size from one to six items with the + following information: + + * The name of the action. Must be specified. + * The stock id for the action. Optional with a default value of None + if a label is specified. + * The label for the action. This field should typically be marked + for translation, see the set_translation_domain() method. Optional + with a default value of None if a stock id is specified. + * The accelerator for the action, in the format understood by the + gtk.accelerator_parse() function. Optional with a default value of + None. + * The tooltip for the action. This field should typically be marked + for translation, see the set_translation_domain() method. Optional + with a default value of None. + * The callback function invoked when the action is activated. + Optional with a default value of None. + + The "activate" signals of the actions are connected to the callbacks and + their accel paths are set to <Actions>/group-name/action-name. + """ + try: + iter(entries) + except (TypeError): + raise TypeError('entries must be iterable') + + def _process_action(name, stock_id=None, label=None, accelerator=None, tooltip=None, callback=None): + action = Action(name=name, label=label, tooltip=tooltip, stock_id=stock_id) + if callback is not None: + if user_data is None: + action.connect('activate', callback) + else: + action.connect('activate', callback, user_data) + + self.add_action_with_accel(action, accelerator) + + for e in entries: + # using inner function above since entries can leave out optional arguments + _process_action(*e) + + def add_toggle_actions(self, entries, user_data=None): + """ + The add_toggle_actions() method is a convenience method that creates a + number of gtk.ToggleAction objects based on the information in the list + of action entry tuples contained in entries and adds them to the action + group. The toggle action entry tuples can vary in size from one to seven + items with the following information: + + * The name of the action. Must be specified. + * The stock id for the action. Optional with a default value of None + if a label is specified. + * The label for the action. This field should typically be marked + for translation, see the set_translation_domain() method. Optional + with a default value of None if a stock id is specified. + * The accelerator for the action, in the format understood by the + gtk.accelerator_parse() function. Optional with a default value of + None. + * The tooltip for the action. This field should typically be marked + for translation, see the set_translation_domain() method. Optional + with a default value of None. + * The callback function invoked when the action is activated. + Optional with a default value of None. + * A flag indicating whether the toggle action is active. Optional + with a default value of False. + + The "activate" signals of the actions are connected to the callbacks and + their accel paths are set to <Actions>/group-name/action-name. + """ -Action = override(Action) -__all__.append("Action") + try: + iter(entries) + except (TypeError): + raise TypeError('entries must be iterable') + + def _process_action(name, stock_id=None, label=None, accelerator=None, tooltip=None, callback=None, is_active=False): + action = Gtk.ToggleAction(name=name, label=label, tooltip=tooltip, stock_id=stock_id) + action.set_active(is_active) + if callback is not None: + if user_data is None: + action.connect('activate', callback) + else: + action.connect('activate', callback, user_data) + + self.add_action_with_accel(action, accelerator) + + for e in entries: + # using inner function above since entries can leave out optional arguments + _process_action(*e) + + def add_radio_actions(self, entries, value=None, on_change=None, user_data=None): + """ + The add_radio_actions() method is a convenience method that creates a + number of gtk.RadioAction objects based on the information in the list + of action entry tuples contained in entries and adds them to the action + group. The entry tuples can vary in size from one to six items with the + following information: + + * The name of the action. Must be specified. + * The stock id for the action. Optional with a default value of None + if a label is specified. + * The label for the action. This field should typically be marked + for translation, see the set_translation_domain() method. Optional + with a default value of None if a stock id is specified. + * The accelerator for the action, in the format understood by the + gtk.accelerator_parse() function. Optional with a default value of + None. + * The tooltip for the action. This field should typically be marked + for translation, see the set_translation_domain() method. Optional + with a default value of None. + * The value to set on the radio action. Optional with a default + value of 0. Should be specified in applications. + + The value parameter specifies the radio action that should be set + active. The "changed" signal of the first radio action is connected to + the on_change callback (if specified and not None) and the accel paths + of the actions are set to <Actions>/group-name/action-name. + """ + try: + iter(entries) + except (TypeError): + raise TypeError('entries must be iterable') + first_action = None -class RadioAction(Gtk.RadioAction): - def __init__(self, name, label, tooltip, stock_id, value, **kwds): - Gtk.RadioAction.__init__(self, name=name, label=label, tooltip=tooltip, stock_id=stock_id, value=value, **kwds) + def _process_action(group_source, name, stock_id=None, label=None, accelerator=None, tooltip=None, entry_value=0): + action = RadioAction(name=name, label=label, tooltip=tooltip, stock_id=stock_id, value=entry_value) -RadioAction = override(RadioAction) -__all__.append("RadioAction") + if GTK3: + action.join_group(group_source) + if value == entry_value: + action.set_active(True) -class ActionGroup(Gtk.ActionGroup): - def __init__(self, name, **kwds): - super(ActionGroup, self).__init__(name=name, **kwds) + self.add_action_with_accel(action, accelerator) + return action - def add_actions(self, entries, user_data=None): - """ - The add_actions() method is a convenience method that creates a number - of gtk.Action objects based on the information in the list of action - entry tuples contained in entries and adds them to the action group. - The entry tuples can vary in size from one to six items with the - following information: - - * The name of the action. Must be specified. - * The stock id for the action. Optional with a default value of None - if a label is specified. - * The label for the action. This field should typically be marked - for translation, see the set_translation_domain() method. Optional - with a default value of None if a stock id is specified. - * The accelerator for the action, in the format understood by the - gtk.accelerator_parse() function. Optional with a default value of - None. - * The tooltip for the action. This field should typically be marked - for translation, see the set_translation_domain() method. Optional - with a default value of None. - * The callback function invoked when the action is activated. - Optional with a default value of None. - - The "activate" signals of the actions are connected to the callbacks and - their accel paths are set to <Actions>/group-name/action-name. - """ - try: - iter(entries) - except (TypeError): - raise TypeError('entries must be iterable') + for e in entries: + # using inner function above since entries can leave out optional arguments + action = _process_action(first_action, *e) + if first_action is None: + first_action = action - def _process_action(name, stock_id=None, label=None, accelerator=None, tooltip=None, callback=None): - action = Action(name, label, tooltip, stock_id) - if callback is not None: + if first_action is not None and on_change is not None: if user_data is None: - action.connect('activate', callback) + first_action.connect('changed', on_change) else: - action.connect('activate', callback, user_data) + first_action.connect('changed', on_change, user_data) - self.add_action_with_accel(action, accelerator) + ActionGroup = override(ActionGroup) + __all__.append('ActionGroup') - for e in entries: - # using inner function above since entries can leave out optional arguments - _process_action(*e) + class UIManager(Gtk.UIManager): + def add_ui_from_string(self, buffer): + if not isinstance(buffer, str): + raise TypeError('buffer must be a string') - def add_toggle_actions(self, entries, user_data=None): - """ - The add_toggle_actions() method is a convenience method that creates a - number of gtk.ToggleAction objects based on the information in the list - of action entry tuples contained in entries and adds them to the action - group. The toggle action entry tuples can vary in size from one to seven - items with the following information: - - * The name of the action. Must be specified. - * The stock id for the action. Optional with a default value of None - if a label is specified. - * The label for the action. This field should typically be marked - for translation, see the set_translation_domain() method. Optional - with a default value of None if a stock id is specified. - * The accelerator for the action, in the format understood by the - gtk.accelerator_parse() function. Optional with a default value of - None. - * The tooltip for the action. This field should typically be marked - for translation, see the set_translation_domain() method. Optional - with a default value of None. - * The callback function invoked when the action is activated. - Optional with a default value of None. - * A flag indicating whether the toggle action is active. Optional - with a default value of False. - - The "activate" signals of the actions are connected to the callbacks and - their accel paths are set to <Actions>/group-name/action-name. - """ + length = _get_utf8_length(buffer) - try: - iter(entries) - except (TypeError): - raise TypeError('entries must be iterable') - - def _process_action(name, stock_id=None, label=None, accelerator=None, tooltip=None, callback=None, is_active=False): - action = Gtk.ToggleAction(name, label, tooltip, stock_id) - action.set_active(is_active) - if callback is not None: - if user_data is None: - action.connect('activate', callback) - else: - action.connect('activate', callback, user_data) + return Gtk.UIManager.add_ui_from_string(self, buffer, length) - self.add_action_with_accel(action, accelerator) + def insert_action_group(self, buffer, length=-1): + return Gtk.UIManager.insert_action_group(self, buffer, length) - for e in entries: - # using inner function above since entries can leave out optional arguments - _process_action(*e) - - def add_radio_actions(self, entries, value=None, on_change=None, user_data=None): - """ - The add_radio_actions() method is a convenience method that creates a - number of gtk.RadioAction objects based on the information in the list - of action entry tuples contained in entries and adds them to the action - group. The entry tuples can vary in size from one to six items with the - following information: - - * The name of the action. Must be specified. - * The stock id for the action. Optional with a default value of None - if a label is specified. - * The label for the action. This field should typically be marked - for translation, see the set_translation_domain() method. Optional - with a default value of None if a stock id is specified. - * The accelerator for the action, in the format understood by the - gtk.accelerator_parse() function. Optional with a default value of - None. - * The tooltip for the action. This field should typically be marked - for translation, see the set_translation_domain() method. Optional - with a default value of None. - * The value to set on the radio action. Optional with a default - value of 0. Should be specified in applications. - - The value parameter specifies the radio action that should be set - active. The "changed" signal of the first radio action is connected to - the on_change callback (if specified and not None) and the accel paths - of the actions are set to <Actions>/group-name/action-name. - """ - try: - iter(entries) - except (TypeError): - raise TypeError('entries must be iterable') - - first_action = None - - def _process_action(group_source, name, stock_id=None, label=None, accelerator=None, tooltip=None, entry_value=0): - action = RadioAction(name, label, tooltip, stock_id, entry_value) - - # FIXME: join_group is a patch to Gtk+ 3.0 - # otherwise we can't effectively add radio actions to a - # group. Should we depend on 3.0 and error out here - # or should we offer the functionality via a compat - # C module? - if hasattr(action, 'join_group'): - action.join_group(group_source) - - if value == entry_value: - action.set_active(True) - - self.add_action_with_accel(action, accelerator) - return action - - for e in entries: - # using inner function above since entries can leave out optional arguments - action = _process_action(first_action, *e) - if first_action is None: - first_action = action - - if first_action is not None and on_change is not None: - if user_data is None: - first_action.connect('changed', on_change) - else: - first_action.connect('changed', on_change, user_data) - -ActionGroup = override(ActionGroup) -__all__.append('ActionGroup') - - -class UIManager(Gtk.UIManager): - def add_ui_from_string(self, buffer): - if not isinstance(buffer, _basestring): - raise TypeError('buffer must be a string') - - length = len(buffer.encode('UTF-8')) - - return Gtk.UIManager.add_ui_from_string(self, buffer, length) - - def insert_action_group(self, buffer, length=-1): - return Gtk.UIManager.insert_action_group(self, buffer, length) - -UIManager = override(UIManager) -__all__.append('UIManager') + UIManager = override(UIManager) + __all__.append('UIManager') class ComboBox(Gtk.ComboBox, Container): get_active_iter = strip_boolean_result(Gtk.ComboBox.get_active_iter) + ComboBox = override(ComboBox) __all__.append('ComboBox') -class Box(Gtk.Box): - def __init__(self, homogeneous=False, spacing=0, **kwds): - super(Box, self).__init__(**kwds) - self.set_homogeneous(homogeneous) - self.set_spacing(spacing) +if GTK3: + class Box(Gtk.Box): + __init__ = deprecated_init(Gtk.Box.__init__, + arg_names=('homogeneous', 'spacing'), + category=PyGTKDeprecationWarning) -Box = override(Box) -__all__.append('Box') + Box = override(Box) + __all__.append('Box') -class SizeGroup(Gtk.SizeGroup): - def __init__(self, mode=Gtk.SizeGroupMode.VERTICAL): - super(SizeGroup, self).__init__(mode=mode) +if GTK3: + class SizeGroup(Gtk.SizeGroup): + __init__ = deprecated_init(Gtk.SizeGroup.__init__, + arg_names=('mode',), + deprecated_defaults={'mode': Gtk.SizeGroupMode.VERTICAL}, + category=PyGTKDeprecationWarning) -SizeGroup = override(SizeGroup) -__all__.append('SizeGroup') + SizeGroup = override(SizeGroup) + __all__.append('SizeGroup') -class MenuItem(Gtk.MenuItem): - def __init__(self, label=None, **kwds): - if label: - super(MenuItem, self).__init__(label=label, **kwds) - else: - super(MenuItem, self).__init__(**kwds) - -MenuItem = override(MenuItem) -__all__.append('MenuItem') +if GTK3: + class MenuItem(Gtk.MenuItem): + __init__ = deprecated_init(Gtk.MenuItem.__init__, + arg_names=('label',), + category=PyGTKDeprecationWarning) + MenuItem = override(MenuItem) + __all__.append('MenuItem') -class Builder(Gtk.Builder): - @staticmethod - def _extract_handler_and_args(obj_or_map, handler_name): - handler = None - if isinstance(obj_or_map, collections.Mapping): - handler = obj_or_map.get(handler_name, None) - else: - handler = getattr(obj_or_map, handler_name, None) - if handler is None: - raise AttributeError('Handler %s not found' % handler_name) +def _get_utf8_length(string): + assert isinstance(string, str) + if not isinstance(string, bytes): + string = string.encode("utf-8") + return len(string) - args = () - if isinstance(handler, collections.Sequence): - if len(handler) == 0: - raise TypeError("Handler %s tuple can not be empty" % handler) - args = handler[1:] - handler = handler[0] - elif not _callable(handler): - raise TypeError('Handler %s is not a method, function or tuple' % handler) +class Builder(Gtk.Builder): + if GTK4: + from .._gtktemplate import define_builder_scope + BuilderScope = define_builder_scope() - return handler, args + def __init__(self, scope_object_or_map=None): + super(Builder, self).__init__() + if scope_object_or_map: + self.set_scope(Builder.BuilderScope(scope_object_or_map)) - def connect_signals(self, obj_or_map): - """Connect signals specified by this builder to a name, handler mapping. + else: + def connect_signals(self, obj_or_map): + """Connect signals specified by this builder to a name, handler mapping. - Connect signal, name, and handler sets specified in the builder with - the given mapping "obj_or_map". The handler/value aspect of the mapping - can also contain a tuple in the form of (handler [,arg1 [,argN]]) - allowing for extra arguments to be passed to the handler. For example: - builder.connect_signals({'on_clicked': (on_clicked, arg1, arg2)}) - """ - def _full_callback(builder, gobj, signal_name, handler_name, connect_obj, flags, obj_or_map): - handler, args = self._extract_handler_and_args(obj_or_map, handler_name) + Connect signal, name, and handler sets specified in the builder with + the given mapping "obj_or_map". The handler/value aspect of the mapping + can also contain a tuple in the form of (handler [,arg1 [,argN]]) + allowing for extra arguments to be passed to the handler. For example: - after = flags & GObject.ConnectFlags.AFTER - if connect_obj is not None: - if after: - gobj.connect_object_after(signal_name, handler, connect_obj, *args) - else: - gobj.connect_object(signal_name, handler, connect_obj, *args) - else: - if after: - gobj.connect_after(signal_name, handler, *args) - else: - gobj.connect(signal_name, handler, *args) + .. code-block:: python - self.connect_signals_full(_full_callback, obj_or_map) + builder.connect_signals({'on_clicked': (on_clicked, arg1, arg2)}) + """ + self.connect_signals_full(_builder_connect_callback, obj_or_map) def add_from_string(self, buffer): - if not isinstance(buffer, _basestring): + if not isinstance(buffer, str): raise TypeError('buffer must be a string') - length = len(buffer) + length = _get_utf8_length(buffer) return Gtk.Builder.add_from_string(self, buffer, length) def add_objects_from_string(self, buffer, object_ids): - if not isinstance(buffer, _basestring): + if not isinstance(buffer, str): raise TypeError('buffer must be a string') - length = len(buffer) + length = _get_utf8_length(buffer) return Gtk.Builder.add_objects_from_string(self, buffer, length, object_ids) + Builder = override(Builder) __all__.append('Builder') @@ -430,61 +493,88 @@ __all__.append('Builder') # NOTE: This must come before any other Window/Dialog subclassing, to ensure # that we have a correct inheritance hierarchy. +if GTK4: + _window_init = Gtk.Window.__init__ +else: + _window_init = deprecated_init(Gtk.Window.__init__, + arg_names=('type',), + category=PyGTKDeprecationWarning, + stacklevel=3) + class Window(Gtk.Window): - def __init__(self, type=Gtk.WindowType.TOPLEVEL, **kwds): + def __init__(self, *args, **kwargs): if not initialized: - raise RuntimeError("Gtk couldn't be initialized") + raise RuntimeError( + "Gtk couldn't be initialized. " + "Use Gtk.init_check() if you want to handle this case.") + _window_init(self, *args, **kwargs) - # type is a construct-only property; if it is already set (e. g. by - # GtkBuilder), do not try to set it again and just ignore it - try: - self.get_property('type') - Gtk.Window.__init__(self, **kwds) - except TypeError: - Gtk.Window.__init__(self, type=type, **kwds) Window = override(Window) __all__.append('Window') class Dialog(Gtk.Dialog, Container): + if GTK3: + _old_arg_names = ('title', 'parent', 'flags', 'buttons', '_buttons_property') + _init = deprecated_init(Gtk.Dialog.__init__, + arg_names=('title', 'transient_for', 'flags', + 'add_buttons', 'buttons'), + ignore=('flags', 'add_buttons'), + deprecated_aliases={'transient_for': 'parent', + 'buttons': '_buttons_property'}, + category=PyGTKDeprecationWarning) + + def __init__(self, *args, **kwargs): + + new_kwargs = kwargs.copy() + old_kwargs = dict(zip(self._old_arg_names, args)) + old_kwargs.update(kwargs) + + # Increment the warning stacklevel for sub-classes which implement their own __init__. + stacklevel = 2 + if self.__class__ != Dialog and self.__class__.__init__ != Dialog.__init__: + stacklevel += 1 + + # buttons was overloaded by PyGtk but is needed for Gtk.MessageDialog + # as a pass through, so type check the argument and give a deprecation + # when it is not of type Gtk.ButtonsType + add_buttons = old_kwargs.get('buttons', None) + if add_buttons is not None and not isinstance(add_buttons, Gtk.ButtonsType): + warnings.warn('The "buttons" argument must be a Gtk.ButtonsType enum value. ' + 'Please use the "add_buttons" method for adding buttons. ' + 'See: https://wiki.gnome.org/PyGObject/InitializerDeprecations', + PyGTKDeprecationWarning, stacklevel=stacklevel) + new_kwargs.pop('buttons', None) + else: + add_buttons = None + + flags = old_kwargs.get('flags', 0) + if flags: + warnings.warn('The "flags" argument for dialog construction is deprecated. ' + 'Please use initializer keywords: modal=True and/or destroy_with_parent=True. ' + 'See: https://wiki.gnome.org/PyGObject/InitializerDeprecations', + PyGTKDeprecationWarning, stacklevel=stacklevel) + + if flags & Gtk.DialogFlags.MODAL: + new_kwargs['modal'] = True + + if flags & Gtk.DialogFlags.DESTROY_WITH_PARENT: + new_kwargs['destroy_with_parent'] = True + + self._init(*args, **new_kwargs) - def __init__(self, - title=None, - parent=None, - flags=0, - buttons=None, - _buttons_property=None, - **kwds): - - # buttons is overloaded by PyGtk so we have to do the same here - # this breaks some subclasses of Dialog so add a _buttons_property - # keyword to work around this - if _buttons_property is not None: - kwds['buttons'] = _buttons_property - - Gtk.Dialog.__init__(self, **kwds) - if title: - self.set_title(title) - if parent: - self.set_transient_for(parent) - if flags & Gtk.DialogFlags.MODAL: - self.set_modal(True) - if flags & Gtk.DialogFlags.DESTROY_WITH_PARENT: - self.set_destroy_with_parent(True) - - # NO_SEPARATOR has been removed from Gtk 3 - if hasattr(Gtk.DialogFlags, "NO_SEPARATOR") and (flags & Gtk.DialogFlags.NO_SEPARATOR): - self.set_has_separator(False) - import warnings - warnings.warn("Gtk.DialogFlags.NO_SEPARATOR has been depricated since Gtk+-3.0", PyGIDeprecationWarning) - - if buttons is not None: - self.add_buttons(*buttons) - - action_area = property(lambda dialog: dialog.get_action_area()) - vbox = property(lambda dialog: dialog.get_content_area()) + if add_buttons: + self.add_buttons(*add_buttons) + + def run(self, *args, **kwargs): + with register_sigint_fallback(self.destroy): + with wakeup_on_signal(): + return Gtk.Dialog.run(self, *args, **kwargs) + + action_area = property(lambda dialog: dialog.get_action_area()) + vbox = property(lambda dialog: dialog.get_content_area()) def add_buttons(self, *args): """ @@ -494,148 +584,120 @@ class Dialog(Gtk.Dialog, Container): pairs - button text (or stock ID) and a response ID integer are passed individually. For example: - dialog.add_buttons(Gtk.STOCK_OPEN, 42, "Close", Gtk.ResponseType.CLOSE) + .. code-block:: python + + dialog.add_buttons(Gtk.STOCK_OPEN, 42, "Close", Gtk.ResponseType.CLOSE) will add "Open" and "Close" buttons to dialog. """ def _button(b): while b: - t, r = b[0:2] + try: + t, r = b[0:2] + except ValueError: + raise ValueError('Must pass an even number of arguments') b = b[2:] yield t, r - try: - for text, response in _button(args): - self.add_button(text, response) - except (IndexError): - raise TypeError('Must pass an even number of arguments') + for text, response in _button(args): + self.add_button(text, response) + Dialog = override(Dialog) __all__.append('Dialog') -class MessageDialog(Gtk.MessageDialog, Dialog): - def __init__(self, - parent=None, - flags=0, - message_type=Gtk.MessageType.INFO, - buttons=Gtk.ButtonsType.NONE, - message_format=None, - **kwds): +if GTK3: + class MessageDialog(Gtk.MessageDialog, Dialog): + __init__ = deprecated_init(Gtk.MessageDialog.__init__, + arg_names=('parent', 'flags', 'message_type', + 'buttons', 'message_format'), + deprecated_aliases={'text': 'message_format', + 'message_type': 'type'}, + category=PyGTKDeprecationWarning) - if message_format: - kwds['text'] = message_format + def format_secondary_text(self, message_format): + self.set_property('secondary-use-markup', False) + self.set_property('secondary-text', message_format) - # type keyword is used for backwards compat with PyGTK - if 'type' in kwds: - import warnings - warnings.warn("The use of the keyword type as a parameter of the Gtk.MessageDialog constructor has been depricated. Please use message_type instead.", PyGIDeprecationWarning) - message_type = kwds.pop('type') + def format_secondary_markup(self, message_format): + self.set_property('secondary-use-markup', True) + self.set_property('secondary-text', message_format) - Gtk.MessageDialog.__init__(self, - _buttons_property=buttons, - message_type=message_type, - parent=parent, - flags=flags, - **kwds) + MessageDialog = override(MessageDialog) + __all__.append('MessageDialog') - def format_secondary_text(self, message_format): - self.set_property('secondary-use-markup', False) - self.set_property('secondary-text', message_format) - def format_secondary_markup(self, message_format): - self.set_property('secondary-use-markup', True) - self.set_property('secondary-text', message_format) +if GTK3: + class ColorSelectionDialog(Gtk.ColorSelectionDialog): + __init__ = deprecated_init(Gtk.ColorSelectionDialog.__init__, + arg_names=('title',), + category=PyGTKDeprecationWarning) -MessageDialog = override(MessageDialog) -__all__.append('MessageDialog') + ColorSelectionDialog = override(ColorSelectionDialog) + __all__.append('ColorSelectionDialog') + class FileChooserDialog(Gtk.FileChooserDialog): + __init__ = deprecated_init(Gtk.FileChooserDialog.__init__, + arg_names=('title', 'parent', 'action', 'buttons'), + category=PyGTKDeprecationWarning) -class AboutDialog(Gtk.AboutDialog): - def __init__(self, **kwds): - Gtk.AboutDialog.__init__(self, **kwds) + FileChooserDialog = override(FileChooserDialog) + __all__.append('FileChooserDialog') -AboutDialog = override(AboutDialog) -__all__.append('AboutDialog') +if GTK3: + class FontSelectionDialog(Gtk.FontSelectionDialog): + __init__ = deprecated_init(Gtk.FontSelectionDialog.__init__, + arg_names=('title',), + category=PyGTKDeprecationWarning) -class ColorSelectionDialog(Gtk.ColorSelectionDialog): - def __init__(self, title=None, **kwds): - Gtk.ColorSelectionDialog.__init__(self, title=title, **kwds) + FontSelectionDialog = override(FontSelectionDialog) + __all__.append('FontSelectionDialog') -ColorSelectionDialog = override(ColorSelectionDialog) -__all__.append('ColorSelectionDialog') +if GTK3: + class RecentChooserDialog(Gtk.RecentChooserDialog): + # Note, the "manager" keyword must work across the entire 3.x series because + # "recent_manager" is not backwards compatible with PyGObject versions prior to 3.10. + __init__ = deprecated_init(Gtk.RecentChooserDialog.__init__, + arg_names=('title', 'parent', 'recent_manager', 'buttons'), + deprecated_aliases={'recent_manager': 'manager'}, + category=PyGTKDeprecationWarning) -class FileChooserDialog(Gtk.FileChooserDialog): - def __init__(self, - title=None, - parent=None, - action=Gtk.FileChooserAction.OPEN, - buttons=None, - **kwds): - Gtk.FileChooserDialog.__init__(self, - action=action, - title=title, - parent=parent, - buttons=buttons, - **kwds) -FileChooserDialog = override(FileChooserDialog) -__all__.append('FileChooserDialog') - - -class FontSelectionDialog(Gtk.FontSelectionDialog): - def __init__(self, title=None, **kwds): - Gtk.FontSelectionDialog.__init__(self, title=title, **kwds) - -FontSelectionDialog = override(FontSelectionDialog) -__all__.append('FontSelectionDialog') - - -class RecentChooserDialog(Gtk.RecentChooserDialog): - def __init__(self, - title=None, - parent=None, - manager=None, - buttons=None, - **kwds): - - Gtk.RecentChooserDialog.__init__(self, - recent_manager=manager, - title=title, - parent=parent, - buttons=buttons, - **kwds) - -RecentChooserDialog = override(RecentChooserDialog) -__all__.append('RecentChooserDialog') + RecentChooserDialog = override(RecentChooserDialog) + __all__.append('RecentChooserDialog') class IconView(Gtk.IconView): - - def __init__(self, model=None, **kwds): - Gtk.IconView.__init__(self, model=model, **kwds) + if GTK3: + __init__ = deprecated_init(Gtk.IconView.__init__, + arg_names=('model',), + category=PyGTKDeprecationWarning) get_item_at_pos = strip_boolean_result(Gtk.IconView.get_item_at_pos) get_visible_range = strip_boolean_result(Gtk.IconView.get_visible_range) get_dest_item_at_pos = strip_boolean_result(Gtk.IconView.get_dest_item_at_pos) + IconView = override(IconView) __all__.append('IconView') -class ToolButton(Gtk.ToolButton): - - def __init__(self, stock_id=None, **kwds): - Gtk.ToolButton.__init__(self, stock_id=stock_id, **kwds) +if GTK3: + class ToolButton(Gtk.ToolButton): + __init__ = deprecated_init(Gtk.ToolButton.__init__, + arg_names=('stock_id',), + category=PyGTKDeprecationWarning) -ToolButton = override(ToolButton) -__all__.append('ToolButton') + ToolButton = override(ToolButton) + __all__.append('ToolButton') class IMContext(Gtk.IMContext): get_surrounding = strip_boolean_result(Gtk.IMContext.get_surrounding) + IMContext = override(IMContext) __all__.append('IMContext') @@ -643,42 +705,39 @@ __all__.append('IMContext') class RecentInfo(Gtk.RecentInfo): get_application_info = strip_boolean_result(Gtk.RecentInfo.get_application_info) + RecentInfo = override(RecentInfo) __all__.append('RecentInfo') class TextBuffer(Gtk.TextBuffer): - def _get_or_create_tag_table(self): - table = self.get_tag_table() - if table is None: - table = Gtk.TextTagTable() - self.set_tag_table(table) - - return table def create_tag(self, tag_name=None, **properties): - """ - @tag_name: name of the new tag, or None - @properties: keyword list of properties and their values + """Creates a tag and adds it to the tag table of the TextBuffer. + + :param str tag_name: + Name of the new tag, or None + :param **properties: + Keyword list of properties and their values - Creates a tag and adds it to the tag table of the TextBuffer. - Equivalent to creating a Gtk.TextTag and then adding the + This is equivalent to creating a Gtk.TextTag and then adding the tag to the buffer's tag table. The returned tag is owned by the buffer's tag table. - If @tag_name is None, the tag is anonymous. + If ``tag_name`` is None, the tag is anonymous. - If @tag_name is not None, a tag called @tag_name must not already + If ``tag_name`` is not None, a tag called ``tag_name`` must not already exist in the tag table for this buffer. Properties are passed as a keyword list of names and values (e.g. - foreground = 'DodgerBlue', weight = Pango.Weight.BOLD) + foreground='DodgerBlue', weight=Pango.Weight.BOLD) - Return value: a new tag + :returns: + A new tag. """ tag = Gtk.TextTag(name=tag_name, **properties) - self._get_or_create_tag_table().add(tag) + self.get_tag_table().add(tag) return tag def create_mark(self, mark_name, where, left_gravity=False): @@ -688,7 +747,7 @@ class TextBuffer(Gtk.TextBuffer): Gtk.TextBuffer.set_text(self, text, length) def insert(self, iter, text, length=-1): - if not isinstance(text, _basestring): + if not isinstance(text, str): raise TypeError('text must be a string, not %s' % type(text)) Gtk.TextBuffer.insert(self, iter, text, length) @@ -706,9 +765,6 @@ class TextBuffer(Gtk.TextBuffer): self.apply_tag(tag, start, iter) def insert_with_tags_by_name(self, iter, text, *tags): - if not tags: - return - tag_objs = [] for tag in tags: @@ -720,30 +776,22 @@ class TextBuffer(Gtk.TextBuffer): self.insert_with_tags(iter, text, *tag_objs) def insert_at_cursor(self, text, length=-1): - if not isinstance(text, _basestring): + if not isinstance(text, str): raise TypeError('text must be a string, not %s' % type(text)) Gtk.TextBuffer.insert_at_cursor(self, text, length) get_selection_bounds = strip_boolean_result(Gtk.TextBuffer.get_selection_bounds, fail_ret=()) + TextBuffer = override(TextBuffer) __all__.append('TextBuffer') class TextIter(Gtk.TextIter): - forward_search = strip_boolean_result(Gtk.TextIter.forward_search) backward_search = strip_boolean_result(Gtk.TextIter.backward_search) - def begins_tag(self, tag=None): - return super(TextIter, self).begins_tag(tag) - - def ends_tag(self, tag=None): - return super(TextIter, self).ends_tag(tag) - - def toggles_tag(self, tag=None): - return super(TextIter, self).toggles_tag(tag) TextIter = override(TextIter) __all__.append('TextIter') @@ -756,8 +804,9 @@ class TreeModel(Gtk.TreeModel): def __bool__(self): return True - # alias for Python 2.x object protocol - __nonzero__ = __bool__ + if GTK3: + # alias for Python 2.x object protocol + __nonzero__ = __bool__ def _getiter(self, key): if isinstance(key, Gtk.TreeIter): @@ -766,11 +815,7 @@ class TreeModel(Gtk.TreeModel): index = len(self) + key if index < 0: raise IndexError("row index is out of bounds: %d" % key) - try: - aiter = self.get_iter(index) - except ValueError: - raise IndexError("could not find tree path '%s'" % key) - return aiter + return self.get_iter(index) else: try: aiter = self.get_iter(key) @@ -778,6 +823,13 @@ class TreeModel(Gtk.TreeModel): raise IndexError("could not find tree path '%s'" % key) return aiter + def sort_new_with_model(self): + super_object = super(TreeModel, self) + if hasattr(super_object, "sort_new_with_model"): + return super_object.sort_new_with_model() + else: + return TreeModelSort.new_with_model(self) + def _coerce_path(self, path): if isinstance(path, Gtk.TreePath): return path @@ -848,11 +900,7 @@ class TreeModel(Gtk.TreeModel): def set_row(self, treeiter, row): converted_row, columns = self._convert_row(row) for column in columns: - value = row[column] - if value is None: - continue # None means skip this row - - self.set_value(treeiter, column, value) + self.set_value(treeiter, column, row[column]) def _convert_value(self, column, value): '''Convert value to a GObject.Value of the expected type''' @@ -876,9 +924,6 @@ class TreeModel(Gtk.TreeModel): return tuple(values) - def filter_new(self, root=None): - return super(TreeModel, self).filter_new(root) - # # Signals supporting python iterables as tree paths # @@ -914,16 +959,24 @@ class TreeSortable(Gtk.TreeSortable, ): def set_default_sort_func(self, sort_func, user_data=None): super(TreeSortable, self).set_default_sort_func(sort_func, user_data) + TreeSortable = override(TreeSortable) __all__.append('TreeSortable') -class TreeModelSort(Gtk.TreeModelSort): - def __init__(self, model, **kwds): - Gtk.TreeModelSort.__init__(self, model=model, **kwds) +if GTK3: + class TreeModelSort(Gtk.TreeModelSort): + __init__ = deprecated_init(Gtk.TreeModelSort.__init__, + arg_names=('model',), + category=PyGTKDeprecationWarning) -TreeModelSort = override(TreeModelSort) -__all__.append('TreeModelSort') + if not hasattr(Gtk.TreeModelSort, "new_with_model"): + @classmethod + def new_with_model(self, child_model): + return TreeModel.sort_new_with_model(child_model) + + TreeModelSort = override(TreeModelSort) + __all__.append('TreeModelSort') class ListStore(Gtk.ListStore, TreeModel, TreeSortable): @@ -931,10 +984,17 @@ class ListStore(Gtk.ListStore, TreeModel, TreeSortable): Gtk.ListStore.__init__(self) self.set_column_types(column_types) + # insert_with_valuesv got renamed to insert_with_values with 4.1.0 + # https://gitlab.gnome.org/GNOME/gtk/-/commit/a1216599ff6b39bca3e9 + if not hasattr(Gtk.ListStore, "insert_with_valuesv"): + insert_with_valuesv = Gtk.ListStore.insert_with_values + elif not hasattr(Gtk.ListStore, "insert_with_values"): + insert_with_values = Gtk.ListStore.insert_with_valuesv + def _do_insert(self, position, row): if row is not None: row, columns = self._convert_row(row) - treeiter = self.insert_with_valuesv(position, columns, row) + treeiter = self.insert_with_values(position, columns, row) else: treeiter = Gtk.ListStore.insert(self, position) @@ -954,58 +1014,59 @@ class ListStore(Gtk.ListStore, TreeModel, TreeSortable): def insert(self, position, row=None): return self._do_insert(position, row) - # FIXME: sends two signals; check if this can use an atomic - # insert_with_valuesv() - def insert_before(self, sibling, row=None): - treeiter = Gtk.ListStore.insert_before(self, sibling) - if row is not None: - self.set_row(treeiter, row) - - return treeiter + if sibling is None: + position = -1 + else: + position = self.get_path(sibling).get_indices()[-1] + return self._do_insert(position, row) - # FIXME: sends two signals; check if this can use an atomic - # insert_with_valuesv() + return Gtk.ListStore.insert_before(self, sibling) def insert_after(self, sibling, row=None): - treeiter = Gtk.ListStore.insert_after(self, sibling) - if row is not None: - self.set_row(treeiter, row) + if sibling is None: + position = 0 + else: + position = self.get_path(sibling).get_indices()[-1] + 1 + return self._do_insert(position, row) - return treeiter + return Gtk.ListStore.insert_after(self, sibling) def set_value(self, treeiter, column, value): value = self._convert_value(column, value) Gtk.ListStore.set_value(self, treeiter, column, value) def set(self, treeiter, *args): - - def _set_lists(columns, values): - if len(columns) != len(values): + def _set_lists(cols, vals): + if len(cols) != len(vals): raise TypeError('The number of columns do not match the number of values') - for col_num, val in zip(columns, values): + + columns = [] + values = [] + for col_num, value in zip(cols, vals): if not isinstance(col_num, int): raise TypeError('TypeError: Expected integer argument for column.') - self.set_value(treeiter, col_num, val) + + columns.append(col_num) + values.append(self._convert_value(col_num, value)) + + Gtk.ListStore.set(self, treeiter, columns, values) if args: if isinstance(args[0], int): - columns = args[::2] - values = args[1::2] - _set_lists(columns, values) + _set_lists(args[::2], args[1::2]) elif isinstance(args[0], (tuple, list)): if len(args) != 2: raise TypeError('Too many arguments') _set_lists(args[0], args[1]) elif isinstance(args[0], dict): - columns = args[0].keys() - values = args[0].values() - _set_lists(columns, values) + _set_lists(list(args[0]), args[0].values()) else: raise TypeError('Argument list must be in the form of (column, value, ...), ((columns,...), (values, ...)) or {column: value}. No -1 termination is needed.') + ListStore = override(ListStore) __all__.append('ListStore') @@ -1021,8 +1082,8 @@ class TreeModelRow(object): elif isinstance(iter_or_path, Gtk.TreeIter): self.iter = iter_or_path else: - raise TypeError("expected Gtk.TreeIter or Gtk.TreePath, \ - %s found" % type(iter_or_path).__name__) + raise TypeError("expected Gtk.TreeIter or Gtk.TreePath, " + "%s found" % type(iter_or_path).__name__) @property def path(self): @@ -1068,8 +1129,11 @@ class TreeModelRow(object): for i in range(start, stop, step): alist.append(self.model.get_value(self.iter, i)) return alist + elif isinstance(key, tuple): + return [self[k] for k in key] else: - raise TypeError("indices must be integers, not %s" % type(key).__name__) + raise TypeError("indices must be integers, slice or tuple, not %s" + % type(key).__name__) def __setitem__(self, key, value): if isinstance(key, int): @@ -1088,8 +1152,16 @@ class TreeModelRow(object): for i, v in enumerate(indexList): self.model.set_value(self.iter, v, value[i]) + elif isinstance(key, tuple): + if len(key) != len(value): + raise ValueError( + "attempt to assign sequence of size %d to sequence of size %d" + % (len(value), len(key))) + for k, v in zip(key, value): + self[k] = v else: - raise TypeError("index must be an integer or slice, not %s" % type(key).__name__) + raise TypeError("indices must be an integer, slice or tuple, not %s" + % type(key).__name__) def _convert_negative_index(self, index): new_index = self.model.get_n_columns() + index @@ -1101,6 +1173,7 @@ class TreeModelRow(object): child_iter = self.model.iter_children(self.iter) return TreeModelRowIter(self.model, child_iter) + __all__.append('TreeModelRow') @@ -1117,12 +1190,14 @@ class TreeModelRowIter(object): self.iter = self.model.iter_next(self.iter) return row - # alias for Python 2.x object protocol - next = __next__ + if GTK3: + # alias for Python 2.x object protocol + next = __next__ def __iter__(self): return self + __all__.append('TreeModelRowIter') @@ -1131,7 +1206,7 @@ class TreePath(Gtk.TreePath): def __new__(cls, path=0): if isinstance(path, int): path = str(path) - elif not isinstance(path, _basestring): + elif not isinstance(path, str): path = ":".join(str(val) for val in path) if len(path) == 0: @@ -1141,17 +1216,20 @@ class TreePath(Gtk.TreePath): except TypeError: raise TypeError("could not parse subscript '%s' as a tree path" % path) + def __init__(self, *args, **kwargs): + super(TreePath, self).__init__() + def __str__(self): - return self.to_string() + return self.to_string() or "" def __lt__(self, other): - return not other is None and self.compare(other) < 0 + return other is not None and self.compare(other) < 0 def __le__(self, other): - return not other is None and self.compare(other) <= 0 + return other is not None and self.compare(other) <= 0 def __eq__(self, other): - return not other is None and self.compare(other) == 0 + return other is not None and self.compare(other) == 0 def __ne__(self, other): return other is None or self.compare(other) != 0 @@ -1171,12 +1249,12 @@ class TreePath(Gtk.TreePath): def __getitem__(self, index): return self.get_indices()[index] + TreePath = override(TreePath) __all__.append('TreePath') class TreeStore(Gtk.TreeStore, TreeModel, TreeSortable): - def __init__(self, *column_types): Gtk.TreeStore.__init__(self) self.set_column_types(column_types) @@ -1199,83 +1277,89 @@ class TreeStore(Gtk.TreeStore, TreeModel, TreeSortable): def insert(self, parent, position, row=None): return self._do_insert(parent, position, row) - # FIXME: sends two signals; check if this can use an atomic - # insert_with_valuesv() - def insert_before(self, parent, sibling, row=None): - treeiter = Gtk.TreeStore.insert_before(self, parent, sibling) - if row is not None: - self.set_row(treeiter, row) - - return treeiter + if sibling is None: + position = -1 + else: + if parent is None: + parent = self.iter_parent(sibling) + position = self.get_path(sibling).get_indices()[-1] + return self._do_insert(parent, position, row) - # FIXME: sends two signals; check if this can use an atomic - # insert_with_valuesv() + return Gtk.TreeStore.insert_before(self, parent, sibling) def insert_after(self, parent, sibling, row=None): - treeiter = Gtk.TreeStore.insert_after(self, parent, sibling) - if row is not None: - self.set_row(treeiter, row) + if sibling is None: + position = 0 + else: + if parent is None: + parent = self.iter_parent(sibling) + position = self.get_path(sibling).get_indices()[-1] + 1 + return self._do_insert(parent, position, row) - return treeiter + return Gtk.TreeStore.insert_after(self, parent, sibling) def set_value(self, treeiter, column, value): value = self._convert_value(column, value) Gtk.TreeStore.set_value(self, treeiter, column, value) def set(self, treeiter, *args): - - def _set_lists(columns, values): - if len(columns) != len(values): + def _set_lists(cols, vals): + if len(cols) != len(vals): raise TypeError('The number of columns do not match the number of values') - for col_num, val in zip(columns, values): + + columns = [] + values = [] + for col_num, value in zip(cols, vals): if not isinstance(col_num, int): raise TypeError('TypeError: Expected integer argument for column.') - self.set_value(treeiter, col_num, val) + + columns.append(col_num) + values.append(self._convert_value(col_num, value)) + + Gtk.TreeStore.set(self, treeiter, columns, values) if args: if isinstance(args[0], int): - columns = args[::2] - values = args[1::2] - _set_lists(columns, values) + _set_lists(args[::2], args[1::2]) elif isinstance(args[0], (tuple, list)): if len(args) != 2: raise TypeError('Too many arguments') _set_lists(args[0], args[1]) elif isinstance(args[0], dict): - columns = args[0].keys() - values = args[0].values() - _set_lists(columns, values) + _set_lists(args[0].keys(), args[0].values()) else: raise TypeError('Argument list must be in the form of (column, value, ...), ((columns,...), (values, ...)) or {column: value}. No -1 termination is needed.') + TreeStore = override(TreeStore) __all__.append('TreeStore') class TreeView(Gtk.TreeView, Container): - - def __init__(self, model=None): - Gtk.TreeView.__init__(self) - if model: - self.set_model(model) + if GTK3: + __init__ = deprecated_init(Gtk.TreeView.__init__, + arg_names=('model',), + category=PyGTKDeprecationWarning) get_path_at_pos = strip_boolean_result(Gtk.TreeView.get_path_at_pos) get_visible_range = strip_boolean_result(Gtk.TreeView.get_visible_range) get_dest_row_at_pos = strip_boolean_result(Gtk.TreeView.get_dest_row_at_pos) - def enable_model_drag_source(self, start_button_mask, targets, actions): - target_entries = _construct_target_list(targets) - super(TreeView, self).enable_model_drag_source(start_button_mask, - target_entries, - actions) + if GTK3: + def enable_model_drag_source(self, start_button_mask, targets, actions): + target_entries = _construct_target_list(targets) + super(TreeView, self).enable_model_drag_source(start_button_mask, + target_entries, + actions) - def enable_model_drag_dest(self, targets, actions): - target_entries = _construct_target_list(targets) - super(TreeView, self).enable_model_drag_dest(target_entries, - actions) + if GTK3: + def enable_model_drag_dest(self, targets, actions): + target_entries = _construct_target_list(targets) + super(TreeView, self).enable_model_drag_dest(target_entries, + actions) def scroll_to_cell(self, path, column=None, use_align=False, row_align=0.0, col_align=0.0): if not isinstance(path, Gtk.TreePath): @@ -1299,6 +1383,7 @@ class TreeView(Gtk.TreeView, Container): self.insert_column(column, position) column.set_attributes(cell, **kwargs) + TreeView = override(TreeView) __all__.append('TreeView') @@ -1355,140 +1440,183 @@ TreeSelection = override(TreeSelection) __all__.append('TreeSelection') -class Button(Gtk.Button, Container): - def __init__(self, label=None, stock=None, use_stock=False, use_underline=False, **kwds): - if stock: - label = stock - use_stock = True - use_underline = True - Gtk.Button.__init__(self, label=label, use_stock=use_stock, - use_underline=use_underline, **kwds) -Button = override(Button) -__all__.append('Button') +if GTK3: + class Button(Gtk.Button, Container): + _init = deprecated_init(Gtk.Button.__init__, + arg_names=('label', 'stock', 'use_stock', 'use_underline'), + ignore=('stock',), + category=PyGTKDeprecationWarning, + stacklevel=3) + + def __init__(self, *args, **kwargs): + # Doubly deprecated initializer, the stock keyword is non-standard. + # Simply give a warning that stock items are deprecated even though + # we want to deprecate the non-standard keyword as well here from + # the overrides. + if 'stock' in kwargs and kwargs['stock']: + warnings.warn('Stock items are deprecated. ' + 'Please use: Gtk.Button.new_with_mnemonic(label)', + PyGTKDeprecationWarning, stacklevel=2) + new_kwargs = kwargs.copy() + new_kwargs['label'] = new_kwargs['stock'] + new_kwargs['use_stock'] = True + new_kwargs['use_underline'] = True + del new_kwargs['stock'] + Gtk.Button.__init__(self, **new_kwargs) + else: + self._init(*args, **kwargs) + if hasattr(Gtk.Widget, "set_focus_on_click"): + def set_focus_on_click(self, *args, **kwargs): + # Gtk.Widget.set_focus_on_click should be used instead but it's + # no obvious how because of the shadowed method, so override here + return Gtk.Widget.set_focus_on_click(self, *args, **kwargs) -class LinkButton(Gtk.LinkButton): - def __init__(self, uri, label=None, **kwds): - Gtk.LinkButton.__init__(self, uri=uri, label=label, **kwds) + if hasattr(Gtk.Widget, "get_focus_on_click"): + def get_focus_on_click(self, *args, **kwargs): + # Gtk.Widget.get_focus_on_click should be used instead but it's + # no obvious how because of the shadowed method, so override here + return Gtk.Widget.get_focus_on_click(self, *args, **kwargs) -LinkButton = override(LinkButton) -__all__.append('LinkButton') + Button = override(Button) + __all__.append('Button') + class LinkButton(Gtk.LinkButton): + __init__ = deprecated_init(Gtk.LinkButton.__init__, + arg_names=('uri', 'label'), + category=PyGTKDeprecationWarning) -class Label(Gtk.Label): - def __init__(self, label=None, **kwds): - Gtk.Label.__init__(self, label=label, **kwds) + LinkButton = override(LinkButton) + __all__.append('LinkButton') -Label = override(Label) -__all__.append('Label') + class Label(Gtk.Label): + __init__ = deprecated_init(Gtk.Label.__init__, + arg_names=('label',), + category=PyGTKDeprecationWarning) + Label = override(Label) + __all__.append('Label') -class Adjustment(Gtk.Adjustment): - def __init__(self, *args, **kwds): - arg_names = ('value', 'lower', 'upper', - 'step_increment', 'page_increment', 'page_size') - new_args = dict(zip(arg_names, args)) - new_args.update(kwds) - - # PyGTK compatiblity - if 'page_incr' in new_args: - new_args['page_increment'] = new_args.pop('page_incr') - if 'step_incr' in new_args: - new_args['step_increment'] = new_args.pop('step_incr') - Gtk.Adjustment.__init__(self, **new_args) - - # The value property is set between lower and (upper - page_size). - # Just in case lower, upper or page_size was still 0 when value - # was set, we set it again here. - if 'value' in new_args: - self.set_value(new_args['value']) -Adjustment = override(Adjustment) -__all__.append('Adjustment') - - -class Table(Gtk.Table, Container): - def __init__(self, rows=1, columns=1, homogeneous=False, **kwds): - if 'n_rows' in kwds: - rows = kwds.pop('n_rows') +class Adjustment(Gtk.Adjustment): + if GTK3: + _init = deprecated_init(Gtk.Adjustment.__init__, + arg_names=('value', 'lower', 'upper', + 'step_increment', 'page_increment', 'page_size'), + deprecated_aliases={'page_increment': 'page_incr', + 'step_increment': 'step_incr'}, + category=PyGTKDeprecationWarning, + stacklevel=3) + + def __init__(self, *args, **kwargs): + if GTK3: + self._init(*args, **kwargs) + # The value property is set between lower and (upper - page_size). + # Just in case lower, upper or page_size was still 0 when value + # was set, we set it again here. + if 'value' in kwargs: + self.set_value(kwargs['value']) + elif len(args) >= 1: + self.set_value(args[0]) + else: + Gtk.Adjustment.__init__(self, *args, **kwargs) - if 'n_columns' in kwds: - columns = kwds.pop('n_columns') + # The value property is set between lower and (upper - page_size). + # Just in case lower, upper or page_size was still 0 when value + # was set, we set it again here. + if 'value' in kwargs: + self.set_value(kwargs['value']) - Gtk.Table.__init__(self, n_rows=rows, n_columns=columns, homogeneous=homogeneous, **kwds) - def attach(self, child, left_attach, right_attach, top_attach, bottom_attach, xoptions=Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL, yoptions=Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL, xpadding=0, ypadding=0): - Gtk.Table.attach(self, child, left_attach, right_attach, top_attach, bottom_attach, xoptions, yoptions, xpadding, ypadding) +Adjustment = override(Adjustment) +__all__.append('Adjustment') -Table = override(Table) -__all__.append('Table') +if GTK3: + class Table(Gtk.Table, Container): + __init__ = deprecated_init(Gtk.Table.__init__, + arg_names=('n_rows', 'n_columns', 'homogeneous'), + deprecated_aliases={'n_rows': 'rows', 'n_columns': 'columns'}, + category=PyGTKDeprecationWarning) -class ScrolledWindow(Gtk.ScrolledWindow): - def __init__(self, hadjustment=None, vadjustment=None, **kwds): - Gtk.ScrolledWindow.__init__(self, hadjustment=hadjustment, vadjustment=vadjustment, **kwds) + def attach(self, child, left_attach, right_attach, top_attach, bottom_attach, xoptions=Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL, yoptions=Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL, xpadding=0, ypadding=0): + Gtk.Table.attach(self, child, left_attach, right_attach, top_attach, bottom_attach, xoptions, yoptions, xpadding, ypadding) -ScrolledWindow = override(ScrolledWindow) -__all__.append('ScrolledWindow') + Table = override(Table) + __all__.append('Table') + class ScrolledWindow(Gtk.ScrolledWindow): + __init__ = deprecated_init(Gtk.ScrolledWindow.__init__, + arg_names=('hadjustment', 'vadjustment'), + category=PyGTKDeprecationWarning) -class HScrollbar(Gtk.HScrollbar): - def __init__(self, adjustment=None, **kwds): - Gtk.HScrollbar.__init__(self, adjustment=adjustment, **kwds) + ScrolledWindow = override(ScrolledWindow) + __all__.append('ScrolledWindow') -HScrollbar = override(HScrollbar) -__all__.append('HScrollbar') +if GTK3: + class HScrollbar(Gtk.HScrollbar): + __init__ = deprecated_init(Gtk.HScrollbar.__init__, + arg_names=('adjustment',), + category=PyGTKDeprecationWarning) -class VScrollbar(Gtk.VScrollbar): - def __init__(self, adjustment=None, **kwds): - Gtk.VScrollbar.__init__(self, adjustment=adjustment, **kwds) + HScrollbar = override(HScrollbar) + __all__.append('HScrollbar') -VScrollbar = override(VScrollbar) -__all__.append('VScrollbar') + class VScrollbar(Gtk.VScrollbar): + __init__ = deprecated_init(Gtk.VScrollbar.__init__, + arg_names=('adjustment',), + category=PyGTKDeprecationWarning) + VScrollbar = override(VScrollbar) + __all__.append('VScrollbar') -class Paned(Gtk.Paned): - def pack1(self, child, resize=False, shrink=True): - super(Paned, self).pack1(child, resize, shrink) - def pack2(self, child, resize=True, shrink=True): - super(Paned, self).pack2(child, resize, shrink) +if GTK3: + class Paned(Gtk.Paned): + def pack1(self, child, resize=False, shrink=True): + super(Paned, self).pack1(child, resize, shrink) -Paned = override(Paned) -__all__.append('Paned') + def pack2(self, child, resize=True, shrink=True): + super(Paned, self).pack2(child, resize, shrink) + Paned = override(Paned) + __all__.append('Paned') -class Arrow(Gtk.Arrow): - def __init__(self, arrow_type, shadow_type, **kwds): - Gtk.Arrow.__init__(self, arrow_type=arrow_type, - shadow_type=shadow_type, - **kwds) -Arrow = override(Arrow) -__all__.append('Arrow') +if GTK3: + class Arrow(Gtk.Arrow): + __init__ = deprecated_init(Gtk.Arrow.__init__, + arg_names=('arrow_type', 'shadow_type'), + category=PyGTKDeprecationWarning) + Arrow = override(Arrow) + __all__.append('Arrow') -class IconSet(Gtk.IconSet): - def __new__(cls, pixbuf=None): - if pixbuf is not None: - iconset = Gtk.IconSet.new_from_pixbuf(pixbuf) - else: - iconset = Gtk.IconSet.__new__(cls) - return iconset + class IconSet(Gtk.IconSet): + def __new__(cls, pixbuf=None): + if pixbuf is not None: + warnings.warn('Gtk.IconSet(pixbuf) has been deprecated. Please use: ' + 'Gtk.IconSet.new_from_pixbuf(pixbuf)', + PyGTKDeprecationWarning, stacklevel=2) + iconset = Gtk.IconSet.new_from_pixbuf(pixbuf) + else: + iconset = Gtk.IconSet.__new__(cls) + return iconset -IconSet = override(IconSet) -__all__.append('IconSet') + def __init__(self, *args, **kwargs): + return super(IconSet, self).__init__() + IconSet = override(IconSet) + __all__.append('IconSet') -class Viewport(Gtk.Viewport): - def __init__(self, hadjustment=None, vadjustment=None, **kwds): - Gtk.Viewport.__init__(self, hadjustment=hadjustment, - vadjustment=vadjustment, - **kwds) + class Viewport(Gtk.Viewport): + __init__ = deprecated_init(Gtk.Viewport.__init__, + arg_names=('hadjustment', 'vadjustment'), + category=PyGTKDeprecationWarning) -Viewport = override(Viewport) -__all__.append('Viewport') + Viewport = override(Viewport) + __all__.append('Viewport') class TreeModelFilter(Gtk.TreeModelFilter): @@ -1500,25 +1628,78 @@ class TreeModelFilter(Gtk.TreeModelFilter): iter = self.convert_iter_to_child_iter(iter) self.get_model().set_value(iter, column, value) + TreeModelFilter = override(TreeModelFilter) __all__.append('TreeModelFilter') -if Gtk._version != '2.0': + +class CssProvider(Gtk.CssProvider): + def load_from_data(self, text, length=-1): + if (Gtk.get_major_version(), Gtk.get_minor_version()) >= (4, 9): + if isinstance(text, bytes): + text = text.decode("utf-8") + super(CssProvider, self).load_from_data(text, length) + else: + if isinstance(text, str): + text = text.encode("utf-8") + super(CssProvider, self).load_from_data(text) + + +CssProvider = override(CssProvider) +__all__.append("CssProvider") + +if GTK4: + class CustomSorter(Gtk.CustomSorter): + + @classmethod + def new(cls, sort_func, user_data=None): + if sort_func is not None: + compare_func = wrap_list_store_sort_func(sort_func) + else: + compare_func = None + + return Gtk.CustomSorter.new(compare_func, user_data) + + def set_sort_func(self, sort_func, user_data=None): + if sort_func is not None: + compare_func = wrap_list_store_sort_func(sort_func) + else: + compare_func = None + + return super(CustomSorter, self).set_sort_func(compare_func, user_data) + + CustomSorter = override(CustomSorter) + __all__.append("CustomSorter") + +if GTK3: class Menu(Gtk.Menu): def popup(self, parent_menu_shell, parent_menu_item, func, data, button, activate_time): self.popup_for_device(None, parent_menu_shell, parent_menu_item, func, data, button, activate_time) Menu = override(Menu) __all__.append('Menu') -_Gtk_main_quit = Gtk.main_quit +if GTK3: + _Gtk_main_quit = Gtk.main_quit + + @override(Gtk.main_quit) + def main_quit(*args): + _Gtk_main_quit() + _Gtk_main = Gtk.main -@override(Gtk.main_quit) -def main_quit(*args): - _Gtk_main_quit() + @override(Gtk.main) + def main(*args, **kwargs): + with register_sigint_fallback(Gtk.main_quit): + with wakeup_on_signal(): + return _Gtk_main(*args, **kwargs) -stock_lookup = strip_boolean_result(Gtk.stock_lookup) -__all__.append('stock_lookup') -initialized, argv = Gtk.init_check(sys.argv) -sys.argv = list(argv) +if GTK3: + stock_lookup = strip_boolean_result(Gtk.stock_lookup) + __all__.append('stock_lookup') + +if GTK4: + initialized = Gtk.init_check() +else: + initialized, argv = Gtk.init_check(sys.argv) + sys.argv = list(argv) diff --git a/gi/overrides/Makefile.am b/gi/overrides/Makefile.am deleted file mode 100644 index e69c91c..0000000 --- a/gi/overrides/Makefile.am +++ /dev/null @@ -1,23 +0,0 @@ -pygioverridesdir = $(pyexecdir)/gi/overrides - -pygioverrides_PYTHON = \ - GLib.py \ - Gtk.py \ - Gdk.py \ - GObject.py \ - Gio.py \ - GIMarshallingTests.py \ - Pango.py \ - keysyms.py \ - __init__.py - -# 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 $(pygioverrides_PYTHON); do \ - [ -e $(builddir)/$$f ] || $(LN_S) $(srcdir)/$$f $(builddir)/$$f; \ - done - -all-local: build_pylinks -check-local: build_pylinks diff --git a/gi/overrides/Makefile.in b/gi/overrides/Makefile.in deleted file mode 100644 index 7b2d5ab..0000000 --- a/gi/overrides/Makefile.in +++ /dev/null @@ -1,582 +0,0 @@ -# Makefile.in generated by automake 1.13.3 from Makefile.am. -# @configure_input@ - -# Copyright (C) 1994-2013 Free Software Foundation, Inc. - -# This Makefile.in is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY, to the extent permitted by law; without -# even the implied warranty of MERCHANTABILITY or FITNESS FOR A -# PARTICULAR PURPOSE. - -@SET_MAKE@ -VPATH = @srcdir@ -am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' -am__make_running_with_option = \ - case $${target_option-} in \ - ?) ;; \ - *) echo "am__make_running_with_option: internal error: invalid" \ - "target option '$${target_option-}' specified" >&2; \ - exit 1;; \ - esac; \ - has_opt=no; \ - sane_makeflags=$$MAKEFLAGS; \ - if $(am__is_gnu_make); then \ - sane_makeflags=$$MFLAGS; \ - else \ - case $$MAKEFLAGS in \ - *\\[\ \ ]*) \ - bs=\\; \ - sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ - | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ - esac; \ - fi; \ - skip_next=no; \ - strip_trailopt () \ - { \ - flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ - }; \ - for flg in $$sane_makeflags; do \ - test $$skip_next = yes && { skip_next=no; continue; }; \ - case $$flg in \ - *=*|--*) continue;; \ - -*I) strip_trailopt 'I'; skip_next=yes;; \ - -*I?*) strip_trailopt 'I';; \ - -*O) strip_trailopt 'O'; skip_next=yes;; \ - -*O?*) strip_trailopt 'O';; \ - -*l) strip_trailopt 'l'; skip_next=yes;; \ - -*l?*) strip_trailopt 'l';; \ - -[dEDm]) skip_next=yes;; \ - -[JT]) skip_next=yes;; \ - esac; \ - case $$flg in \ - *$$target_option*) has_opt=yes; break;; \ - esac; \ - done; \ - test $$has_opt = yes -am__make_dryrun = (target_option=n; $(am__make_running_with_option)) -am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) -pkgdatadir = $(datadir)/@PACKAGE@ -pkgincludedir = $(includedir)/@PACKAGE@ -pkglibdir = $(libdir)/@PACKAGE@ -pkglibexecdir = $(libexecdir)/@PACKAGE@ -am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd -install_sh_DATA = $(install_sh) -c -m 644 -install_sh_PROGRAM = $(install_sh) -c -install_sh_SCRIPT = $(install_sh) -c -INSTALL_HEADER = $(INSTALL_DATA) -transform = $(program_transform_name) -NORMAL_INSTALL = : -PRE_INSTALL = : -POST_INSTALL = : -NORMAL_UNINSTALL = : -PRE_UNINSTALL = : -POST_UNINSTALL = : -build_triplet = @build@ -host_triplet = @host@ -subdir = gi/overrides -DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ - $(pygioverrides_PYTHON) $(top_srcdir)/py-compile -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 -am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ - $(ACLOCAL_M4) -mkinstalldirs = $(install_sh) -d -CONFIG_HEADER = $(top_builddir)/config.h -CONFIG_CLEAN_FILES = -CONFIG_CLEAN_VPATH_FILES = -AM_V_P = $(am__v_P_@AM_V@) -am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) -am__v_P_0 = false -am__v_P_1 = : -AM_V_GEN = $(am__v_GEN_@AM_V@) -am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) -am__v_GEN_0 = @echo " GEN " $@; -am__v_GEN_1 = -AM_V_at = $(am__v_at_@AM_V@) -am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) -am__v_at_0 = @ -am__v_at_1 = -SOURCES = -DIST_SOURCES = -am__can_run_installinfo = \ - case $$AM_UPDATE_INFO_DIR in \ - n|no|NO) false;; \ - *) (install-info --version) >/dev/null 2>&1;; \ - esac -am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; -am__vpath_adj = case $$p in \ - $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ - *) f=$$p;; \ - esac; -am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; -am__install_max = 40 -am__nobase_strip_setup = \ - srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` -am__nobase_strip = \ - for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" -am__nobase_list = $(am__nobase_strip_setup); \ - for p in $$list; do echo "$$p $$p"; done | \ - sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ - $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ - if (++n[$$2] == $(am__install_max)) \ - { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ - END { for (dir in files) print dir, files[dir] }' -am__base_list = \ - sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ - sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' -am__uninstall_files_from_dir = { \ - test -z "$$files" \ - || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ - || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ - $(am__cd) "$$dir" && rm -f $$files; }; \ - } -am__py_compile = PYTHON=$(PYTHON) $(SHELL) $(py_compile) -am__installdirs = "$(DESTDIR)$(pygioverridesdir)" -am__pep3147_tweak = \ - sed -e 's|\.py$$||' -e 's|[^/]*$$|__pycache__/&.*.py|' -py_compile = $(top_srcdir)/py-compile -am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) -DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) -ACLOCAL = @ACLOCAL@ -ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@ -AMTAR = @AMTAR@ -AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ -AR = @AR@ -AS = @AS@ -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@ -DATADIR = @DATADIR@ -DEFS = @DEFS@ -DEPDIR = @DEPDIR@ -DLLTOOL = @DLLTOOL@ -DSYMUTIL = @DSYMUTIL@ -DUMPBIN = @DUMPBIN@ -ECHO_C = @ECHO_C@ -ECHO_N = @ECHO_N@ -ECHO_T = @ECHO_T@ -EGREP = @EGREP@ -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@ -GI_DATADIR = @GI_DATADIR@ -GI_LIBS = @GI_LIBS@ -GLIB_CFLAGS = @GLIB_CFLAGS@ -GLIB_COMPILE_RESOURCES = @GLIB_COMPILE_RESOURCES@ -GLIB_GENMARSHAL = @GLIB_GENMARSHAL@ -GLIB_LIBS = @GLIB_LIBS@ -GLIB_MKENUMS = @GLIB_MKENUMS@ -GOBJECT_QUERY = @GOBJECT_QUERY@ -GREP = @GREP@ -INSTALL = @INSTALL@ -INSTALL_DATA = @INSTALL_DATA@ -INSTALL_PROGRAM = @INSTALL_PROGRAM@ -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@ -LIBOBJS = @LIBOBJS@ -LIBS = @LIBS@ -LIBTOOL = @LIBTOOL@ -LIPO = @LIPO@ -LN_S = @LN_S@ -LTLIBOBJS = @LTLIBOBJS@ -MAKEINFO = @MAKEINFO@ -MANIFEST_TOOL = @MANIFEST_TOOL@ -MKDIR_P = @MKDIR_P@ -NM = @NM@ -NMEDIT = @NMEDIT@ -OBJDUMP = @OBJDUMP@ -OBJEXT = @OBJEXT@ -OTOOL = @OTOOL@ -OTOOL64 = @OTOOL64@ -PACKAGE = @PACKAGE@ -PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ -PACKAGE_NAME = @PACKAGE_NAME@ -PACKAGE_STRING = @PACKAGE_STRING@ -PACKAGE_TARNAME = @PACKAGE_TARNAME@ -PACKAGE_URL = @PACKAGE_URL@ -PACKAGE_VERSION = @PACKAGE_VERSION@ -PATH_SEPARATOR = @PATH_SEPARATOR@ -PKG_CONFIG = @PKG_CONFIG@ -PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ -PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ -PLATFORM = @PLATFORM@ -PYCAIRO_CFLAGS = @PYCAIRO_CFLAGS@ -PYCAIRO_LIBS = @PYCAIRO_LIBS@ -PYGOBJECT_MAJOR_VERSION = @PYGOBJECT_MAJOR_VERSION@ -PYGOBJECT_MICRO_VERSION = @PYGOBJECT_MICRO_VERSION@ -PYGOBJECT_MINOR_VERSION = @PYGOBJECT_MINOR_VERSION@ -PYTHON = @PYTHON@ -PYTHON_BASENAME = @PYTHON_BASENAME@ -PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ -PYTHON_INCLUDES = @PYTHON_INCLUDES@ -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@ -SET_MAKE = @SET_MAKE@ -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@ -abs_top_srcdir = @abs_top_srcdir@ -ac_ct_AR = @ac_ct_AR@ -ac_ct_CC = @ac_ct_CC@ -ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ -am__include = @am__include@ -am__leading_dot = @am__leading_dot@ -am__quote = @am__quote@ -am__tar = @am__tar@ -am__untar = @am__untar@ -bindir = @bindir@ -build = @build@ -build_alias = @build_alias@ -build_cpu = @build_cpu@ -build_os = @build_os@ -build_vendor = @build_vendor@ -builddir = @builddir@ -datadir = @datadir@ -datarootdir = @datarootdir@ -docdir = @docdir@ -dvidir = @dvidir@ -exec_prefix = @exec_prefix@ -host = @host@ -host_alias = @host_alias@ -host_cpu = @host_cpu@ -host_os = @host_os@ -host_vendor = @host_vendor@ -htmldir = @htmldir@ -includedir = @includedir@ -infodir = @infodir@ -install_sh = @install_sh@ -libdir = @libdir@ -libexecdir = @libexecdir@ -localedir = @localedir@ -localstatedir = @localstatedir@ -mandir = @mandir@ -mkdir_p = @mkdir_p@ -oldincludedir = @oldincludedir@ -pdfdir = @pdfdir@ -pkgpyexecdir = @pkgpyexecdir@ -pkgpythondir = @pkgpythondir@ -prefix = @prefix@ -program_transform_name = @program_transform_name@ -psdir = @psdir@ -pyexecdir = @pyexecdir@ -pythondir = @pythondir@ -sbindir = @sbindir@ -sharedstatedir = @sharedstatedir@ -srcdir = @srcdir@ -sysconfdir = @sysconfdir@ -target_alias = @target_alias@ -top_build_prefix = @top_build_prefix@ -top_builddir = @top_builddir@ -top_srcdir = @top_srcdir@ -pygioverridesdir = $(pyexecdir)/gi/overrides -pygioverrides_PYTHON = \ - GLib.py \ - Gtk.py \ - Gdk.py \ - GObject.py \ - Gio.py \ - GIMarshallingTests.py \ - Pango.py \ - keysyms.py \ - __init__.py - -all: all-am - -.SUFFIXES: -$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) - @for dep in $?; do \ - case '$(am__configure_deps)' in \ - *$$dep*) \ - ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ - && { if test -f $@; then exit 0; else break; fi; }; \ - exit 1;; \ - esac; \ - done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign gi/overrides/Makefile'; \ - $(am__cd) $(top_srcdir) && \ - $(AUTOMAKE) --foreign gi/overrides/Makefile -.PRECIOUS: Makefile -Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status - @case '$?' in \ - *config.status*) \ - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ - *) \ - echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ - cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ - esac; - -$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh - -$(top_srcdir)/configure: $(am__configure_deps) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh -$(ACLOCAL_M4): $(am__aclocal_m4_deps) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh -$(am__aclocal_m4_deps): - -mostlyclean-libtool: - -rm -f *.lo - -clean-libtool: - -rm -rf .libs _libs -install-pygioverridesPYTHON: $(pygioverrides_PYTHON) - @$(NORMAL_INSTALL) - @list='$(pygioverrides_PYTHON)'; dlist=; list2=; test -n "$(pygioverridesdir)" || list=; \ - if test -n "$$list"; then \ - echo " $(MKDIR_P) '$(DESTDIR)$(pygioverridesdir)'"; \ - $(MKDIR_P) "$(DESTDIR)$(pygioverridesdir)" || exit 1; \ - fi; \ - for p in $$list; do \ - if test -f "$$p"; then b=; else b="$(srcdir)/"; fi; \ - if test -f $$b$$p; then \ - $(am__strip_dir) \ - dlist="$$dlist $$f"; \ - list2="$$list2 $$b$$p"; \ - else :; fi; \ - done; \ - for file in $$list2; do echo $$file; done | $(am__base_list) | \ - while read files; do \ - echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pygioverridesdir)'"; \ - $(INSTALL_DATA) $$files "$(DESTDIR)$(pygioverridesdir)" || exit $$?; \ - done || exit $$?; \ - if test -n "$$dlist"; then \ - $(am__py_compile) --destdir "$(DESTDIR)" \ - --basedir "$(pygioverridesdir)" $$dlist; \ - else :; fi - -uninstall-pygioverridesPYTHON: - @$(NORMAL_UNINSTALL) - @list='$(pygioverrides_PYTHON)'; test -n "$(pygioverridesdir)" || list=; \ - py_files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ - test -n "$$py_files" || exit 0; \ - dir='$(DESTDIR)$(pygioverridesdir)'; \ - pyc_files=`echo "$$py_files" | sed 's|$$|c|'`; \ - pyo_files=`echo "$$py_files" | sed 's|$$|o|'`; \ - py_files_pep3147=`echo "$$py_files" | $(am__pep3147_tweak)`; \ - echo "$$py_files_pep3147";\ - pyc_files_pep3147=`echo "$$py_files_pep3147" | sed 's|$$|c|'`; \ - pyo_files_pep3147=`echo "$$py_files_pep3147" | sed 's|$$|o|'`; \ - st=0; \ - for files in \ - "$$py_files" \ - "$$pyc_files" \ - "$$pyo_files" \ - "$$pyc_files_pep3147" \ - "$$pyo_files_pep3147" \ - ; do \ - $(am__uninstall_files_from_dir) || st=$$?; \ - done; \ - exit $$st -tags TAGS: - -ctags CTAGS: - -cscope cscopelist: - - -distdir: $(DISTFILES) - @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - list='$(DISTFILES)'; \ - dist_files=`for file in $$list; do echo $$file; done | \ - sed -e "s|^$$srcdirstrip/||;t" \ - -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ - case $$dist_files in \ - */*) $(MKDIR_P) `echo "$$dist_files" | \ - sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ - sort -u` ;; \ - esac; \ - for file in $$dist_files; do \ - if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ - if test -d $$d/$$file; then \ - dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ - if test -d "$(distdir)/$$file"; then \ - find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ - fi; \ - if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ - cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ - find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ - fi; \ - cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ - else \ - test -f "$(distdir)/$$file" \ - || cp -p $$d/$$file "$(distdir)/$$file" \ - || exit 1; \ - fi; \ - done -check-am: all-am - $(MAKE) $(AM_MAKEFLAGS) check-local -check: check-am -all-am: Makefile all-local -installdirs: - for dir in "$(DESTDIR)$(pygioverridesdir)"; do \ - test -z "$$dir" || $(MKDIR_P) "$$dir"; \ - done -install: install-am -install-exec: install-exec-am -install-data: install-data-am -uninstall: uninstall-am - -install-am: all-am - @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am - -installcheck: installcheck-am -install-strip: - if test -z '$(STRIP)'; then \ - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ - install; \ - else \ - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ - "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ - fi -mostlyclean-generic: - -clean-generic: - -distclean-generic: - -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) - -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) - -maintainer-clean-generic: - @echo "This command is intended for maintainers to use" - @echo "it deletes files that may require special tools to rebuild." -clean: clean-am - -clean-am: clean-generic clean-libtool mostlyclean-am - -distclean: distclean-am - -rm -f Makefile -distclean-am: clean-am distclean-generic - -dvi: dvi-am - -dvi-am: - -html: html-am - -html-am: - -info: info-am - -info-am: - -install-data-am: install-pygioverridesPYTHON - -install-dvi: install-dvi-am - -install-dvi-am: - -install-exec-am: - -install-html: install-html-am - -install-html-am: - -install-info: install-info-am - -install-info-am: - -install-man: - -install-pdf: install-pdf-am - -install-pdf-am: - -install-ps: install-ps-am - -install-ps-am: - -installcheck-am: - -maintainer-clean: maintainer-clean-am - -rm -f Makefile -maintainer-clean-am: distclean-am maintainer-clean-generic - -mostlyclean: mostlyclean-am - -mostlyclean-am: mostlyclean-generic mostlyclean-libtool - -pdf: pdf-am - -pdf-am: - -ps: ps-am - -ps-am: - -uninstall-am: uninstall-pygioverridesPYTHON - -.MAKE: check-am install-am install-strip - -.PHONY: all all-am all-local check check-am check-local clean \ - clean-generic clean-libtool cscopelist-am ctags-am distclean \ - distclean-generic distclean-libtool distdir dvi dvi-am html \ - html-am info info-am install install-am install-data \ - install-data-am install-dvi install-dvi-am install-exec \ - install-exec-am install-html install-html-am install-info \ - install-info-am install-man install-pdf install-pdf-am \ - install-ps install-ps-am install-pygioverridesPYTHON \ - install-strip installcheck installcheck-am installdirs \ - maintainer-clean maintainer-clean-generic mostlyclean \ - mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ - tags-am uninstall uninstall-am uninstall-pygioverridesPYTHON - - -# 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 $(pygioverrides_PYTHON); do \ - [ -e $(builddir)/$$f ] || $(LN_S) $(srcdir)/$$f $(builddir)/$$f; \ - done - -all-local: build_pylinks -check-local: build_pylinks - -# Tell versions [3.59,3.63) of GNU make to not export all variables. -# Otherwise a system limit (for SysV at least) may be exceeded. -.NOEXPORT: diff --git a/gi/overrides/Pango.py b/gi/overrides/Pango.py index 15d5edc..7d0d8cf 100644 --- a/gi/overrides/Pango.py +++ b/gi/overrides/Pango.py @@ -26,15 +26,6 @@ Pango = get_introspection_module('Pango') __all__ = [] -class Context(Pango.Context): - - def get_metrics(self, desc, language=None): - return super(Context, self).get_metrics(desc, language) - -Context = override(Context) -__all__.append('Context') - - class FontDescription(Pango.FontDescription): def __new__(cls, string=None): @@ -43,6 +34,10 @@ class FontDescription(Pango.FontDescription): else: return Pango.FontDescription.__new__(cls) + def __init__(self, *args, **kwargs): + return super(FontDescription, self).__init__() + + FontDescription = override(FontDescription) __all__.append('FontDescription') @@ -52,13 +47,12 @@ class Layout(Pango.Layout): def __new__(cls, context): return Pango.Layout.new(context) - def __init__(self, context, **kwds): - # simply discard 'context', since it was set by - # __new__ and it is not a PangoLayout property - super(Layout, self).__init__(**kwds) - def set_markup(self, text, length=-1): super(Layout, self).set_markup(text, length) + def set_text(self, text, length=-1): + super(Layout, self).set_text(text, length) + + Layout = override(Layout) __all__.append('Layout') diff --git a/gi/overrides/__init__.py b/gi/overrides/__init__.py index 8aa9731..37dfbbe 100644 --- a/gi/overrides/__init__.py +++ b/gi/overrides/__init__.py @@ -1,10 +1,13 @@ +import functools import types import warnings -import functools +import importlib +import sys +from pkgutil import get_loader from gi import PyGIDeprecationWarning -from gi._gi import CallableInfo -from gi._gobject.constants import \ +from gi._gi import CallableInfo, pygobject_new_full +from gi._constants import \ TYPE_NONE, \ TYPE_INVALID @@ -12,76 +15,200 @@ from gi._gobject.constants import \ from pkgutil import extend_path __path__ = extend_path(__path__, __name__) -registry = None +# namespace -> (attr, replacement) +_deprecated_attrs = {} + + +class OverridesProxyModule(types.ModuleType): + """Wraps a introspection module and contains all overrides""" + + def __init__(self, introspection_module): + super(OverridesProxyModule, self).__init__( + introspection_module.__name__) + self._introspection_module = introspection_module + + def __getattr__(self, name): + return getattr(self._introspection_module, name) + + def __dir__(self): + result = set(dir(self.__class__)) + result.update(self.__dict__.keys()) + result.update(dir(self._introspection_module)) + return sorted(result) + + def __repr__(self): + return "<%s %r>" % (type(self).__name__, self._introspection_module) + + +class _DeprecatedAttribute(object): + """A deprecation descriptor for OverridesProxyModule subclasses. + + Emits a PyGIDeprecationWarning on every access and tries to act as a + normal instance attribute (can be replaced and deleted). + """ + + def __init__(self, namespace, attr, value, replacement): + self._attr = attr + self._value = value + self._warning = PyGIDeprecationWarning( + '%s.%s is deprecated; use %s instead' % ( + namespace, attr, replacement)) + + def __get__(self, instance, owner): + if instance is None: + raise AttributeError(self._attr) + warnings.warn(self._warning, stacklevel=2) + return self._value + + def __set__(self, instance, value): + attr = self._attr + # delete the descriptor, then set the instance value + delattr(type(instance), attr) + setattr(instance, attr, value) + + def __delete__(self, instance): + # delete the descriptor + delattr(type(instance), self._attr) + + +def load_overrides(introspection_module): + """Loads overrides for an introspection module. + + Either returns the same module again in case there are no overrides or a + proxy module including overrides. Doesn't cache the result. + """ -class _Registry(dict): - def __setitem__(self, key, value): - '''We do checks here to make sure only submodules of the override - module are added. Key and value should be the same object and come - from the gi.override module. + namespace = introspection_module.__name__.rsplit(".", 1)[-1] + module_key = 'gi.repository.' + namespace - We add the override to the dict as "override_module.name". For instance - if we were overriding Gtk.Button you would retrive it as such: - registry['Gtk.Button'] - ''' - if not key == value: - raise KeyError('You have tried to modify the registry. This should only be done by the override decorator') + # We use sys.modules so overrides can import from gi.repository + # but restore everything at the end so this doesn't have any side effects + has_old = module_key in sys.modules + old_module = sys.modules.get(module_key) + # Create a new sub type, so we can separate descriptors like + # _DeprecatedAttribute for each namespace. + proxy_type = type(namespace + "ProxyModule", (OverridesProxyModule, ), {}) + + proxy = proxy_type(introspection_module) + sys.modules[module_key] = proxy + + # backwards compat: + # gedit uses gi.importer.modules['Gedit']._introspection_module + from ..importer import modules + assert hasattr(proxy, "_introspection_module") + modules[namespace] = proxy + + try: + override_package_name = 'gi.overrides.' + namespace + + # http://bugs.python.org/issue14710 try: - info = getattr(value, '__info__') + override_loader = get_loader(override_package_name) + except AttributeError: - raise TypeError('Can not override a type %s, which is not in a gobject introspection typelib' % value.__name__) + override_loader = None - if not value.__module__.startswith('gi.overrides'): - raise KeyError('You have tried to modify the registry outside of the overrides module. ' - 'This is not allowed (%s, %s)' % (value, value.__module__)) + # Avoid checking for an ImportError, an override might + # depend on a missing module thus causing an ImportError + if override_loader is None: + return introspection_module - g_type = info.get_g_type() - assert g_type != TYPE_NONE - if g_type != TYPE_INVALID: - g_type.pytype = value - - # strip gi.overrides from module name - module = value.__module__[13:] - key = "%s.%s" % (module, value.__name__) - super(_Registry, self).__setitem__(key, value) - - def register(self, override_class): - self[override_class] = override_class - - -class overridefunc(object): - '''decorator for overriding a function''' - def __init__(self, func): - if not isinstance(func, CallableInfo): - raise TypeError("func must be a gi function, got %s" % func) - from ..importer import modules - module_name = func.__module__.rsplit('.', 1)[-1] - self.module = modules[module_name]._introspection_module - - def __call__(self, func): - def wrapper(*args, **kwargs): - return func(*args, **kwargs) - wrapper.__name__ = func.__name__ - wrapper.__doc__ = func.__doc__ - setattr(self.module, func.__name__, wrapper) - return wrapper + override_mod = importlib.import_module(override_package_name) -registry = _Registry() + finally: + del modules[namespace] + del sys.modules[module_key] + if has_old: + sys.modules[module_key] = old_module + + # backwards compat: for gst-python/gstmodule.c, + # which tries to access Gst.Fraction through + # Gst._overrides_module.Fraction. We assign the proxy instead as that + # contains all overridden classes like Fraction during import anyway and + # there is no need to keep the real override module alive. + proxy._overrides_module = proxy + + override_all = [] + if hasattr(override_mod, "__all__"): + override_all = override_mod.__all__ + + for var in override_all: + try: + item = getattr(override_mod, var) + except (AttributeError, TypeError): + # Gedit puts a non-string in __all__, so catch TypeError here + continue + setattr(proxy, var, item) + + # Replace deprecated module level attributes with a descriptor + # which emits a warning when accessed. + for attr, replacement in _deprecated_attrs.pop(namespace, []): + try: + value = getattr(proxy, attr) + except AttributeError: + raise AssertionError( + "%s was set deprecated but wasn't added to __all__" % attr) + delattr(proxy, attr) + deprecated_attr = _DeprecatedAttribute( + namespace, attr, value, replacement) + setattr(proxy_type, attr, deprecated_attr) + + return proxy def override(type_): - '''Decorator for registering an override''' - if isinstance(type_, (types.FunctionType, CallableInfo)): - return overridefunc(type_) + """Decorator for registering an override. + + Other than objects added to __all__, these can get referenced in the same + override module via the gi.repository module (get_parent_for_object() does + for example), so they have to be added to the module immediately. + """ + + if isinstance(type_, CallableInfo): + func = type_ + namespace = func.__module__.rsplit('.', 1)[-1] + module = sys.modules["gi.repository." + namespace] + + def wrapper(func): + setattr(module, func.__name__, func) + return func + + return wrapper + elif isinstance(type_, types.FunctionType): + raise TypeError("func must be a gi function, got %s" % type_) else: - registry.register(type_) + try: + info = getattr(type_, '__info__') + except AttributeError: + raise TypeError( + 'Can not override a type %s, which is not in a gobject ' + 'introspection typelib' % type_.__name__) + + if not type_.__module__.startswith('gi.overrides'): + raise KeyError( + 'You have tried override outside of the overrides module. ' + 'This is not allowed (%s, %s)' % (type_, type_.__module__)) + + g_type = info.get_g_type() + assert g_type != TYPE_NONE + if g_type != TYPE_INVALID: + g_type.pytype = type_ + + namespace = type_.__module__.rsplit(".", 1)[-1] + module = sys.modules["gi.repository." + namespace] + setattr(module, type_.__name__, type_) + return type_ +overridefunc = override +"""Deprecated""" + + def deprecated(fn, replacement): - '''Decorator for marking methods and classes as deprecated''' + """Decorator for marking methods and classes as deprecated""" @functools.wraps(fn) def wrapped(*args, **kwargs): warnings.warn('%s is deprecated; use %s instead' % (fn.__name__, replacement), @@ -90,13 +217,117 @@ def deprecated(fn, replacement): return wrapped +def deprecated_attr(namespace, attr, replacement): + """Marks a module level attribute as deprecated. Accessing it will emit + a PyGIDeprecationWarning warning. + + e.g. for ``deprecated_attr("GObject", "STATUS_FOO", "GLib.Status.FOO")`` + accessing GObject.STATUS_FOO will emit: + + "GObject.STATUS_FOO is deprecated; use GLib.Status.FOO instead" + + :param str namespace: + The namespace of the override this is called in. + :param str namespace: + The attribute name (which gets added to __all__). + :param str replacement: + The replacement text which will be included in the warning. + """ + + _deprecated_attrs.setdefault(namespace, []).append((attr, replacement)) + + +def deprecated_init(super_init_func, arg_names, ignore=tuple(), + deprecated_aliases={}, deprecated_defaults={}, + category=PyGIDeprecationWarning, + stacklevel=2): + """Wrapper for deprecating GObject based __init__ methods which specify + defaults already available or non-standard defaults. + + :param callable super_init_func: + Initializer to wrap. + :param list arg_names: + Ordered argument name list. + :param list ignore: + List of argument names to ignore when calling the wrapped function. + This is useful for function which take a non-standard keyword that is munged elsewhere. + :param dict deprecated_aliases: + Dictionary mapping a keyword alias to the actual g_object_newv keyword. + :param dict deprecated_defaults: + Dictionary of non-standard defaults that will be used when the + keyword is not explicitly passed. + :param Exception category: + Exception category of the error. + :param int stacklevel: + Stack level for the deprecation passed on to warnings.warn + :returns: Wrapped version of ``super_init_func`` which gives a deprecation + warning when non-keyword args or aliases are used. + :rtype: callable + """ + # We use a list of argument names to maintain order of the arguments + # being deprecated. This allows calls with positional arguments to + # continue working but with a deprecation message. + def new_init(self, *args, **kwargs): + """Initializer for a GObject based classes with support for property + sets through the use of explicit keyword arguments. + """ + # Print warnings for calls with positional arguments. + if args: + warnings.warn('Using positional arguments with the GObject constructor has been deprecated. ' + 'Please specify keyword(s) for "%s" or use a class specific constructor. ' + 'See: https://wiki.gnome.org/PyGObject/InitializerDeprecations' % + ', '.join(arg_names[:len(args)]), + category, stacklevel=stacklevel) + new_kwargs = dict(zip(arg_names, args)) + else: + new_kwargs = {} + new_kwargs.update(kwargs) + + # Print warnings for alias usage and transfer them into the new key. + aliases_used = [] + for key, alias in deprecated_aliases.items(): + if alias in new_kwargs: + new_kwargs[key] = new_kwargs.pop(alias) + aliases_used.append(key) + + if aliases_used: + warnings.warn('The keyword(s) "%s" have been deprecated in favor of "%s" respectively. ' + 'See: https://wiki.gnome.org/PyGObject/InitializerDeprecations' % + (', '.join(deprecated_aliases[k] for k in sorted(aliases_used)), + ', '.join(sorted(aliases_used))), + category, stacklevel=stacklevel) + + # Print warnings for defaults different than what is already provided by the property + defaults_used = [] + for key, value in deprecated_defaults.items(): + if key not in new_kwargs: + new_kwargs[key] = deprecated_defaults[key] + defaults_used.append(key) + + if defaults_used: + warnings.warn('Initializer is relying on deprecated non-standard ' + 'defaults. Please update to explicitly use: %s ' + 'See: https://wiki.gnome.org/PyGObject/InitializerDeprecations' % + ', '.join('%s=%s' % (k, deprecated_defaults[k]) for k in sorted(defaults_used)), + category, stacklevel=stacklevel) + + # Remove keywords that should be ignored. + for key in ignore: + if key in new_kwargs: + new_kwargs.pop(key) + + return super_init_func(self, **new_kwargs) + + return new_init + + def strip_boolean_result(method, exc_type=None, exc_str=None, fail_ret=None): - '''Translate method's return value for stripping off success flag. + """Translate method's return value for stripping off success flag. There are a lot of methods which return a "success" boolean and have several out arguments. Translate such a method to return the out arguments on success and None on failure. - ''' + """ @functools.wraps(method) def wrapped(*args, **kwargs): ret = method(*args, **kwargs) @@ -110,3 +341,13 @@ def strip_boolean_result(method, exc_type=None, exc_str=None, fail_ret=None): raise exc_type(exc_str or 'call failed') return fail_ret return wrapped + + +def wrap_list_store_sort_func(func): + + def wrap(a, b, *user_data): + a = pygobject_new_full(a, False) + b = pygobject_new_full(b, False) + return func(a, b, *user_data) + + return wrap diff --git a/gi/overrides/keysyms.py b/gi/overrides/keysyms.py index 35ee8eb..07ce277 100644 --- a/gi/overrides/keysyms.py +++ b/gi/overrides/keysyms.py @@ -15,1485 +15,39 @@ # 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 +# License along with this library; if not, see <http://www.gnu.org/licenses/>. -VoidSymbol = 0xFFFFFF -BackSpace = 0xFF08 -Tab = 0xFF09 -Linefeed = 0xFF0A -Clear = 0xFF0B -Return = 0xFF0D -Pause = 0xFF13 -Scroll_Lock = 0xFF14 -Sys_Req = 0xFF15 -Escape = 0xFF1B -Delete = 0xFFFF -Multi_key = 0xFF20 -Codeinput = 0xFF37 -SingleCandidate = 0xFF3C -MultipleCandidate = 0xFF3D -PreviousCandidate = 0xFF3E -Kanji = 0xFF21 -Muhenkan = 0xFF22 -Henkan_Mode = 0xFF23 -Henkan = 0xFF23 -Romaji = 0xFF24 -Hiragana = 0xFF25 -Katakana = 0xFF26 -Hiragana_Katakana = 0xFF27 -Zenkaku = 0xFF28 -Hankaku = 0xFF29 -Zenkaku_Hankaku = 0xFF2A -Touroku = 0xFF2B -Massyo = 0xFF2C -Kana_Lock = 0xFF2D -Kana_Shift = 0xFF2E -Eisu_Shift = 0xFF2F -Eisu_toggle = 0xFF30 -Kanji_Bangou = 0xFF37 -Zen_Koho = 0xFF3D -Mae_Koho = 0xFF3E -Home = 0xFF50 -Left = 0xFF51 -Up = 0xFF52 -Right = 0xFF53 -Down = 0xFF54 -Prior = 0xFF55 -Page_Up = 0xFF55 -Next = 0xFF56 -Page_Down = 0xFF56 -End = 0xFF57 -Begin = 0xFF58 -Select = 0xFF60 -Print = 0xFF61 -Execute = 0xFF62 -Insert = 0xFF63 -Undo = 0xFF65 -Redo = 0xFF66 -Menu = 0xFF67 -Find = 0xFF68 -Cancel = 0xFF69 -Help = 0xFF6A -Break = 0xFF6B -Mode_switch = 0xFF7E -script_switch = 0xFF7E -Num_Lock = 0xFF7F -KP_Space = 0xFF80 -KP_Tab = 0xFF89 -KP_Enter = 0xFF8D -KP_F1 = 0xFF91 -KP_F2 = 0xFF92 -KP_F3 = 0xFF93 -KP_F4 = 0xFF94 -KP_Home = 0xFF95 -KP_Left = 0xFF96 -KP_Up = 0xFF97 -KP_Right = 0xFF98 -KP_Down = 0xFF99 -KP_Prior = 0xFF9A -KP_Page_Up = 0xFF9A -KP_Next = 0xFF9B -KP_Page_Down = 0xFF9B -KP_End = 0xFF9C -KP_Begin = 0xFF9D -KP_Insert = 0xFF9E -KP_Delete = 0xFF9F -KP_Equal = 0xFFBD -KP_Multiply = 0xFFAA -KP_Add = 0xFFAB -KP_Separator = 0xFFAC -KP_Subtract = 0xFFAD -KP_Decimal = 0xFFAE -KP_Divide = 0xFFAF -KP_0 = 0xFFB0 -KP_1 = 0xFFB1 -KP_2 = 0xFFB2 -KP_3 = 0xFFB3 -KP_4 = 0xFFB4 -KP_5 = 0xFFB5 -KP_6 = 0xFFB6 -KP_7 = 0xFFB7 -KP_8 = 0xFFB8 -KP_9 = 0xFFB9 -F1 = 0xFFBE -F2 = 0xFFBF -F3 = 0xFFC0 -F4 = 0xFFC1 -F5 = 0xFFC2 -F6 = 0xFFC3 -F7 = 0xFFC4 -F8 = 0xFFC5 -F9 = 0xFFC6 -F10 = 0xFFC7 -F11 = 0xFFC8 -L1 = 0xFFC8 -F12 = 0xFFC9 -L2 = 0xFFC9 -F13 = 0xFFCA -L3 = 0xFFCA -F14 = 0xFFCB -L4 = 0xFFCB -F15 = 0xFFCC -L5 = 0xFFCC -F16 = 0xFFCD -L6 = 0xFFCD -F17 = 0xFFCE -L7 = 0xFFCE -F18 = 0xFFCF -L8 = 0xFFCF -F19 = 0xFFD0 -L9 = 0xFFD0 -F20 = 0xFFD1 -L10 = 0xFFD1 -F21 = 0xFFD2 -R1 = 0xFFD2 -F22 = 0xFFD3 -R2 = 0xFFD3 -F23 = 0xFFD4 -R3 = 0xFFD4 -F24 = 0xFFD5 -R4 = 0xFFD5 -F25 = 0xFFD6 -R5 = 0xFFD6 -F26 = 0xFFD7 -R6 = 0xFFD7 -F27 = 0xFFD8 -R7 = 0xFFD8 -F28 = 0xFFD9 -R8 = 0xFFD9 -F29 = 0xFFDA -R9 = 0xFFDA -F30 = 0xFFDB -R10 = 0xFFDB -F31 = 0xFFDC -R11 = 0xFFDC -F32 = 0xFFDD -R12 = 0xFFDD -F33 = 0xFFDE -R13 = 0xFFDE -F34 = 0xFFDF -R14 = 0xFFDF -F35 = 0xFFE0 -R15 = 0xFFE0 -Shift_L = 0xFFE1 -Shift_R = 0xFFE2 -Control_L = 0xFFE3 -Control_R = 0xFFE4 -Caps_Lock = 0xFFE5 -Shift_Lock = 0xFFE6 -Meta_L = 0xFFE7 -Meta_R = 0xFFE8 -Alt_L = 0xFFE9 -Alt_R = 0xFFEA -Super_L = 0xFFEB -Super_R = 0xFFEC -Hyper_L = 0xFFED -Hyper_R = 0xFFEE -ISO_Lock = 0xFE01 -ISO_Level2_Latch = 0xFE02 -ISO_Level3_Shift = 0xFE03 -ISO_Level3_Latch = 0xFE04 -ISO_Level3_Lock = 0xFE05 -ISO_Group_Shift = 0xFF7E -ISO_Group_Latch = 0xFE06 -ISO_Group_Lock = 0xFE07 -ISO_Next_Group = 0xFE08 -ISO_Next_Group_Lock = 0xFE09 -ISO_Prev_Group = 0xFE0A -ISO_Prev_Group_Lock = 0xFE0B -ISO_First_Group = 0xFE0C -ISO_First_Group_Lock = 0xFE0D -ISO_Last_Group = 0xFE0E -ISO_Last_Group_Lock = 0xFE0F -ISO_Left_Tab = 0xFE20 -ISO_Move_Line_Up = 0xFE21 -ISO_Move_Line_Down = 0xFE22 -ISO_Partial_Line_Up = 0xFE23 -ISO_Partial_Line_Down = 0xFE24 -ISO_Partial_Space_Left = 0xFE25 -ISO_Partial_Space_Right = 0xFE26 -ISO_Set_Margin_Left = 0xFE27 -ISO_Set_Margin_Right = 0xFE28 -ISO_Release_Margin_Left = 0xFE29 -ISO_Release_Margin_Right = 0xFE2A -ISO_Release_Both_Margins = 0xFE2B -ISO_Fast_Cursor_Left = 0xFE2C -ISO_Fast_Cursor_Right = 0xFE2D -ISO_Fast_Cursor_Up = 0xFE2E -ISO_Fast_Cursor_Down = 0xFE2F -ISO_Continuous_Underline = 0xFE30 -ISO_Discontinuous_Underline = 0xFE31 -ISO_Emphasize = 0xFE32 -ISO_Center_Object = 0xFE33 -ISO_Enter = 0xFE34 -dead_grave = 0xFE50 -dead_acute = 0xFE51 -dead_circumflex = 0xFE52 -dead_tilde = 0xFE53 -dead_macron = 0xFE54 -dead_breve = 0xFE55 -dead_abovedot = 0xFE56 -dead_diaeresis = 0xFE57 -dead_abovering = 0xFE58 -dead_doubleacute = 0xFE59 -dead_caron = 0xFE5A -dead_cedilla = 0xFE5B -dead_ogonek = 0xFE5C -dead_iota = 0xFE5D -dead_voiced_sound = 0xFE5E -dead_semivoiced_sound = 0xFE5F -dead_belowdot = 0xFE60 -First_Virtual_Screen = 0xFED0 -Prev_Virtual_Screen = 0xFED1 -Next_Virtual_Screen = 0xFED2 -Last_Virtual_Screen = 0xFED4 -Terminate_Server = 0xFED5 -AccessX_Enable = 0xFE70 -AccessX_Feedback_Enable = 0xFE71 -RepeatKeys_Enable = 0xFE72 -SlowKeys_Enable = 0xFE73 -BounceKeys_Enable = 0xFE74 -StickyKeys_Enable = 0xFE75 -MouseKeys_Enable = 0xFE76 -MouseKeys_Accel_Enable = 0xFE77 -Overlay1_Enable = 0xFE78 -Overlay2_Enable = 0xFE79 -AudibleBell_Enable = 0xFE7A -Pointer_Left = 0xFEE0 -Pointer_Right = 0xFEE1 -Pointer_Up = 0xFEE2 -Pointer_Down = 0xFEE3 -Pointer_UpLeft = 0xFEE4 -Pointer_UpRight = 0xFEE5 -Pointer_DownLeft = 0xFEE6 -Pointer_DownRight = 0xFEE7 -Pointer_Button_Dflt = 0xFEE8 -Pointer_Button1 = 0xFEE9 -Pointer_Button2 = 0xFEEA -Pointer_Button3 = 0xFEEB -Pointer_Button4 = 0xFEEC -Pointer_Button5 = 0xFEED -Pointer_DblClick_Dflt = 0xFEEE -Pointer_DblClick1 = 0xFEEF -Pointer_DblClick2 = 0xFEF0 -Pointer_DblClick3 = 0xFEF1 -Pointer_DblClick4 = 0xFEF2 -Pointer_DblClick5 = 0xFEF3 -Pointer_Drag_Dflt = 0xFEF4 -Pointer_Drag1 = 0xFEF5 -Pointer_Drag2 = 0xFEF6 -Pointer_Drag3 = 0xFEF7 -Pointer_Drag4 = 0xFEF8 -Pointer_Drag5 = 0xFEFD -Pointer_EnableKeys = 0xFEF9 -Pointer_Accelerate = 0xFEFA -Pointer_DfltBtnNext = 0xFEFB -Pointer_DfltBtnPrev = 0xFEFC -_3270_Duplicate = 0xFD01 -_3270_FieldMark = 0xFD02 -_3270_Right2 = 0xFD03 -_3270_Left2 = 0xFD04 -_3270_BackTab = 0xFD05 -_3270_EraseEOF = 0xFD06 -_3270_EraseInput = 0xFD07 -_3270_Reset = 0xFD08 -_3270_Quit = 0xFD09 -_3270_PA1 = 0xFD0A -_3270_PA2 = 0xFD0B -_3270_PA3 = 0xFD0C -_3270_Test = 0xFD0D -_3270_Attn = 0xFD0E -_3270_CursorBlink = 0xFD0F -_3270_AltCursor = 0xFD10 -_3270_KeyClick = 0xFD11 -_3270_Jump = 0xFD12 -_3270_Ident = 0xFD13 -_3270_Rule = 0xFD14 -_3270_Copy = 0xFD15 -_3270_Play = 0xFD16 -_3270_Setup = 0xFD17 -_3270_Record = 0xFD18 -_3270_ChangeScreen = 0xFD19 -_3270_DeleteWord = 0xFD1A -_3270_ExSelect = 0xFD1B -_3270_CursorSelect = 0xFD1C -_3270_PrintScreen = 0xFD1D -_3270_Enter = 0xFD1E -space = 0x020 -exclam = 0x021 -quotedbl = 0x022 -numbersign = 0x023 -dollar = 0x024 -percent = 0x025 -ampersand = 0x026 -apostrophe = 0x027 -quoteright = 0x027 -parenleft = 0x028 -parenright = 0x029 -asterisk = 0x02a -plus = 0x02b -comma = 0x02c -minus = 0x02d -period = 0x02e -slash = 0x02f -_0 = 0x030 -_1 = 0x031 -_2 = 0x032 -_3 = 0x033 -_4 = 0x034 -_5 = 0x035 -_6 = 0x036 -_7 = 0x037 -_8 = 0x038 -_9 = 0x039 -colon = 0x03a -semicolon = 0x03b -less = 0x03c -equal = 0x03d -greater = 0x03e -question = 0x03f -at = 0x040 -A = 0x041 -B = 0x042 -C = 0x043 -D = 0x044 -E = 0x045 -F = 0x046 -G = 0x047 -H = 0x048 -I = 0x049 -J = 0x04a -K = 0x04b -L = 0x04c -M = 0x04d -N = 0x04e -O = 0x04f -P = 0x050 -Q = 0x051 -R = 0x052 -S = 0x053 -T = 0x054 -U = 0x055 -V = 0x056 -W = 0x057 -X = 0x058 -Y = 0x059 -Z = 0x05a -bracketleft = 0x05b -backslash = 0x05c -bracketright = 0x05d -asciicircum = 0x05e -underscore = 0x05f -grave = 0x060 -quoteleft = 0x060 -a = 0x061 -b = 0x062 -c = 0x063 -d = 0x064 -e = 0x065 -f = 0x066 -g = 0x067 -h = 0x068 -i = 0x069 -j = 0x06a -k = 0x06b -l = 0x06c -m = 0x06d -n = 0x06e -o = 0x06f -p = 0x070 -q = 0x071 -r = 0x072 -s = 0x073 -t = 0x074 -u = 0x075 -v = 0x076 -w = 0x077 -x = 0x078 -y = 0x079 -z = 0x07a -braceleft = 0x07b -bar = 0x07c -braceright = 0x07d -asciitilde = 0x07e -nobreakspace = 0x0a0 -exclamdown = 0x0a1 -cent = 0x0a2 -sterling = 0x0a3 -currency = 0x0a4 -yen = 0x0a5 -brokenbar = 0x0a6 -section = 0x0a7 -diaeresis = 0x0a8 -copyright = 0x0a9 -ordfeminine = 0x0aa -guillemotleft = 0x0ab -notsign = 0x0ac -hyphen = 0x0ad -registered = 0x0ae -macron = 0x0af -degree = 0x0b0 -plusminus = 0x0b1 -twosuperior = 0x0b2 -threesuperior = 0x0b3 -acute = 0x0b4 -mu = 0x0b5 -paragraph = 0x0b6 -periodcentered = 0x0b7 -cedilla = 0x0b8 -onesuperior = 0x0b9 -masculine = 0x0ba -guillemotright = 0x0bb -onequarter = 0x0bc -onehalf = 0x0bd -threequarters = 0x0be -questiondown = 0x0bf -Agrave = 0x0c0 -Aacute = 0x0c1 -Acircumflex = 0x0c2 -Atilde = 0x0c3 -Adiaeresis = 0x0c4 -Aring = 0x0c5 -AE = 0x0c6 -Ccedilla = 0x0c7 -Egrave = 0x0c8 -Eacute = 0x0c9 -Ecircumflex = 0x0ca -Ediaeresis = 0x0cb -Igrave = 0x0cc -Iacute = 0x0cd -Icircumflex = 0x0ce -Idiaeresis = 0x0cf -ETH = 0x0d0 -Eth = 0x0d0 -Ntilde = 0x0d1 -Ograve = 0x0d2 -Oacute = 0x0d3 -Ocircumflex = 0x0d4 -Otilde = 0x0d5 -Odiaeresis = 0x0d6 -multiply = 0x0d7 -Ooblique = 0x0d8 -Ugrave = 0x0d9 -Uacute = 0x0da -Ucircumflex = 0x0db -Udiaeresis = 0x0dc -Yacute = 0x0dd -THORN = 0x0de -Thorn = 0x0de -ssharp = 0x0df -agrave = 0x0e0 -aacute = 0x0e1 -acircumflex = 0x0e2 -atilde = 0x0e3 -adiaeresis = 0x0e4 -aring = 0x0e5 -ae = 0x0e6 -ccedilla = 0x0e7 -egrave = 0x0e8 -eacute = 0x0e9 -ecircumflex = 0x0ea -ediaeresis = 0x0eb -igrave = 0x0ec -iacute = 0x0ed -icircumflex = 0x0ee -idiaeresis = 0x0ef -eth = 0x0f0 -ntilde = 0x0f1 -ograve = 0x0f2 -oacute = 0x0f3 -ocircumflex = 0x0f4 -otilde = 0x0f5 -odiaeresis = 0x0f6 -division = 0x0f7 -oslash = 0x0f8 -ugrave = 0x0f9 -uacute = 0x0fa -ucircumflex = 0x0fb -udiaeresis = 0x0fc -yacute = 0x0fd -thorn = 0x0fe -ydiaeresis = 0x0ff -Aogonek = 0x1a1 -breve = 0x1a2 -Lstroke = 0x1a3 -Lcaron = 0x1a5 -Sacute = 0x1a6 -Scaron = 0x1a9 -Scedilla = 0x1aa -Tcaron = 0x1ab -Zacute = 0x1ac -Zcaron = 0x1ae -Zabovedot = 0x1af -aogonek = 0x1b1 -ogonek = 0x1b2 -lstroke = 0x1b3 -lcaron = 0x1b5 -sacute = 0x1b6 -caron = 0x1b7 -scaron = 0x1b9 -scedilla = 0x1ba -tcaron = 0x1bb -zacute = 0x1bc -doubleacute = 0x1bd -zcaron = 0x1be -zabovedot = 0x1bf -Racute = 0x1c0 -Abreve = 0x1c3 -Lacute = 0x1c5 -Cacute = 0x1c6 -Ccaron = 0x1c8 -Eogonek = 0x1ca -Ecaron = 0x1cc -Dcaron = 0x1cf -Dstroke = 0x1d0 -Nacute = 0x1d1 -Ncaron = 0x1d2 -Odoubleacute = 0x1d5 -Rcaron = 0x1d8 -Uring = 0x1d9 -Udoubleacute = 0x1db -Tcedilla = 0x1de -racute = 0x1e0 -abreve = 0x1e3 -lacute = 0x1e5 -cacute = 0x1e6 -ccaron = 0x1e8 -eogonek = 0x1ea -ecaron = 0x1ec -dcaron = 0x1ef -dstroke = 0x1f0 -nacute = 0x1f1 -ncaron = 0x1f2 -odoubleacute = 0x1f5 -udoubleacute = 0x1fb -rcaron = 0x1f8 -uring = 0x1f9 -tcedilla = 0x1fe -abovedot = 0x1ff -Hstroke = 0x2a1 -Hcircumflex = 0x2a6 -Iabovedot = 0x2a9 -Gbreve = 0x2ab -Jcircumflex = 0x2ac -hstroke = 0x2b1 -hcircumflex = 0x2b6 -idotless = 0x2b9 -gbreve = 0x2bb -jcircumflex = 0x2bc -Cabovedot = 0x2c5 -Ccircumflex = 0x2c6 -Gabovedot = 0x2d5 -Gcircumflex = 0x2d8 -Ubreve = 0x2dd -Scircumflex = 0x2de -cabovedot = 0x2e5 -ccircumflex = 0x2e6 -gabovedot = 0x2f5 -gcircumflex = 0x2f8 -ubreve = 0x2fd -scircumflex = 0x2fe -kra = 0x3a2 -kappa = 0x3a2 -Rcedilla = 0x3a3 -Itilde = 0x3a5 -Lcedilla = 0x3a6 -Emacron = 0x3aa -Gcedilla = 0x3ab -Tslash = 0x3ac -rcedilla = 0x3b3 -itilde = 0x3b5 -lcedilla = 0x3b6 -emacron = 0x3ba -gcedilla = 0x3bb -tslash = 0x3bc -ENG = 0x3bd -eng = 0x3bf -Amacron = 0x3c0 -Iogonek = 0x3c7 -Eabovedot = 0x3cc -Imacron = 0x3cf -Ncedilla = 0x3d1 -Omacron = 0x3d2 -Kcedilla = 0x3d3 -Uogonek = 0x3d9 -Utilde = 0x3dd -Umacron = 0x3de -amacron = 0x3e0 -iogonek = 0x3e7 -eabovedot = 0x3ec -imacron = 0x3ef -ncedilla = 0x3f1 -omacron = 0x3f2 -kcedilla = 0x3f3 -uogonek = 0x3f9 -utilde = 0x3fd -umacron = 0x3fe -OE = 0x13bc -oe = 0x13bd -Ydiaeresis = 0x13be -overline = 0x47e -kana_fullstop = 0x4a1 -kana_openingbracket = 0x4a2 -kana_closingbracket = 0x4a3 -kana_comma = 0x4a4 -kana_conjunctive = 0x4a5 -kana_middledot = 0x4a5 -kana_WO = 0x4a6 -kana_a = 0x4a7 -kana_i = 0x4a8 -kana_u = 0x4a9 -kana_e = 0x4aa -kana_o = 0x4ab -kana_ya = 0x4ac -kana_yu = 0x4ad -kana_yo = 0x4ae -kana_tsu = 0x4af -kana_tu = 0x4af -prolongedsound = 0x4b0 -kana_A = 0x4b1 -kana_I = 0x4b2 -kana_U = 0x4b3 -kana_E = 0x4b4 -kana_O = 0x4b5 -kana_KA = 0x4b6 -kana_KI = 0x4b7 -kana_KU = 0x4b8 -kana_KE = 0x4b9 -kana_KO = 0x4ba -kana_SA = 0x4bb -kana_SHI = 0x4bc -kana_SU = 0x4bd -kana_SE = 0x4be -kana_SO = 0x4bf -kana_TA = 0x4c0 -kana_CHI = 0x4c1 -kana_TI = 0x4c1 -kana_TSU = 0x4c2 -kana_TU = 0x4c2 -kana_TE = 0x4c3 -kana_TO = 0x4c4 -kana_NA = 0x4c5 -kana_NI = 0x4c6 -kana_NU = 0x4c7 -kana_NE = 0x4c8 -kana_NO = 0x4c9 -kana_HA = 0x4ca -kana_HI = 0x4cb -kana_FU = 0x4cc -kana_HU = 0x4cc -kana_HE = 0x4cd -kana_HO = 0x4ce -kana_MA = 0x4cf -kana_MI = 0x4d0 -kana_MU = 0x4d1 -kana_ME = 0x4d2 -kana_MO = 0x4d3 -kana_YA = 0x4d4 -kana_YU = 0x4d5 -kana_YO = 0x4d6 -kana_RA = 0x4d7 -kana_RI = 0x4d8 -kana_RU = 0x4d9 -kana_RE = 0x4da -kana_RO = 0x4db -kana_WA = 0x4dc -kana_N = 0x4dd -voicedsound = 0x4de -semivoicedsound = 0x4df -kana_switch = 0xFF7E -Arabic_comma = 0x5ac -Arabic_semicolon = 0x5bb -Arabic_question_mark = 0x5bf -Arabic_hamza = 0x5c1 -Arabic_maddaonalef = 0x5c2 -Arabic_hamzaonalef = 0x5c3 -Arabic_hamzaonwaw = 0x5c4 -Arabic_hamzaunderalef = 0x5c5 -Arabic_hamzaonyeh = 0x5c6 -Arabic_alef = 0x5c7 -Arabic_beh = 0x5c8 -Arabic_tehmarbuta = 0x5c9 -Arabic_teh = 0x5ca -Arabic_theh = 0x5cb -Arabic_jeem = 0x5cc -Arabic_hah = 0x5cd -Arabic_khah = 0x5ce -Arabic_dal = 0x5cf -Arabic_thal = 0x5d0 -Arabic_ra = 0x5d1 -Arabic_zain = 0x5d2 -Arabic_seen = 0x5d3 -Arabic_sheen = 0x5d4 -Arabic_sad = 0x5d5 -Arabic_dad = 0x5d6 -Arabic_tah = 0x5d7 -Arabic_zah = 0x5d8 -Arabic_ain = 0x5d9 -Arabic_ghain = 0x5da -Arabic_tatweel = 0x5e0 -Arabic_feh = 0x5e1 -Arabic_qaf = 0x5e2 -Arabic_kaf = 0x5e3 -Arabic_lam = 0x5e4 -Arabic_meem = 0x5e5 -Arabic_noon = 0x5e6 -Arabic_ha = 0x5e7 -Arabic_heh = 0x5e7 -Arabic_waw = 0x5e8 -Arabic_alefmaksura = 0x5e9 -Arabic_yeh = 0x5ea -Arabic_fathatan = 0x5eb -Arabic_dammatan = 0x5ec -Arabic_kasratan = 0x5ed -Arabic_fatha = 0x5ee -Arabic_damma = 0x5ef -Arabic_kasra = 0x5f0 -Arabic_shadda = 0x5f1 -Arabic_sukun = 0x5f2 -Arabic_switch = 0xFF7E -Serbian_dje = 0x6a1 -Macedonia_gje = 0x6a2 -Cyrillic_io = 0x6a3 -Ukrainian_ie = 0x6a4 -Ukranian_je = 0x6a4 -Macedonia_dse = 0x6a5 -Ukrainian_i = 0x6a6 -Ukranian_i = 0x6a6 -Ukrainian_yi = 0x6a7 -Ukranian_yi = 0x6a7 -Cyrillic_je = 0x6a8 -Serbian_je = 0x6a8 -Cyrillic_lje = 0x6a9 -Serbian_lje = 0x6a9 -Cyrillic_nje = 0x6aa -Serbian_nje = 0x6aa -Serbian_tshe = 0x6ab -Macedonia_kje = 0x6ac -Ukrainian_ghe_with_upturn = 0x6ad -Byelorussian_shortu = 0x6ae -Cyrillic_dzhe = 0x6af -Serbian_dze = 0x6af -numerosign = 0x6b0 -Serbian_DJE = 0x6b1 -Macedonia_GJE = 0x6b2 -Cyrillic_IO = 0x6b3 -Ukrainian_IE = 0x6b4 -Ukranian_JE = 0x6b4 -Macedonia_DSE = 0x6b5 -Ukrainian_I = 0x6b6 -Ukranian_I = 0x6b6 -Ukrainian_YI = 0x6b7 -Ukranian_YI = 0x6b7 -Cyrillic_JE = 0x6b8 -Serbian_JE = 0x6b8 -Cyrillic_LJE = 0x6b9 -Serbian_LJE = 0x6b9 -Cyrillic_NJE = 0x6ba -Serbian_NJE = 0x6ba -Serbian_TSHE = 0x6bb -Macedonia_KJE = 0x6bc -Ukrainian_GHE_WITH_UPTURN = 0x6bd -Byelorussian_SHORTU = 0x6be -Cyrillic_DZHE = 0x6bf -Serbian_DZE = 0x6bf -Cyrillic_yu = 0x6c0 -Cyrillic_a = 0x6c1 -Cyrillic_be = 0x6c2 -Cyrillic_tse = 0x6c3 -Cyrillic_de = 0x6c4 -Cyrillic_ie = 0x6c5 -Cyrillic_ef = 0x6c6 -Cyrillic_ghe = 0x6c7 -Cyrillic_ha = 0x6c8 -Cyrillic_i = 0x6c9 -Cyrillic_shorti = 0x6ca -Cyrillic_ka = 0x6cb -Cyrillic_el = 0x6cc -Cyrillic_em = 0x6cd -Cyrillic_en = 0x6ce -Cyrillic_o = 0x6cf -Cyrillic_pe = 0x6d0 -Cyrillic_ya = 0x6d1 -Cyrillic_er = 0x6d2 -Cyrillic_es = 0x6d3 -Cyrillic_te = 0x6d4 -Cyrillic_u = 0x6d5 -Cyrillic_zhe = 0x6d6 -Cyrillic_ve = 0x6d7 -Cyrillic_softsign = 0x6d8 -Cyrillic_yeru = 0x6d9 -Cyrillic_ze = 0x6da -Cyrillic_sha = 0x6db -Cyrillic_e = 0x6dc -Cyrillic_shcha = 0x6dd -Cyrillic_che = 0x6de -Cyrillic_hardsign = 0x6df -Cyrillic_YU = 0x6e0 -Cyrillic_A = 0x6e1 -Cyrillic_BE = 0x6e2 -Cyrillic_TSE = 0x6e3 -Cyrillic_DE = 0x6e4 -Cyrillic_IE = 0x6e5 -Cyrillic_EF = 0x6e6 -Cyrillic_GHE = 0x6e7 -Cyrillic_HA = 0x6e8 -Cyrillic_I = 0x6e9 -Cyrillic_SHORTI = 0x6ea -Cyrillic_KA = 0x6eb -Cyrillic_EL = 0x6ec -Cyrillic_EM = 0x6ed -Cyrillic_EN = 0x6ee -Cyrillic_O = 0x6ef -Cyrillic_PE = 0x6f0 -Cyrillic_YA = 0x6f1 -Cyrillic_ER = 0x6f2 -Cyrillic_ES = 0x6f3 -Cyrillic_TE = 0x6f4 -Cyrillic_U = 0x6f5 -Cyrillic_ZHE = 0x6f6 -Cyrillic_VE = 0x6f7 -Cyrillic_SOFTSIGN = 0x6f8 -Cyrillic_YERU = 0x6f9 -Cyrillic_ZE = 0x6fa -Cyrillic_SHA = 0x6fb -Cyrillic_E = 0x6fc -Cyrillic_SHCHA = 0x6fd -Cyrillic_CHE = 0x6fe -Cyrillic_HARDSIGN = 0x6ff -Greek_ALPHAaccent = 0x7a1 -Greek_EPSILONaccent = 0x7a2 -Greek_ETAaccent = 0x7a3 -Greek_IOTAaccent = 0x7a4 -Greek_IOTAdiaeresis = 0x7a5 -Greek_OMICRONaccent = 0x7a7 -Greek_UPSILONaccent = 0x7a8 -Greek_UPSILONdieresis = 0x7a9 -Greek_OMEGAaccent = 0x7ab -Greek_accentdieresis = 0x7ae -Greek_horizbar = 0x7af -Greek_alphaaccent = 0x7b1 -Greek_epsilonaccent = 0x7b2 -Greek_etaaccent = 0x7b3 -Greek_iotaaccent = 0x7b4 -Greek_iotadieresis = 0x7b5 -Greek_iotaaccentdieresis = 0x7b6 -Greek_omicronaccent = 0x7b7 -Greek_upsilonaccent = 0x7b8 -Greek_upsilondieresis = 0x7b9 -Greek_upsilonaccentdieresis = 0x7ba -Greek_omegaaccent = 0x7bb -Greek_ALPHA = 0x7c1 -Greek_BETA = 0x7c2 -Greek_GAMMA = 0x7c3 -Greek_DELTA = 0x7c4 -Greek_EPSILON = 0x7c5 -Greek_ZETA = 0x7c6 -Greek_ETA = 0x7c7 -Greek_THETA = 0x7c8 -Greek_IOTA = 0x7c9 -Greek_KAPPA = 0x7ca -Greek_LAMDA = 0x7cb -Greek_LAMBDA = 0x7cb -Greek_MU = 0x7cc -Greek_NU = 0x7cd -Greek_XI = 0x7ce -Greek_OMICRON = 0x7cf -Greek_PI = 0x7d0 -Greek_RHO = 0x7d1 -Greek_SIGMA = 0x7d2 -Greek_TAU = 0x7d4 -Greek_UPSILON = 0x7d5 -Greek_PHI = 0x7d6 -Greek_CHI = 0x7d7 -Greek_PSI = 0x7d8 -Greek_OMEGA = 0x7d9 -Greek_alpha = 0x7e1 -Greek_beta = 0x7e2 -Greek_gamma = 0x7e3 -Greek_delta = 0x7e4 -Greek_epsilon = 0x7e5 -Greek_zeta = 0x7e6 -Greek_eta = 0x7e7 -Greek_theta = 0x7e8 -Greek_iota = 0x7e9 -Greek_kappa = 0x7ea -Greek_lamda = 0x7eb -Greek_lambda = 0x7eb -Greek_mu = 0x7ec -Greek_nu = 0x7ed -Greek_xi = 0x7ee -Greek_omicron = 0x7ef -Greek_pi = 0x7f0 -Greek_rho = 0x7f1 -Greek_sigma = 0x7f2 -Greek_finalsmallsigma = 0x7f3 -Greek_tau = 0x7f4 -Greek_upsilon = 0x7f5 -Greek_phi = 0x7f6 -Greek_chi = 0x7f7 -Greek_psi = 0x7f8 -Greek_omega = 0x7f9 -Greek_switch = 0xFF7E -leftradical = 0x8a1 -topleftradical = 0x8a2 -horizconnector = 0x8a3 -topintegral = 0x8a4 -botintegral = 0x8a5 -vertconnector = 0x8a6 -topleftsqbracket = 0x8a7 -botleftsqbracket = 0x8a8 -toprightsqbracket = 0x8a9 -botrightsqbracket = 0x8aa -topleftparens = 0x8ab -botleftparens = 0x8ac -toprightparens = 0x8ad -botrightparens = 0x8ae -leftmiddlecurlybrace = 0x8af -rightmiddlecurlybrace = 0x8b0 -topleftsummation = 0x8b1 -botleftsummation = 0x8b2 -topvertsummationconnector = 0x8b3 -botvertsummationconnector = 0x8b4 -toprightsummation = 0x8b5 -botrightsummation = 0x8b6 -rightmiddlesummation = 0x8b7 -lessthanequal = 0x8bc -notequal = 0x8bd -greaterthanequal = 0x8be -integral = 0x8bf -therefore = 0x8c0 -variation = 0x8c1 -infinity = 0x8c2 -nabla = 0x8c5 -approximate = 0x8c8 -similarequal = 0x8c9 -ifonlyif = 0x8cd -implies = 0x8ce -identical = 0x8cf -radical = 0x8d6 -includedin = 0x8da -includes = 0x8db -intersection = 0x8dc -union = 0x8dd -logicaland = 0x8de -logicalor = 0x8df -partialderivative = 0x8ef -function = 0x8f6 -leftarrow = 0x8fb -uparrow = 0x8fc -rightarrow = 0x8fd -downarrow = 0x8fe -blank = 0x9df -soliddiamond = 0x9e0 -checkerboard = 0x9e1 -ht = 0x9e2 -ff = 0x9e3 -cr = 0x9e4 -lf = 0x9e5 -nl = 0x9e8 -vt = 0x9e9 -lowrightcorner = 0x9ea -uprightcorner = 0x9eb -upleftcorner = 0x9ec -lowleftcorner = 0x9ed -crossinglines = 0x9ee -horizlinescan1 = 0x9ef -horizlinescan3 = 0x9f0 -horizlinescan5 = 0x9f1 -horizlinescan7 = 0x9f2 -horizlinescan9 = 0x9f3 -leftt = 0x9f4 -rightt = 0x9f5 -bott = 0x9f6 -topt = 0x9f7 -vertbar = 0x9f8 -emspace = 0xaa1 -enspace = 0xaa2 -em3space = 0xaa3 -em4space = 0xaa4 -digitspace = 0xaa5 -punctspace = 0xaa6 -thinspace = 0xaa7 -hairspace = 0xaa8 -emdash = 0xaa9 -endash = 0xaaa -signifblank = 0xaac -ellipsis = 0xaae -doubbaselinedot = 0xaaf -onethird = 0xab0 -twothirds = 0xab1 -onefifth = 0xab2 -twofifths = 0xab3 -threefifths = 0xab4 -fourfifths = 0xab5 -onesixth = 0xab6 -fivesixths = 0xab7 -careof = 0xab8 -figdash = 0xabb -leftanglebracket = 0xabc -decimalpoint = 0xabd -rightanglebracket = 0xabe -marker = 0xabf -oneeighth = 0xac3 -threeeighths = 0xac4 -fiveeighths = 0xac5 -seveneighths = 0xac6 -trademark = 0xac9 -signaturemark = 0xaca -trademarkincircle = 0xacb -leftopentriangle = 0xacc -rightopentriangle = 0xacd -emopencircle = 0xace -emopenrectangle = 0xacf -leftsinglequotemark = 0xad0 -rightsinglequotemark = 0xad1 -leftdoublequotemark = 0xad2 -rightdoublequotemark = 0xad3 -prescription = 0xad4 -minutes = 0xad6 -seconds = 0xad7 -latincross = 0xad9 -hexagram = 0xada -filledrectbullet = 0xadb -filledlefttribullet = 0xadc -filledrighttribullet = 0xadd -emfilledcircle = 0xade -emfilledrect = 0xadf -enopencircbullet = 0xae0 -enopensquarebullet = 0xae1 -openrectbullet = 0xae2 -opentribulletup = 0xae3 -opentribulletdown = 0xae4 -openstar = 0xae5 -enfilledcircbullet = 0xae6 -enfilledsqbullet = 0xae7 -filledtribulletup = 0xae8 -filledtribulletdown = 0xae9 -leftpointer = 0xaea -rightpointer = 0xaeb -club = 0xaec -diamond = 0xaed -heart = 0xaee -maltesecross = 0xaf0 -dagger = 0xaf1 -doubledagger = 0xaf2 -checkmark = 0xaf3 -ballotcross = 0xaf4 -musicalsharp = 0xaf5 -musicalflat = 0xaf6 -malesymbol = 0xaf7 -femalesymbol = 0xaf8 -telephone = 0xaf9 -telephonerecorder = 0xafa -phonographcopyright = 0xafb -caret = 0xafc -singlelowquotemark = 0xafd -doublelowquotemark = 0xafe -cursor = 0xaff -leftcaret = 0xba3 -rightcaret = 0xba6 -downcaret = 0xba8 -upcaret = 0xba9 -overbar = 0xbc0 -downtack = 0xbc2 -upshoe = 0xbc3 -downstile = 0xbc4 -underbar = 0xbc6 -jot = 0xbca -quad = 0xbcc -uptack = 0xbce -circle = 0xbcf -upstile = 0xbd3 -downshoe = 0xbd6 -rightshoe = 0xbd8 -leftshoe = 0xbda -lefttack = 0xbdc -righttack = 0xbfc -hebrew_doublelowline = 0xcdf -hebrew_aleph = 0xce0 -hebrew_bet = 0xce1 -hebrew_beth = 0xce1 -hebrew_gimel = 0xce2 -hebrew_gimmel = 0xce2 -hebrew_dalet = 0xce3 -hebrew_daleth = 0xce3 -hebrew_he = 0xce4 -hebrew_waw = 0xce5 -hebrew_zain = 0xce6 -hebrew_zayin = 0xce6 -hebrew_chet = 0xce7 -hebrew_het = 0xce7 -hebrew_tet = 0xce8 -hebrew_teth = 0xce8 -hebrew_yod = 0xce9 -hebrew_finalkaph = 0xcea -hebrew_kaph = 0xceb -hebrew_lamed = 0xcec -hebrew_finalmem = 0xced -hebrew_mem = 0xcee -hebrew_finalnun = 0xcef -hebrew_nun = 0xcf0 -hebrew_samech = 0xcf1 -hebrew_samekh = 0xcf1 -hebrew_ayin = 0xcf2 -hebrew_finalpe = 0xcf3 -hebrew_pe = 0xcf4 -hebrew_finalzade = 0xcf5 -hebrew_finalzadi = 0xcf5 -hebrew_zade = 0xcf6 -hebrew_zadi = 0xcf6 -hebrew_qoph = 0xcf7 -hebrew_kuf = 0xcf7 -hebrew_resh = 0xcf8 -hebrew_shin = 0xcf9 -hebrew_taw = 0xcfa -hebrew_taf = 0xcfa -Hebrew_switch = 0xFF7E -Thai_kokai = 0xda1 -Thai_khokhai = 0xda2 -Thai_khokhuat = 0xda3 -Thai_khokhwai = 0xda4 -Thai_khokhon = 0xda5 -Thai_khorakhang = 0xda6 -Thai_ngongu = 0xda7 -Thai_chochan = 0xda8 -Thai_choching = 0xda9 -Thai_chochang = 0xdaa -Thai_soso = 0xdab -Thai_chochoe = 0xdac -Thai_yoying = 0xdad -Thai_dochada = 0xdae -Thai_topatak = 0xdaf -Thai_thothan = 0xdb0 -Thai_thonangmontho = 0xdb1 -Thai_thophuthao = 0xdb2 -Thai_nonen = 0xdb3 -Thai_dodek = 0xdb4 -Thai_totao = 0xdb5 -Thai_thothung = 0xdb6 -Thai_thothahan = 0xdb7 -Thai_thothong = 0xdb8 -Thai_nonu = 0xdb9 -Thai_bobaimai = 0xdba -Thai_popla = 0xdbb -Thai_phophung = 0xdbc -Thai_fofa = 0xdbd -Thai_phophan = 0xdbe -Thai_fofan = 0xdbf -Thai_phosamphao = 0xdc0 -Thai_moma = 0xdc1 -Thai_yoyak = 0xdc2 -Thai_rorua = 0xdc3 -Thai_ru = 0xdc4 -Thai_loling = 0xdc5 -Thai_lu = 0xdc6 -Thai_wowaen = 0xdc7 -Thai_sosala = 0xdc8 -Thai_sorusi = 0xdc9 -Thai_sosua = 0xdca -Thai_hohip = 0xdcb -Thai_lochula = 0xdcc -Thai_oang = 0xdcd -Thai_honokhuk = 0xdce -Thai_paiyannoi = 0xdcf -Thai_saraa = 0xdd0 -Thai_maihanakat = 0xdd1 -Thai_saraaa = 0xdd2 -Thai_saraam = 0xdd3 -Thai_sarai = 0xdd4 -Thai_saraii = 0xdd5 -Thai_saraue = 0xdd6 -Thai_sarauee = 0xdd7 -Thai_sarau = 0xdd8 -Thai_sarauu = 0xdd9 -Thai_phinthu = 0xdda -Thai_maihanakat_maitho = 0xdde -Thai_baht = 0xddf -Thai_sarae = 0xde0 -Thai_saraae = 0xde1 -Thai_sarao = 0xde2 -Thai_saraaimaimuan = 0xde3 -Thai_saraaimaimalai = 0xde4 -Thai_lakkhangyao = 0xde5 -Thai_maiyamok = 0xde6 -Thai_maitaikhu = 0xde7 -Thai_maiek = 0xde8 -Thai_maitho = 0xde9 -Thai_maitri = 0xdea -Thai_maichattawa = 0xdeb -Thai_thanthakhat = 0xdec -Thai_nikhahit = 0xded -Thai_leksun = 0xdf0 -Thai_leknung = 0xdf1 -Thai_leksong = 0xdf2 -Thai_leksam = 0xdf3 -Thai_leksi = 0xdf4 -Thai_lekha = 0xdf5 -Thai_lekhok = 0xdf6 -Thai_lekchet = 0xdf7 -Thai_lekpaet = 0xdf8 -Thai_lekkao = 0xdf9 -Hangul = 0xff31 -Hangul_Start = 0xff32 -Hangul_End = 0xff33 -Hangul_Hanja = 0xff34 -Hangul_Jamo = 0xff35 -Hangul_Romaja = 0xff36 -Hangul_Codeinput = 0xff37 -Hangul_Jeonja = 0xff38 -Hangul_Banja = 0xff39 -Hangul_PreHanja = 0xff3a -Hangul_PostHanja = 0xff3b -Hangul_SingleCandidate = 0xff3c -Hangul_MultipleCandidate = 0xff3d -Hangul_PreviousCandidate = 0xff3e -Hangul_Special = 0xff3f -Hangul_switch = 0xFF7E -Hangul_Kiyeog = 0xea1 -Hangul_SsangKiyeog = 0xea2 -Hangul_KiyeogSios = 0xea3 -Hangul_Nieun = 0xea4 -Hangul_NieunJieuj = 0xea5 -Hangul_NieunHieuh = 0xea6 -Hangul_Dikeud = 0xea7 -Hangul_SsangDikeud = 0xea8 -Hangul_Rieul = 0xea9 -Hangul_RieulKiyeog = 0xeaa -Hangul_RieulMieum = 0xeab -Hangul_RieulPieub = 0xeac -Hangul_RieulSios = 0xead -Hangul_RieulTieut = 0xeae -Hangul_RieulPhieuf = 0xeaf -Hangul_RieulHieuh = 0xeb0 -Hangul_Mieum = 0xeb1 -Hangul_Pieub = 0xeb2 -Hangul_SsangPieub = 0xeb3 -Hangul_PieubSios = 0xeb4 -Hangul_Sios = 0xeb5 -Hangul_SsangSios = 0xeb6 -Hangul_Ieung = 0xeb7 -Hangul_Jieuj = 0xeb8 -Hangul_SsangJieuj = 0xeb9 -Hangul_Cieuc = 0xeba -Hangul_Khieuq = 0xebb -Hangul_Tieut = 0xebc -Hangul_Phieuf = 0xebd -Hangul_Hieuh = 0xebe -Hangul_A = 0xebf -Hangul_AE = 0xec0 -Hangul_YA = 0xec1 -Hangul_YAE = 0xec2 -Hangul_EO = 0xec3 -Hangul_E = 0xec4 -Hangul_YEO = 0xec5 -Hangul_YE = 0xec6 -Hangul_O = 0xec7 -Hangul_WA = 0xec8 -Hangul_WAE = 0xec9 -Hangul_OE = 0xeca -Hangul_YO = 0xecb -Hangul_U = 0xecc -Hangul_WEO = 0xecd -Hangul_WE = 0xece -Hangul_WI = 0xecf -Hangul_YU = 0xed0 -Hangul_EU = 0xed1 -Hangul_YI = 0xed2 -Hangul_I = 0xed3 -Hangul_J_Kiyeog = 0xed4 -Hangul_J_SsangKiyeog = 0xed5 -Hangul_J_KiyeogSios = 0xed6 -Hangul_J_Nieun = 0xed7 -Hangul_J_NieunJieuj = 0xed8 -Hangul_J_NieunHieuh = 0xed9 -Hangul_J_Dikeud = 0xeda -Hangul_J_Rieul = 0xedb -Hangul_J_RieulKiyeog = 0xedc -Hangul_J_RieulMieum = 0xedd -Hangul_J_RieulPieub = 0xede -Hangul_J_RieulSios = 0xedf -Hangul_J_RieulTieut = 0xee0 -Hangul_J_RieulPhieuf = 0xee1 -Hangul_J_RieulHieuh = 0xee2 -Hangul_J_Mieum = 0xee3 -Hangul_J_Pieub = 0xee4 -Hangul_J_PieubSios = 0xee5 -Hangul_J_Sios = 0xee6 -Hangul_J_SsangSios = 0xee7 -Hangul_J_Ieung = 0xee8 -Hangul_J_Jieuj = 0xee9 -Hangul_J_Cieuc = 0xeea -Hangul_J_Khieuq = 0xeeb -Hangul_J_Tieut = 0xeec -Hangul_J_Phieuf = 0xeed -Hangul_J_Hieuh = 0xeee -Hangul_RieulYeorinHieuh = 0xeef -Hangul_SunkyeongeumMieum = 0xef0 -Hangul_SunkyeongeumPieub = 0xef1 -Hangul_PanSios = 0xef2 -Hangul_KkogjiDalrinIeung = 0xef3 -Hangul_SunkyeongeumPhieuf = 0xef4 -Hangul_YeorinHieuh = 0xef5 -Hangul_AraeA = 0xef6 -Hangul_AraeAE = 0xef7 -Hangul_J_PanSios = 0xef8 -Hangul_J_KkogjiDalrinIeung = 0xef9 -Hangul_J_YeorinHieuh = 0xefa -Korean_Won = 0xeff +import sys +import warnings + +from ..module import get_introspection_module + +Gdk = get_introspection_module('Gdk') + +warnings.warn('keysyms has been deprecated. Please use Gdk.KEY_<name> instead.', + RuntimeWarning) + +_modname = globals()['__name__'] +_keysyms = sys.modules[_modname] + +for name in dir(Gdk): + if name.startswith('KEY_'): + target = name[4:] + if target[0] in '0123456789': + target = '_' + target + value = getattr(Gdk, name) + setattr(_keysyms, target, value) + + +# Not found in Gdk but left for compatibility. Armenian_eternity = 0x14a1 Armenian_section_sign = 0x14a2 -Armenian_full_stop = 0x14a3 -Armenian_verjaket = 0x14a3 -Armenian_parenright = 0x14a4 Armenian_parenleft = 0x14a5 Armenian_guillemotright = 0x14a6 Armenian_guillemotleft = 0x14a7 Armenian_em_dash = 0x14a8 Armenian_dot = 0x14a9 Armenian_mijaket = 0x14a9 -Armenian_separation_mark = 0x14aa -Armenian_but = 0x14aa Armenian_comma = 0x14ab Armenian_en_dash = 0x14ac -Armenian_hyphen = 0x14ad -Armenian_yentamna = 0x14ad Armenian_ellipsis = 0x14ae -Armenian_exclam = 0x14af -Armenian_amanak = 0x14af -Armenian_accent = 0x14b0 -Armenian_shesht = 0x14b0 -Armenian_question = 0x14b1 -Armenian_paruyk = 0x14b1 -Armenian_AYB = 0x14b2 -Armenian_ayb = 0x14b3 -Armenian_BEN = 0x14b4 -Armenian_ben = 0x14b5 -Armenian_GIM = 0x14b6 -Armenian_gim = 0x14b7 -Armenian_DA = 0x14b8 -Armenian_da = 0x14b9 -Armenian_YECH = 0x14ba -Armenian_yech = 0x14bb -Armenian_ZA = 0x14bc -Armenian_za = 0x14bd -Armenian_E = 0x14be -Armenian_e = 0x14bf -Armenian_AT = 0x14c0 -Armenian_at = 0x14c1 -Armenian_TO = 0x14c2 -Armenian_to = 0x14c3 -Armenian_ZHE = 0x14c4 -Armenian_zhe = 0x14c5 -Armenian_INI = 0x14c6 -Armenian_ini = 0x14c7 -Armenian_LYUN = 0x14c8 -Armenian_lyun = 0x14c9 -Armenian_KHE = 0x14ca -Armenian_khe = 0x14cb -Armenian_TSA = 0x14cc -Armenian_tsa = 0x14cd -Armenian_KEN = 0x14ce -Armenian_ken = 0x14cf -Armenian_HO = 0x14d0 -Armenian_ho = 0x14d1 -Armenian_DZA = 0x14d2 -Armenian_dza = 0x14d3 -Armenian_GHAT = 0x14d4 -Armenian_ghat = 0x14d5 -Armenian_TCHE = 0x14d6 -Armenian_tche = 0x14d7 -Armenian_MEN = 0x14d8 -Armenian_men = 0x14d9 -Armenian_HI = 0x14da -Armenian_hi = 0x14db -Armenian_NU = 0x14dc -Armenian_nu = 0x14dd -Armenian_SHA = 0x14de -Armenian_sha = 0x14df -Armenian_VO = 0x14e0 -Armenian_vo = 0x14e1 -Armenian_CHA = 0x14e2 -Armenian_cha = 0x14e3 -Armenian_PE = 0x14e4 -Armenian_pe = 0x14e5 -Armenian_JE = 0x14e6 -Armenian_je = 0x14e7 -Armenian_RA = 0x14e8 -Armenian_ra = 0x14e9 -Armenian_SE = 0x14ea -Armenian_se = 0x14eb -Armenian_VEV = 0x14ec -Armenian_vev = 0x14ed -Armenian_TYUN = 0x14ee -Armenian_tyun = 0x14ef -Armenian_RE = 0x14f0 -Armenian_re = 0x14f1 -Armenian_TSO = 0x14f2 -Armenian_tso = 0x14f3 -Armenian_VYUN = 0x14f4 -Armenian_vyun = 0x14f5 -Armenian_PYUR = 0x14f6 -Armenian_pyur = 0x14f7 -Armenian_KE = 0x14f8 -Armenian_ke = 0x14f9 -Armenian_O = 0x14fa -Armenian_o = 0x14fb -Armenian_FE = 0x14fc -Armenian_fe = 0x14fd -Armenian_apostrophe = 0x14fe -Armenian_ligature_ew = 0x14ff -Georgian_an = 0x15d0 -Georgian_ban = 0x15d1 -Georgian_gan = 0x15d2 -Georgian_don = 0x15d3 -Georgian_en = 0x15d4 -Georgian_vin = 0x15d5 -Georgian_zen = 0x15d6 -Georgian_tan = 0x15d7 -Georgian_in = 0x15d8 -Georgian_kan = 0x15d9 -Georgian_las = 0x15da -Georgian_man = 0x15db -Georgian_nar = 0x15dc -Georgian_on = 0x15dd -Georgian_par = 0x15de -Georgian_zhar = 0x15df -Georgian_rae = 0x15e0 -Georgian_san = 0x15e1 -Georgian_tar = 0x15e2 -Georgian_un = 0x15e3 -Georgian_phar = 0x15e4 -Georgian_khar = 0x15e5 -Georgian_ghan = 0x15e6 -Georgian_qar = 0x15e7 -Georgian_shin = 0x15e8 -Georgian_chin = 0x15e9 -Georgian_can = 0x15ea -Georgian_jil = 0x15eb -Georgian_cil = 0x15ec -Georgian_char = 0x15ed -Georgian_xan = 0x15ee -Georgian_jhan = 0x15ef -Georgian_hae = 0x15f0 -Georgian_he = 0x15f1 -Georgian_hie = 0x15f2 -Georgian_we = 0x15f3 -Georgian_har = 0x15f4 -Georgian_hoe = 0x15f5 -Georgian_fi = 0x15f6 -EcuSign = 0x20a0 -ColonSign = 0x20a1 -CruzeiroSign = 0x20a2 -FFrancSign = 0x20a3 -LiraSign = 0x20a4 -MillSign = 0x20a5 -NairaSign = 0x20a6 -PesetaSign = 0x20a7 -RupeeSign = 0x20a8 -WonSign = 0x20a9 -NewSheqelSign = 0x20aa -DongSign = 0x20ab -EuroSign = 0x20ac diff --git a/gi/overrides/meson.build b/gi/overrides/meson.build new file mode 100644 index 0000000..6ff073f --- /dev/null +++ b/gi/overrides/meson.build @@ -0,0 +1,15 @@ +python_sources = [ + 'GLib.py', + 'Gtk.py', + 'Gdk.py', + 'GdkPixbuf.py', + 'GObject.py', + 'Gio.py', + 'GIMarshallingTests.py', + 'Pango.py', + 'keysyms.py', + '__init__.py'] + +python.install_sources(python_sources, + subdir : join_paths('gi', 'overrides') +) diff --git a/gi/_gobject/pygboxed.c b/gi/pygboxed.c index 541e77b..595f815 100644 --- a/gi/_gobject/pygboxed.c +++ b/gi/pygboxed.c @@ -15,78 +15,95 @@ * 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 + * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif +#include <config.h> -#include <pyglib.h> -#include "pygobject-private.h" -#include "pygboxed.h" +#include <Python.h> +#include <glib-object.h> -#include "pygi.h" +#include "pygboxed.h" +#include "pygi-type.h" +#include "pygi-type.h" +#include "pygi-util.h" GQuark pygboxed_type_key; -GQuark pygboxed_marshal_key; -PYGLIB_DEFINE_TYPE("gobject.GBoxed", PyGBoxed_Type, PyGBoxed); +PYGI_DEFINE_TYPE("gobject.GBoxed", PyGBoxed_Type, PyGBoxed); static void -pyg_boxed_dealloc(PyGBoxed *self) +gboxed_dealloc(PyGBoxed *self) { - if (self->free_on_dealloc && self->boxed) { - PyGILState_STATE state = pyglib_gil_state_ensure(); - g_boxed_free(self->gtype, self->boxed); - pyglib_gil_state_release(state); + if (self->free_on_dealloc && pyg_boxed_get_ptr (self)) { + PyGILState_STATE state = PyGILState_Ensure(); + g_boxed_free (self->gtype, pyg_boxed_get_ptr (self)); + PyGILState_Release(state); } Py_TYPE(self)->tp_free((PyObject *)self); } static PyObject* -pyg_boxed_richcompare(PyObject *self, PyObject *other, int op) +gboxed_richcompare(PyObject *self, PyObject *other, int op) { 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); + return pyg_ptr_richcompare (pyg_boxed_get_ptr (self), + pyg_boxed_get_ptr (other), + op); else { Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } } - -static long -pyg_boxed_hash(PyGBoxed *self) +static Py_hash_t +gboxed_hash(PyGBoxed *self) { - return (long)self->boxed; + return (Py_hash_t)(gintptr)(pyg_boxed_get_ptr (self)); } static PyObject * -pyg_boxed_repr(PyGBoxed *self) +gboxed_repr(PyGBoxed *boxed) { - gchar buf[128]; + PyObject *module, *repr, *self = (PyObject *)boxed; + gchar *module_str, *namespace; + + module = PyObject_GetAttrString (self, "__module__"); + if (module == NULL) + return NULL; + + if (!PyUnicode_Check (module)) { + Py_DECREF (module); + return NULL; + } + + module_str = PyUnicode_AsUTF8 (module); + namespace = g_strrstr (module_str, "."); + if (namespace == NULL) { + namespace = module_str; + } else { + namespace += 1; + } - g_snprintf(buf, sizeof(buf), "<%s at 0x%lx>", g_type_name(self->gtype), - (long)self->boxed); - return PYGLIB_PyUnicode_FromString(buf); + repr = PyUnicode_FromFormat ("<%s.%s object at %p (%s at %p)>", + namespace, Py_TYPE (self)->tp_name, + self, g_type_name (boxed->gtype), + pyg_boxed_get_ptr (boxed)); + Py_DECREF (module); + return repr; } static int -pyg_boxed_init(PyGBoxed *self, PyObject *args, PyObject *kwargs) +gboxed_init(PyGBoxed *self, PyObject *args, PyObject *kwargs) { gchar buf[512]; if (!PyArg_ParseTuple(args, ":GBoxed.__init__")) return -1; - self->boxed = NULL; + pyg_boxed_set_ptr (self, NULL); self->gtype = 0; self->free_on_dealloc = FALSE; @@ -97,27 +114,25 @@ pyg_boxed_init(PyGBoxed *self, PyObject *args, PyObject *kwargs) } static void -pyg_boxed_free(PyObject *op) +gboxed_free(PyObject *op) { PyObject_FREE(op); } static PyObject * -pyg_boxed_copy(PyGBoxed *self) +gboxed_copy(PyGBoxed *self) { - return pyg_boxed_new (self->gtype, self->boxed, TRUE, TRUE); + return pygi_gboxed_new (self->gtype, pyg_boxed_get_ptr (self), TRUE, TRUE); } - - static PyMethodDef pygboxed_methods[] = { - { "copy", (PyCFunction) pyg_boxed_copy, METH_NOARGS }, + { "copy", (PyCFunction) gboxed_copy, METH_NOARGS }, { NULL, NULL, 0 } }; /** - * pyg_register_boxed: + * pygi_register_gboxed: * @dict: the module dictionary to store the wrapper class. * @class_name: the Python name for the wrapper class. * @boxed_type: the GType of the boxed type being wrapped. @@ -128,8 +143,8 @@ static PyMethodDef pygboxed_methods[] = { * will be stored in the provided module dictionary. */ void -pyg_register_boxed(PyObject *dict, const gchar *class_name, - GType boxed_type, PyTypeObject *type) +pygi_register_gboxed (PyObject *dict, const gchar *class_name, + GType boxed_type, PyTypeObject *type) { PyObject *o; @@ -137,9 +152,10 @@ pyg_register_boxed(PyObject *dict, const gchar *class_name, g_return_if_fail(class_name != NULL); g_return_if_fail(boxed_type != 0); - if (!type->tp_dealloc) type->tp_dealloc = (destructor)pyg_boxed_dealloc; + if (!type->tp_dealloc) type->tp_dealloc = (destructor)gboxed_dealloc; - Py_TYPE(type) = &PyType_Type; + Py_SET_TYPE(type, &PyType_Type); + g_assert (Py_TYPE (&PyGBoxed_Type) != NULL); type->tp_base = &PyGBoxed_Type; if (PyType_Ready(type) < 0) { @@ -157,7 +173,7 @@ pyg_register_boxed(PyObject *dict, const gchar *class_name, } /** - * pyg_boxed_new: + * pygi_gboxed_new: * @boxed_type: the GType of the boxed value. * @boxed: the boxed value. * @copy_boxed: whether the new boxed wrapper should hold a copy of the value. @@ -169,11 +185,11 @@ pyg_register_boxed(PyObject *dict, const gchar *class_name, * wrapper will be freed when the wrapper is deallocated. If * @copy_boxed is True, then @own_ref must also be True. * - * Returns: the boxed wrapper. + * Returns: the boxed wrapper or %NULL and sets an exception. */ PyObject * -pyg_boxed_new(GType boxed_type, gpointer boxed, gboolean copy_boxed, - gboolean own_ref) +pygi_gboxed_new (GType boxed_type, gpointer boxed, gboolean copy_boxed, + gboolean own_ref) { PyGILState_STATE state; PyGBoxed *self; @@ -182,11 +198,11 @@ pyg_boxed_new(GType boxed_type, gpointer boxed, gboolean copy_boxed, g_return_val_if_fail(boxed_type != 0, NULL); g_return_val_if_fail(!copy_boxed || (copy_boxed && own_ref), NULL); - state = pyglib_gil_state_ensure(); + state = PyGILState_Ensure(); if (!boxed) { Py_INCREF(Py_None); - pyglib_gil_state_release(state); + PyGILState_Release(state); return Py_None; } @@ -198,38 +214,58 @@ pyg_boxed_new(GType boxed_type, gpointer boxed, gboolean copy_boxed, if (!tp) tp = (PyTypeObject *)&PyGBoxed_Type; /* fallback */ + if (!PyType_IsSubtype (tp, &PyGBoxed_Type)) { + PyErr_Format (PyExc_RuntimeError, "%s isn't a GBoxed", tp->tp_name); + PyGILState_Release (state); + return NULL; + } + self = (PyGBoxed *)tp->tp_alloc(tp, 0); if (self == NULL) { - pyglib_gil_state_release(state); + PyGILState_Release(state); return NULL; } if (copy_boxed) boxed = g_boxed_copy(boxed_type, boxed); - self->boxed = boxed; + pyg_boxed_set_ptr (self, boxed); self->gtype = boxed_type; self->free_on_dealloc = own_ref; - pyglib_gil_state_release(state); + PyGILState_Release(state); return (PyObject *)self; } -void -pygobject_boxed_register_types(PyObject *d) +/** + * Returns 0 on success, or -1 and sets an exception. + */ +int +pygi_gboxed_register_types(PyObject *d) { + PyObject *pygtype; + pygboxed_type_key = g_quark_from_static_string("PyGBoxed::class"); - pygboxed_marshal_key = g_quark_from_static_string("PyGBoxed::marshal"); - PyGBoxed_Type.tp_dealloc = (destructor)pyg_boxed_dealloc; - PyGBoxed_Type.tp_richcompare = pyg_boxed_richcompare; - PyGBoxed_Type.tp_repr = (reprfunc)pyg_boxed_repr; + PyGBoxed_Type.tp_dealloc = (destructor)gboxed_dealloc; + PyGBoxed_Type.tp_richcompare = gboxed_richcompare; + PyGBoxed_Type.tp_repr = (reprfunc)gboxed_repr; PyGBoxed_Type.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE; PyGBoxed_Type.tp_methods = pygboxed_methods; - PyGBoxed_Type.tp_init = (initproc)pyg_boxed_init; - PyGBoxed_Type.tp_free = (freefunc)pyg_boxed_free; - PyGBoxed_Type.tp_hash = (hashfunc)pyg_boxed_hash; - - PYGOBJECT_REGISTER_GTYPE(d, PyGBoxed_Type, "GBoxed", G_TYPE_BOXED); + PyGBoxed_Type.tp_init = (initproc)gboxed_init; + PyGBoxed_Type.tp_free = (freefunc)gboxed_free; + PyGBoxed_Type.tp_hash = (hashfunc)gboxed_hash; + PyGBoxed_Type.tp_alloc = PyType_GenericAlloc; + PyGBoxed_Type.tp_new = PyType_GenericNew; + if (PyType_Ready(&PyGBoxed_Type)) + return -1; + + pygtype = pyg_type_wrapper_new (G_TYPE_POINTER); + PyDict_SetItemString (PyGBoxed_Type.tp_dict, "__gtype__", pygtype); + Py_DECREF (pygtype); + + PyDict_SetItemString(d, "GBoxed", (PyObject *)&PyGBoxed_Type); + + return 0; } diff --git a/gi/_gobject/pygboxed.h b/gi/pygboxed.h index 8433b9d..c1b80bf 100644 --- a/gi/_gobject/pygboxed.h +++ b/gi/pygboxed.h @@ -14,14 +14,21 @@ * 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 + * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ #ifndef __PYGOBJECT_BOXED_H__ #define __PYGOBJECT_BOXED_H__ -void pygobject_boxed_register_types(PyObject *d); +extern GQuark pygboxed_type_key; + +extern PyTypeObject PyGBoxed_Type; + +void pygi_register_gboxed (PyObject *dict, const gchar *class_name, + GType boxed_type, PyTypeObject *type); +PyObject * pygi_gboxed_new (GType boxed_type, gpointer boxed, + gboolean copy_boxed, gboolean own_ref); + +int pygi_gboxed_register_types(PyObject *d); #endif /* __PYGOBJECT_BOXED_H__ */ diff --git a/gi/_gobject/pygenum.c b/gi/pygenum.c index 89e3a06..37495e8 100644 --- a/gi/_gobject/pygenum.c +++ b/gi/pygenum.c @@ -16,31 +16,28 @@ * 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 + * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif - -#include <pyglib.h> -#include "pygobject-private.h" -#include "pygi.h" +#include <config.h> +#include "pygi-type.h" +#include "pygi-util.h" +#include "pygi-type.h" +#include "pygi-basictype.h" #include "pygenum.h" +#include "pygboxed.h" GQuark pygenum_class_key; -PYGLIB_DEFINE_TYPE("gobject.GEnum", PyGEnum_Type, PyGEnum); +PYGI_DEFINE_TYPE("gobject.GEnum", PyGEnum_Type, PyGEnum); static PyObject * pyg_enum_val_new(PyObject* subclass, GType gtype, PyObject *intval) { PyObject *args, *item; args = Py_BuildValue("(O)", intval); - item = (&PYGLIB_PyLong_Type)->tp_new((PyTypeObject*)subclass, args, NULL); + item = (&PyLong_Type)->tp_new((PyTypeObject*)subclass, args, NULL); Py_DECREF(args); if (!item) return NULL; @@ -54,7 +51,7 @@ pyg_enum_richcompare(PyGEnum *self, PyObject *other, int op) { static char warning[256]; - if (!PYGLIB_PyLong_Check(other)) { + if (!PyLong_Check (other)) { Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } @@ -72,29 +69,50 @@ pyg_enum_richcompare(PyGEnum *self, PyObject *other, int op) static PyObject * pyg_enum_repr(PyGEnum *self) { - GEnumClass *enum_class; - const char *value; - guint index; - static char tmp[256]; - long l; + PyObject *module; + GEnumClass *enum_class; + const char *value; + guint index; + char *namespace, *module_str; + static char tmp[256]; + long l; + + module = PyObject_GetAttrString ((PyObject *)self, "__module__"); + if (module == NULL) + return NULL; - enum_class = g_type_class_ref(self->gtype); - g_assert(G_IS_ENUM_CLASS(enum_class)); + if (!PyUnicode_Check (module)) { + Py_DECREF (module); + return NULL; + } - l = PYGLIB_PyLong_AS_LONG(self); - for (index = 0; index < enum_class->n_values; index++) - if (l == enum_class->values[index].value) - break; + enum_class = g_type_class_ref(self->gtype); + g_assert(G_IS_ENUM_CLASS(enum_class)); - value = enum_class->values[index].value_name; - if (value) - sprintf(tmp, "<enum %s of type %s>", value, g_type_name(self->gtype)); - else - sprintf(tmp, "<enum %ld of type %s>", PYGLIB_PyLong_AS_LONG(self), g_type_name(self->gtype)); + l = PyLong_AS_LONG ((PyObject*)self); + for (index = 0; index < enum_class->n_values; index++) + if (l == enum_class->values[index].value) + break; - g_type_class_unref(enum_class); + module_str = PyUnicode_AsUTF8 (module); + namespace = g_strrstr (module_str, "."); + if (namespace == NULL) { + namespace = module_str; + } else { + namespace += 1; + } - return PYGLIB_PyUnicode_FromString(tmp); + value = enum_class->values[index].value_name; + if (value) + sprintf(tmp, "<enum %s of type %s.%s>", value, + namespace, Py_TYPE (self)->tp_name); + else + sprintf(tmp, "<enum %ld of type %s.%s>", PyLong_AS_LONG ((PyObject*)self), + namespace, Py_TYPE (self)->tp_name); + Py_DECREF (module); + g_type_class_unref(enum_class); + + return PyUnicode_FromString (tmp); } static PyObject * @@ -143,7 +161,7 @@ pyg_enum_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) * values might not have been that good", but we need to keep * backward compatibility. */ - if (!PyDict_Check(values) || PyDict_Size(values) > eclass->n_values) { + if (!PyDict_Check(values) || (gsize)PyDict_Size(values) > eclass->n_values) { PyErr_SetString(PyExc_TypeError, "__enum_values__ badly formed"); Py_DECREF(values); g_type_class_unref(eclass); @@ -152,7 +170,7 @@ pyg_enum_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) g_type_class_unref(eclass); - intvalue = PYGLIB_PyLong_FromLong(value); + intvalue = PyLong_FromLong(value); ret = PyDict_GetItem(values, intvalue); Py_DECREF(intvalue); Py_DECREF(values); @@ -182,11 +200,11 @@ pyg_enum_from_gtype (GType gtype, int value) if (!pyclass) pyclass = pyg_enum_add(NULL, g_type_name(gtype), NULL, gtype); if (!pyclass) - return PYGLIB_PyLong_FromLong(value); + return PyLong_FromLong(value); values = PyDict_GetItemString(((PyTypeObject *)pyclass)->tp_dict, "__enum_values__"); - intvalue = PYGLIB_PyLong_FromLong(value); + intvalue = PyLong_FromLong(value); retval = PyDict_GetItem(values, intvalue); if (retval) { Py_INCREF(retval); @@ -213,7 +231,7 @@ pyg_enum_add (PyObject * module, PyGILState_STATE state; PyObject *instance_dict, *stub, *values, *o; GEnumClass *eclass; - int i; + guint i; g_return_val_if_fail(typename != NULL, NULL); if (!g_type_is_a (gtype, G_TYPE_ENUM)) { @@ -222,7 +240,7 @@ pyg_enum_add (PyObject * module, return NULL; } - state = pyglib_gil_state_ensure(); + state = PyGILState_Ensure(); /* Create a new type derived from GEnum. This is the same as: * >>> stub = type(typename, (GEnum,), {}) @@ -234,17 +252,16 @@ pyg_enum_add (PyObject * module, Py_DECREF(instance_dict); if (!stub) { PyErr_SetString(PyExc_RuntimeError, "can't create const"); - pyglib_gil_state_release(state); + PyGILState_Release(state); return NULL; } ((PyTypeObject *)stub)->tp_flags &= ~Py_TPFLAGS_BASETYPE; - ((PyTypeObject *)stub)->tp_new = pyg_enum_new; if (module) PyDict_SetItemString(((PyTypeObject *)stub)->tp_dict, "__module__", - PYGLIB_PyUnicode_FromString(PyModule_GetName(module))); + PyUnicode_FromString (PyModule_GetName(module))); g_type_set_qdata(gtype, pygenum_class_key, stub); @@ -265,7 +282,7 @@ pyg_enum_add (PyObject * module, for (i = 0; i < eclass->n_values; i++) { PyObject *item, *intval; - intval = PYGLIB_PyLong_FromLong(eclass->values[i].value); + intval = PyLong_FromLong(eclass->values[i].value); item = pyg_enum_val_new(stub, gtype, intval); PyDict_SetItem(values, intval, item); Py_DECREF(intval); @@ -287,7 +304,7 @@ pyg_enum_add (PyObject * module, g_type_class_unref(eclass); - pyglib_gil_state_release(state); + PyGILState_Release(state); return stub; } @@ -297,7 +314,7 @@ pyg_enum_reduce(PyObject *self, PyObject *args) if (!PyArg_ParseTuple(args, ":GEnum.__reduce__")) return NULL; - return Py_BuildValue("(O(i)O)", Py_TYPE(self), PYGLIB_PyLong_AsLong(self), + return Py_BuildValue("(O(i)O)", Py_TYPE(self), PyLong_AsLong (self), PyObject_GetAttrString(self, "__dict__")); } @@ -307,13 +324,17 @@ pyg_enum_get_value_name(PyGEnum *self, void *closure) GEnumClass *enum_class; GEnumValue *enum_value; PyObject *retval; + gint intvalue; + + if (!pygi_gint_from_py ((PyObject*) self, &intvalue)) + return NULL; enum_class = g_type_class_ref(self->gtype); g_assert(G_IS_ENUM_CLASS(enum_class)); - enum_value = g_enum_get_value(enum_class, PYGLIB_PyLong_AS_LONG(self)); + enum_value = g_enum_get_value(enum_class, intvalue); - retval = PYGLIB_PyUnicode_FromString(enum_value->value_name); + retval = pygi_utf8_to_py (enum_value->value_name); g_type_class_unref(enum_class); return retval; @@ -325,13 +346,18 @@ pyg_enum_get_value_nick(PyGEnum *self, void *closure) GEnumClass *enum_class; GEnumValue *enum_value; PyObject *retval; + gint intvalue; + + if (!pygi_gint_from_py ((PyObject*) self, &intvalue)) + return NULL; enum_class = g_type_class_ref(self->gtype); g_assert(G_IS_ENUM_CLASS(enum_class)); - enum_value = g_enum_get_value(enum_class, PYGLIB_PyLong_AS_LONG(self)); + enum_value = g_enum_get_value(enum_class, intvalue); + + retval = pygi_utf8_to_py (enum_value->value_nick); - retval = PYGLIB_PyUnicode_FromString(enum_value->value_nick); g_type_class_unref(enum_class); return retval; @@ -349,23 +375,34 @@ static PyGetSetDef pyg_enum_getsets[] = { { NULL, 0, 0 } }; -void -pygobject_enum_register_types(PyObject *d) +/** + * Returns 0 on success, or -1 and sets an exception. + */ +int +pygi_enum_register_types(PyObject *d) { + PyObject *pygtype; + pygenum_class_key = g_quark_from_static_string("PyGEnum::class"); - PyGEnum_Type.tp_base = &PYGLIB_PyLong_Type; -#if PY_VERSION_HEX < 0x03000000 + PyGEnum_Type.tp_base = &PyLong_Type; PyGEnum_Type.tp_new = pyg_enum_new; -#else - PyGEnum_Type.tp_new = PyLong_Type.tp_new; 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; PyGEnum_Type.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE; PyGEnum_Type.tp_richcompare = (richcmpfunc)pyg_enum_richcompare; PyGEnum_Type.tp_methods = pyg_enum_methods; PyGEnum_Type.tp_getset = pyg_enum_getsets; - PYGOBJECT_REGISTER_GTYPE(d, PyGEnum_Type, "GEnum", G_TYPE_ENUM); + PyGEnum_Type.tp_alloc = PyType_GenericAlloc; + if (PyType_Ready(&PyGEnum_Type)) + return -1; + + pygtype = pyg_type_wrapper_new (G_TYPE_ENUM); + PyDict_SetItemString (PyGEnum_Type.tp_dict, "__gtype__", pygtype); + Py_DECREF (pygtype); + + PyDict_SetItemString(d, "GEnum", (PyObject *)&PyGEnum_Type); + + return 0; } diff --git a/gi/pygenum.h b/gi/pygenum.h new file mode 100644 index 0000000..5b46d35 --- /dev/null +++ b/gi/pygenum.h @@ -0,0 +1,47 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- + * pygtk- Python bindings for the GTK toolkit. + * Copyright (C) 1998-2003 James Henstridge + * 2004-2008 Johan Dahlin + * + * 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, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __PYGOBJECT_ENUM_H__ +#define __PYGOBJECT_ENUM_H__ + +extern GQuark pygenum_class_key; + +#define PyGEnum_Check(x) (PyObject_IsInstance((PyObject *)x, (PyObject *)&PyGEnum_Type) && g_type_is_a(((PyGFlags*)x)->gtype, G_TYPE_ENUM)) + +typedef struct { + PyLongObject parent; + int zero_pad; /* must always be 0 */ + GType gtype; +} PyGEnum; + +extern PyTypeObject PyGEnum_Type; + +PyObject * pyg_enum_add (PyObject * module, + const char * type_name, + const char * strip_prefix, + GType gtype); + +PyObject * pyg_enum_from_gtype (GType gtype, + int value); + +gint pyg_enum_get_value (GType enum_type, PyObject *obj, gint *val); + +int pygi_enum_register_types(PyObject *d); + +#endif /* __PYGOBJECT_ENUM_H__ */ diff --git a/gi/_gobject/pygflags.c b/gi/pygflags.c index bdeaae7..df1280f 100644 --- a/gi/_gobject/pygflags.c +++ b/gi/pygflags.c @@ -16,24 +16,20 @@ * 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 + * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif +#include <config.h> -#include <pyglib.h> -#include "pygobject-private.h" +#include "pygi-type.h" +#include "pygi-util.h" +#include "pygi-type.h" #include "pygflags.h" - -#include "pygi.h" +#include "pygboxed.h" GQuark pygflags_class_key; -PYGLIB_DEFINE_TYPE("gobject.GFlags", PyGFlags_Type, PyGFlags); +PYGI_DEFINE_TYPE("gobject.GFlags", PyGFlags_Type, PyGFlags); static PyObject * pyg_flags_val_new(PyObject* subclass, GType gtype, PyObject *intval) @@ -41,7 +37,7 @@ pyg_flags_val_new(PyObject* subclass, GType gtype, PyObject *intval) 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); + item = PyLong_Type.tp_new((PyTypeObject*)subclass, args, NULL); Py_DECREF(args); if (!item) return NULL; @@ -55,7 +51,7 @@ pyg_flags_richcompare(PyGFlags *self, PyObject *other, int op) { static char warning[256]; - if (!PYGLIB_PyLong_Check(other)) { + if (!PyLong_Check (other)) { Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } @@ -75,7 +71,7 @@ generate_repr(GType gtype, guint value) { GFlagsClass *flags_class; char *retval = NULL, *tmp; - int i; + guint i; flags_class = g_type_class_ref(gtype); g_assert(G_IS_FLAGS_CLASS(flags_class)); @@ -106,20 +102,42 @@ generate_repr(GType gtype, guint value) static PyObject * pyg_flags_repr(PyGFlags *self) { - char *tmp, *retval; - PyObject *pyretval; + char *tmp, *retval, *module_str, *namespace; + PyObject *pyretval, *module; + + tmp = generate_repr(self->gtype, (guint)PyLong_AsUnsignedLongMask ((PyObject*)self)); + + module = PyObject_GetAttrString ((PyObject *)self, "__module__"); + if (module == NULL) { + g_free (tmp); + return NULL; + } - tmp = generate_repr(self->gtype, PYGLIB_PyLong_AsUnsignedLong(self)); + if (!PyUnicode_Check (module)) { + g_free (tmp); + Py_DECREF (module); + return NULL; + } + + module_str = PyUnicode_AsUTF8 (module); + namespace = g_strrstr (module_str, "."); + if (namespace == NULL) { + namespace = module_str; + } else { + namespace += 1; + } if (tmp) - retval = g_strdup_printf("<flags %s of type %s>", tmp, - g_type_name(self->gtype)); + retval = g_strdup_printf("<flags %s of type %s.%s>", tmp, + namespace, Py_TYPE (self)->tp_name); else - retval = g_strdup_printf("<flags %ld of type %s>", PYGLIB_PyLong_AsUnsignedLong(self), - g_type_name(self->gtype)); + retval = g_strdup_printf("<flags %ld of type %s.%s>", + PyLong_AsUnsignedLongMask ((PyObject*)self), + namespace, Py_TYPE (self)->tp_name); g_free(tmp); + Py_DECREF (module); - pyretval = PYGLIB_PyUnicode_FromString(retval); + pyretval = PyUnicode_FromString (retval); g_free(retval); return pyretval; @@ -168,7 +186,7 @@ pyg_flags_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) g_type_class_unref(eclass); - pyint = PYGLIB_PyLong_FromUnsignedLong(value); + pyint = PyLong_FromUnsignedLong (value); ret = PyDict_GetItem(values, pyint); if (!ret) { PyErr_Clear(); @@ -191,7 +209,7 @@ pyg_flags_from_gtype (GType gtype, guint value) PyObject *pyclass, *values, *retval, *pyint; if (PyErr_Occurred()) - return PYGLIB_PyLong_FromUnsignedLong(0); + return PyLong_FromUnsignedLong (0); g_return_val_if_fail(gtype != G_TYPE_INVALID, NULL); @@ -206,11 +224,11 @@ pyg_flags_from_gtype (GType gtype, guint value) if (!pyclass) pyclass = pyg_flags_add(NULL, g_type_name(gtype), NULL, gtype); if (!pyclass) - return PYGLIB_PyLong_FromUnsignedLong(value); + return PyLong_FromUnsignedLong (value); values = PyDict_GetItemString(((PyTypeObject *)pyclass)->tp_dict, "__flags_values__"); - pyint = PYGLIB_PyLong_FromUnsignedLong(value); + pyint = PyLong_FromUnsignedLong (value); retval = PyDict_GetItem(values, pyint); if (!retval) { PyErr_Clear(); @@ -238,7 +256,7 @@ pyg_flags_add (PyObject * module, PyGILState_STATE state; PyObject *instance_dict, *stub, *values, *o; GFlagsClass *eclass; - int i; + guint i; g_return_val_if_fail(typename != NULL, NULL); if (!g_type_is_a(gtype, G_TYPE_FLAGS)) { @@ -247,7 +265,7 @@ pyg_flags_add (PyObject * module, return NULL; } - state = pyglib_gil_state_ensure(); + state = PyGILState_Ensure(); /* Create a new type derived from GFlags. This is the same as: * >>> stub = type(typename, (GFlags,), {}) @@ -259,17 +277,16 @@ pyg_flags_add (PyObject * module, Py_DECREF(instance_dict); if (!stub) { PyErr_SetString(PyExc_RuntimeError, "can't create GFlags subtype"); - pyglib_gil_state_release(state); + PyGILState_Release(state); return NULL; } ((PyTypeObject *)stub)->tp_flags &= ~Py_TPFLAGS_BASETYPE; - ((PyTypeObject *)stub)->tp_new = pyg_flags_new; if (module) { PyDict_SetItemString(((PyTypeObject *)stub)->tp_dict, "__module__", - PYGLIB_PyUnicode_FromString(PyModule_GetName(module))); + PyUnicode_FromString (PyModule_GetName(module))); /* Add it to the module name space */ PyModule_AddObject(module, (char*)typename, stub); @@ -288,7 +305,7 @@ pyg_flags_add (PyObject * module, for (i = 0; i < eclass->n_values; i++) { PyObject *item, *intval; - intval = PYGLIB_PyLong_FromUnsignedLong(eclass->values[i].value); + intval = PyLong_FromUnsignedLong (eclass->values[i].value); g_assert(PyErr_Occurred() == NULL); item = pyg_flags_val_new(stub, gtype, intval); PyDict_SetItem(values, intval, item); @@ -311,7 +328,7 @@ pyg_flags_add (PyObject * module, g_type_class_unref(eclass); - pyglib_gil_state_release(state); + PyGILState_Release(state); return stub; } @@ -320,32 +337,32 @@ static PyObject * pyg_flags_and(PyGFlags *a, PyGFlags *b) { if (!PyGFlags_Check(a) || !PyGFlags_Check(b)) - return PYGLIB_PyLong_Type.tp_as_number->nb_and((PyObject*)a, + return PyLong_Type.tp_as_number->nb_and((PyObject*)a, (PyObject*)b); return pyg_flags_from_gtype(a->gtype, - PYGLIB_PyLong_AsUnsignedLong(a) & PYGLIB_PyLong_AsUnsignedLong(b)); + (guint)(PyLong_AsUnsignedLongMask ((PyObject*)a) & PyLong_AsUnsignedLongMask ((PyObject*)b))); } static PyObject * pyg_flags_or(PyGFlags *a, PyGFlags *b) { if (!PyGFlags_Check(a) || !PyGFlags_Check(b)) - return PYGLIB_PyLong_Type.tp_as_number->nb_or((PyObject*)a, + return PyLong_Type.tp_as_number->nb_or((PyObject*)a, (PyObject*)b); - return pyg_flags_from_gtype(a->gtype, PYGLIB_PyLong_AsUnsignedLong(a) | PYGLIB_PyLong_AsUnsignedLong(b)); + return pyg_flags_from_gtype(a->gtype, (guint)(PyLong_AsUnsignedLongMask ((PyObject*)a) | PyLong_AsUnsignedLongMask ((PyObject*)b))); } static PyObject * pyg_flags_xor(PyGFlags *a, PyGFlags *b) { if (!PyGFlags_Check(a) || !PyGFlags_Check(b)) - return PYGLIB_PyLong_Type.tp_as_number->nb_xor((PyObject*)a, + return PyLong_Type.tp_as_number->nb_xor((PyObject*)a, (PyObject*)b); return pyg_flags_from_gtype(a->gtype, - PYGLIB_PyLong_AsUnsignedLong(a) ^ PYGLIB_PyLong_AsUnsignedLong(b)); + (guint)(PyLong_AsUnsignedLongMask ((PyObject*)a) ^ PyLong_AsUnsignedLongMask ((PyObject*)b))); } @@ -368,9 +385,9 @@ 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_AsUnsignedLong(self)); + flags_value = g_flags_get_first_value(flags_class, (guint)PyLong_AsUnsignedLongMask ((PyObject*)self)); if (flags_value) - retval = PYGLIB_PyUnicode_FromString(flags_value->value_name); + retval = PyUnicode_FromString (flags_value->value_name); else { retval = Py_None; Py_INCREF(Py_None); @@ -390,9 +407,9 @@ 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_AsUnsignedLong(self)); + flags_value = g_flags_get_first_value(flags_class, (guint)PyLong_AsUnsignedLongMask ((PyObject*)self)); if (flags_value) - retval = PYGLIB_PyUnicode_FromString(flags_value->value_nick); + retval = PyUnicode_FromString (flags_value->value_nick); else { retval = Py_None; Py_INCREF(Py_None); @@ -407,15 +424,21 @@ pyg_flags_get_value_names(PyGFlags *self, void *closure) { GFlagsClass *flags_class; PyObject *retval; - int i; + guint i; flags_class = g_type_class_ref(self->gtype); g_assert(G_IS_FLAGS_CLASS(flags_class)); retval = PyList_New(0); - for (i = 0; i < flags_class->n_values; i++) - 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)); + for (i = 0; i < flags_class->n_values; i++) { + PyObject *value_name; + + if ((PyLong_AsUnsignedLongMask ((PyObject*)self) & flags_class->values[i].value) == flags_class->values[i].value) { + value_name = PyUnicode_FromString (flags_class->values[i].value_name); + PyList_Append (retval, value_name); + Py_DECREF (value_name); + } + } g_type_class_unref(flags_class); @@ -427,15 +450,15 @@ pyg_flags_get_value_nicks(PyGFlags *self, void *closure) { GFlagsClass *flags_class; PyObject *retval; - int i; + guint i; flags_class = g_type_class_ref(self->gtype); g_assert(G_IS_FLAGS_CLASS(flags_class)); retval = PyList_New(0); for (i = 0; i < flags_class->n_values; i++) - 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); + if ((PyLong_AsUnsignedLongMask ((PyObject*)self) & flags_class->values[i].value) == flags_class->values[i].value) { + PyObject *py_nick = PyUnicode_FromString (flags_class->values[i].value_nick); PyList_Append(retval, py_nick); Py_DECREF (py_nick); } @@ -459,9 +482,6 @@ static PyNumberMethods pyg_flags_as_number = { (binaryfunc)pyg_flags_warn, /* nb_multiply */ (binaryfunc)pyg_flags_warn, /* nb_divide */ (binaryfunc)pyg_flags_warn, /* nb_remainder */ -#if PY_VERSION_HEX < 0x03000000 - (binaryfunc)pyg_flags_warn, /* nb_divmod */ -#endif (ternaryfunc)pyg_flags_warn, /* nb_power */ 0, /* nb_negative */ 0, /* nb_positive */ @@ -475,23 +495,34 @@ static PyNumberMethods pyg_flags_as_number = { (binaryfunc)pyg_flags_or, /* nb_or */ }; -void -pygobject_flags_register_types(PyObject *d) +/** + * Returns 0 on success, or -1 and sets an exception. + */ +int +pygi_flags_register_types(PyObject *d) { + PyObject *pygtype; + pygflags_class_key = g_quark_from_static_string("PyGFlags::class"); - PyGFlags_Type.tp_base = &PYGLIB_PyLong_Type; -#if PY_VERSION_HEX < 0x03000000 + PyGFlags_Type.tp_base = &PyLong_Type; PyGFlags_Type.tp_new = pyg_flags_new; -#else - PyGFlags_Type.tp_new = PyLong_Type.tp_new; - PyGFlags_Type.tp_hash = PyLong_Type.tp_hash; -#endif + PyGFlags_Type.tp_hash = PyLong_Type.tp_hash; PyGFlags_Type.tp_repr = (reprfunc)pyg_flags_repr; PyGFlags_Type.tp_as_number = &pyg_flags_as_number; PyGFlags_Type.tp_str = (reprfunc)pyg_flags_repr; PyGFlags_Type.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE; PyGFlags_Type.tp_richcompare = (richcmpfunc)pyg_flags_richcompare; PyGFlags_Type.tp_getset = pyg_flags_getsets; - PYGOBJECT_REGISTER_GTYPE(d, PyGFlags_Type, "GFlags", G_TYPE_FLAGS); + PyGFlags_Type.tp_alloc = PyType_GenericAlloc; + if (PyType_Ready(&PyGFlags_Type)) + return -1; + + pygtype = pyg_type_wrapper_new (G_TYPE_FLAGS); + PyDict_SetItemString (PyGFlags_Type.tp_dict, "__gtype__", pygtype); + Py_DECREF (pygtype); + + PyDict_SetItemString(d, "GFlags", (PyObject *)&PyGFlags_Type); + + return 0; } diff --git a/gi/pygflags.h b/gi/pygflags.h new file mode 100644 index 0000000..7cff7f2 --- /dev/null +++ b/gi/pygflags.h @@ -0,0 +1,46 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- + * pygtk- Python bindings for the GTK toolkit. + * Copyright (C) 1998-2003 James Henstridge + * 2004-2008 Johan Dahlin + * + * 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, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __PYGOBJECT_FLAGS_H__ +#define __PYGOBJECT_FLAGS_H__ + +extern GQuark pygflags_class_key; + +typedef struct { + PyLongObject parent; + int zero_pad; /* must always be 0 */ + GType gtype; +} PyGFlags; + +extern PyTypeObject PyGFlags_Type; + +#define PyGFlags_Check(x) (PyObject_IsInstance((PyObject *)x, (PyObject *)&PyGFlags_Type) && g_type_is_a(((PyGFlags*)x)->gtype, G_TYPE_FLAGS)) + +extern PyObject * pyg_flags_add (PyObject * module, + const char * type_name, + const char * strip_prefix, + GType gtype); +extern PyObject * pyg_flags_from_gtype (GType gtype, + guint value); + +gint pyg_flags_get_value (GType flag_type, PyObject *obj, guint *val); + +int pygi_flags_register_types(PyObject *d); + +#endif /* __PYGOBJECT_FLAGS_H__ */ diff --git a/gi/pygi-argument.c b/gi/pygi-argument.c index 7d8a837..c5c5bea 100644 --- a/gi/pygi-argument.c +++ b/gi/pygi-argument.c @@ -16,29 +16,35 @@ * 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 + * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ -#include "pygi-private.h" +#include <Python.h> #include <string.h> #include <time.h> -#include <datetime.h> -#include <pygobject.h> -#include <pyglib-python-compat.h> -#include <pyglib.h> +#include "pygobject-internal.h" -#include "pygi-marshal-from-py.h" -#include "pygi-marshal-to-py.h" +#include <pygenum.h> +#include <pygflags.h> +#include "pygi-argument.h" +#include "pygi-info.h" +#include "pygi-value.h" +#include "pygi-basictype.h" +#include "pygi-object.h" +#include "pygi-struct-marshal.h" +#include "pygi-error.h" +#include "pygi-foreign.h" +#include "pygi-type.h" +#include "pygi-util.h" -static gboolean -gi_argument_to_gssize (GIArgument *arg_in, - GITypeTag type_tag, - gssize *gssize_out) + +gboolean +pygi_argument_to_gssize (GIArgument *arg_in, + GITypeTag type_tag, + gssize *gssize_out) { switch (type_tag) { case GI_TYPE_TAG_INT8: @@ -60,10 +66,22 @@ gi_argument_to_gssize (GIArgument *arg_in, *gssize_out = arg_in->v_uint32; return TRUE; case GI_TYPE_TAG_INT64: - *gssize_out = arg_in->v_int64; + if (arg_in->v_int64 > G_MAXSSIZE || arg_in->v_int64 < G_MINSSIZE) { + PyErr_Format (PyExc_TypeError, + "Unable to marshal %s to gssize", + g_type_tag_to_string(type_tag)); + return FALSE; + } + *gssize_out = (gssize)arg_in->v_int64; return TRUE; case GI_TYPE_TAG_UINT64: - *gssize_out = arg_in->v_uint64; + if (arg_in->v_uint64 > G_MAXSSIZE) { + PyErr_Format (PyExc_TypeError, + "Unable to marshal %s to gssize", + g_type_tag_to_string(type_tag)); + return FALSE; + } + *gssize_out = (gssize)arg_in->v_uint64; return TRUE; default: PyErr_Format (PyExc_TypeError, @@ -73,32 +91,59 @@ gi_argument_to_gssize (GIArgument *arg_in, } } +static GITypeTag +_pygi_get_storage_type (GITypeInfo *type_info) +{ + GITypeTag type_tag = g_type_info_get_tag (type_info); + + if (type_tag == GI_TYPE_TAG_INTERFACE) { + GIBaseInfo *interface = g_type_info_get_interface (type_info); + switch (g_base_info_get_type (interface)) { + case GI_INFO_TYPE_ENUM: + case GI_INFO_TYPE_FLAGS: + type_tag = g_enum_info_get_storage_type ((GIEnumInfo *)interface); + break; + default: + /* FIXME: we might have something to do for other types */ + break; + } + g_base_info_unref (interface); + } + return type_tag; +} + void _pygi_hash_pointer_to_arg (GIArgument *arg, - GITypeTag type_tag) + GITypeInfo *type_info) { + GITypeTag type_tag = _pygi_get_storage_type (type_info); + switch (type_tag) { case GI_TYPE_TAG_INT8: - arg->v_int8 = GPOINTER_TO_INT (arg->v_pointer); + arg->v_int8 = (gint8)GPOINTER_TO_INT (arg->v_pointer); break; case GI_TYPE_TAG_INT16: - arg->v_int16 = GPOINTER_TO_INT (arg->v_pointer); + arg->v_int16 = (gint16)GPOINTER_TO_INT (arg->v_pointer); break; case GI_TYPE_TAG_INT32: - arg->v_int32 = GPOINTER_TO_INT (arg->v_pointer); + arg->v_int32 = (gint32)GPOINTER_TO_INT (arg->v_pointer); break; case GI_TYPE_TAG_UINT8: - arg->v_uint8 = GPOINTER_TO_UINT (arg->v_pointer); + arg->v_uint8 = (guint8)GPOINTER_TO_UINT (arg->v_pointer); break; case GI_TYPE_TAG_UINT16: - arg->v_uint16 = GPOINTER_TO_UINT (arg->v_pointer); + arg->v_uint16 = (guint16)GPOINTER_TO_UINT (arg->v_pointer); break; case GI_TYPE_TAG_UINT32: - arg->v_uint32 = GPOINTER_TO_UINT (arg->v_pointer); + arg->v_uint32 = (guint32)GPOINTER_TO_UINT (arg->v_pointer); + break; + case GI_TYPE_TAG_GTYPE: + arg->v_size = GPOINTER_TO_SIZE (arg->v_pointer); break; case GI_TYPE_TAG_UTF8: case GI_TYPE_TAG_FILENAME: case GI_TYPE_TAG_INTERFACE: + case GI_TYPE_TAG_ARRAY: break; default: g_critical ("Unsupported type %s", g_type_tag_to_string(type_tag)); @@ -107,8 +152,10 @@ _pygi_hash_pointer_to_arg (GIArgument *arg, gpointer _pygi_arg_to_hash_pointer (const GIArgument *arg, - GITypeTag type_tag) + GITypeInfo *type_info) { + GITypeTag type_tag = _pygi_get_storage_type (type_info); + switch (type_tag) { case GI_TYPE_TAG_INT8: return GINT_TO_POINTER (arg->v_int8); @@ -122,9 +169,12 @@ _pygi_arg_to_hash_pointer (const GIArgument *arg, return GINT_TO_POINTER (arg->v_int32); case GI_TYPE_TAG_UINT32: return GINT_TO_POINTER (arg->v_uint32); + case GI_TYPE_TAG_GTYPE: + return GSIZE_TO_POINTER (arg->v_size); case GI_TYPE_TAG_UTF8: case GI_TYPE_TAG_FILENAME: case GI_TYPE_TAG_INTERFACE: + case GI_TYPE_TAG_ARRAY: return arg->v_pointer; default: g_critical ("Unsupported type %s", g_type_tag_to_string(type_tag)); @@ -132,642 +182,49 @@ _pygi_arg_to_hash_pointer (const GIArgument *arg, } } -static void -_pygi_g_type_tag_py_bounds (GITypeTag type_tag, - PyObject **lower, - PyObject **upper) -{ - switch (type_tag) { - case GI_TYPE_TAG_INT8: - *lower = PYGLIB_PyLong_FromLong (-128); - *upper = PYGLIB_PyLong_FromLong (127); - break; - case GI_TYPE_TAG_UINT8: - *upper = PYGLIB_PyLong_FromLong (255); - *lower = PYGLIB_PyLong_FromLong (0); - break; - case GI_TYPE_TAG_INT16: - *lower = PYGLIB_PyLong_FromLong (-32768); - *upper = PYGLIB_PyLong_FromLong (32767); - break; - case GI_TYPE_TAG_UINT16: - *upper = PYGLIB_PyLong_FromLong (65535); - *lower = PYGLIB_PyLong_FromLong (0); - break; - case GI_TYPE_TAG_INT32: - *lower = PYGLIB_PyLong_FromLong (G_MININT32); - *upper = PYGLIB_PyLong_FromLong (G_MAXINT32); - break; - case GI_TYPE_TAG_UINT32: - /* Note: On 32-bit archs, this number doesn't fit in a long. */ - *upper = PyLong_FromLongLong (G_MAXUINT32); - *lower = PYGLIB_PyLong_FromLong (0); - break; - case GI_TYPE_TAG_INT64: - /* Note: On 32-bit archs, these numbers don't fit in a long. */ - *lower = PyLong_FromLongLong (G_MININT64); - *upper = PyLong_FromLongLong (G_MAXINT64); - break; - case GI_TYPE_TAG_UINT64: - *upper = PyLong_FromUnsignedLongLong (G_MAXUINT64); - *lower = PYGLIB_PyLong_FromLong (0); - break; - case GI_TYPE_TAG_FLOAT: - *upper = PyFloat_FromDouble (G_MAXFLOAT); - *lower = PyFloat_FromDouble (-G_MAXFLOAT); - break; - case GI_TYPE_TAG_DOUBLE: - *upper = PyFloat_FromDouble (G_MAXDOUBLE); - *lower = PyFloat_FromDouble (-G_MAXDOUBLE); - break; - default: - PyErr_SetString (PyExc_TypeError, "Non-numeric type tag"); - *lower = *upper = NULL; - return; - } -} - -gint -_pygi_g_registered_type_info_check_object (GIRegisteredTypeInfo *info, - gboolean is_instance, - PyObject *object) -{ - gint retval; - - GType g_type; - PyObject *py_type; - gchar *type_name_expected = NULL; - GIInfoType interface_type; - - interface_type = g_base_info_get_type (info); - if ( (interface_type == GI_INFO_TYPE_STRUCT) && - (g_struct_info_is_foreign ( (GIStructInfo*) info))) { - /* TODO: Could we check is the correct foreign type? */ - return 1; - } - - g_type = g_registered_type_info_get_g_type (info); - if (g_type != G_TYPE_NONE) { - py_type = _pygi_type_get_from_g_type (g_type); - } else { - py_type = _pygi_type_import_by_gi_info ( (GIBaseInfo *) info); - } - - if (py_type == NULL) { - return 0; - } - - g_assert (PyType_Check (py_type)); - - if (is_instance) { - retval = PyObject_IsInstance (object, py_type); - if (!retval) { - type_name_expected = _pygi_g_base_info_get_fullname ( - (GIBaseInfo *) info); - } - } else { - if (!PyObject_Type (py_type)) { - type_name_expected = "type"; - retval = 0; - } else if (!PyType_IsSubtype ( (PyTypeObject *) object, - (PyTypeObject *) py_type)) { - type_name_expected = _pygi_g_base_info_get_fullname ( - (GIBaseInfo *) info); - retval = 0; - } else { - retval = 1; - } - } - - Py_DECREF (py_type); - - if (!retval) { - PyTypeObject *object_type; - if (type_name_expected == NULL) { - return -1; - } - - object_type = (PyTypeObject *) PyObject_Type (object); - if (object_type == NULL) { - return -1; - } - - PyErr_Format (PyExc_TypeError, "Must be %s, not %s", - type_name_expected, object_type->tp_name); - - g_free (type_name_expected); - } - - return retval; -} - -gint -_pygi_g_type_interface_check_object (GIBaseInfo *info, - PyObject *object) -{ - gint retval = 1; - GIInfoType info_type; - - info_type = g_base_info_get_type (info); - switch (info_type) { - case GI_INFO_TYPE_CALLBACK: - if (!PyCallable_Check (object)) { - PyErr_Format (PyExc_TypeError, "Must be callable, not %s", - object->ob_type->tp_name); - retval = 0; - } - break; - case GI_INFO_TYPE_ENUM: - retval = 0; - if (PyNumber_Check (object)) { - PyObject *number = PYGLIB_PyNumber_Long (object); - if (number == NULL) - PyErr_Clear(); - else { - glong value = PYGLIB_PyLong_AsLong (number); - int i; - for (i = 0; i < g_enum_info_get_n_values (info); i++) { - GIValueInfo *value_info = g_enum_info_get_value (info, i); - glong enum_value = g_value_info_get_value (value_info); - g_base_info_unref (value_info); - if (value == enum_value) { - retval = 1; - break; - } - } - } - } - if (retval < 1) - retval = _pygi_g_registered_type_info_check_object ( - (GIRegisteredTypeInfo *) info, TRUE, object); - break; - case GI_INFO_TYPE_FLAGS: - if (PyNumber_Check (object)) { - /* Accept 0 as a valid flag value */ - PyObject *number = PYGLIB_PyNumber_Long (object); - if (number == NULL) - PyErr_Clear(); - else { - long value = PYGLIB_PyLong_AsLong (number); - if (value == 0) - break; - else if (value == -1) - PyErr_Clear(); - } - } - retval = _pygi_g_registered_type_info_check_object ( - (GIRegisteredTypeInfo *) info, TRUE, object); - break; - case GI_INFO_TYPE_STRUCT: - { - GType type; - - /* Handle special cases. */ - type = g_registered_type_info_get_g_type ( (GIRegisteredTypeInfo *) info); - if (g_type_is_a (type, G_TYPE_CLOSURE)) { - if (!(PyCallable_Check (object) || - pyg_type_from_object_strict (object, FALSE) == G_TYPE_CLOSURE)) { - PyErr_Format (PyExc_TypeError, "Must be callable, not %s", - object->ob_type->tp_name); - retval = 0; - } - break; - } else if (g_type_is_a (type, G_TYPE_VALUE)) { - /* we can't check g_values because we don't have - * enough context so just pass them through */ - break; - } - - /* Fallback. */ - } - case GI_INFO_TYPE_BOXED: - case GI_INFO_TYPE_INTERFACE: - case GI_INFO_TYPE_OBJECT: - retval = _pygi_g_registered_type_info_check_object ( (GIRegisteredTypeInfo *) info, TRUE, object); - break; - case GI_INFO_TYPE_UNION: - - - retval = _pygi_g_registered_type_info_check_object ( (GIRegisteredTypeInfo *) info, TRUE, object); - - /* If not the same type then check to see if the object's type - * is the same as one of the union's members - */ - if (retval == 0) { - gint i; - gint n_fields; - - n_fields = g_union_info_get_n_fields ( (GIUnionInfo *) info); - - for (i = 0; i < n_fields; i++) { - gint member_retval; - GIFieldInfo *field_info; - GITypeInfo *field_type_info; - - field_info = - g_union_info_get_field ( (GIUnionInfo *) info, i); - field_type_info = g_field_info_get_type (field_info); - - member_retval = _pygi_g_type_info_check_object( - field_type_info, - object, - TRUE); - - g_base_info_unref ( ( GIBaseInfo *) field_type_info); - g_base_info_unref ( ( GIBaseInfo *) field_info); - - if (member_retval == 1) { - retval = member_retval; - break; - } - } - } - - break; - default: - g_assert_not_reached(); - } - - return retval; -} - -gint -_pygi_g_type_info_check_object (GITypeInfo *type_info, - PyObject *object, - gboolean allow_none) +/** + * _pygi_argument_array_length_marshal: + * @length_arg_index: Index of length argument in the callables args list. + * @user_data1: (type Array(GValue)): Array of GValue arguments to retrieve length + * @user_data2: (type GICallableInfo): Callable info to get the argument from. + * + * Generic marshalling policy for array length arguments in callables. + * + * Returns: The length of the array or -1 on failure. + */ +gssize +_pygi_argument_array_length_marshal (gsize length_arg_index, + void *user_data1, + void *user_data2) { - GITypeTag type_tag; - gint retval = 1; - - if (allow_none && object == Py_None) { - return retval; - } - - type_tag = g_type_info_get_tag (type_info); - - switch (type_tag) { - case GI_TYPE_TAG_VOID: - /* No check; VOID means undefined type */ - break; - case GI_TYPE_TAG_BOOLEAN: - /* No check; every Python object has a truth value. */ - break; - case GI_TYPE_TAG_UINT8: - case GI_TYPE_TAG_INT8: - /* (U)INT8 types can be characters */ - if (PYGLIB_PyBytes_Check(object)) { - if (PYGLIB_PyBytes_Size(object) != 1) { - PyErr_Format (PyExc_TypeError, "Must be a single character"); - retval = 0; - break; - } - - break; - } - case GI_TYPE_TAG_INT16: - case GI_TYPE_TAG_UINT16: - case GI_TYPE_TAG_INT32: - case GI_TYPE_TAG_UINT32: - case GI_TYPE_TAG_INT64: - case GI_TYPE_TAG_UINT64: - case GI_TYPE_TAG_FLOAT: - case GI_TYPE_TAG_DOUBLE: - { - PyObject *number, *lower, *upper; - - if (!PyNumber_Check (object)) { - PyErr_Format (PyExc_TypeError, "Must be number, not %s", - object->ob_type->tp_name); - retval = 0; - break; - } - - if (type_tag == GI_TYPE_TAG_FLOAT || type_tag == GI_TYPE_TAG_DOUBLE) { - number = PyNumber_Float (object); - } else { - number = PYGLIB_PyNumber_Long (object); - } - - _pygi_g_type_tag_py_bounds (type_tag, &lower, &upper); - - if (lower == NULL || upper == NULL || number == NULL) { - retval = -1; - goto check_number_release; - } - - /* Check bounds */ - if (PyObject_RichCompareBool (lower, number, Py_GT) - || PyObject_RichCompareBool (upper, number, Py_LT)) { - PyObject *lower_str; - PyObject *upper_str; - - if (PyErr_Occurred()) { - retval = -1; - goto check_number_release; - } - - lower_str = PyObject_Str (lower); - upper_str = PyObject_Str (upper); - if (lower_str == NULL || upper_str == NULL) { - retval = -1; - goto check_number_error_release; - } - -#if PY_VERSION_HEX < 0x03000000 - PyErr_Format (PyExc_ValueError, "Must range from %s to %s", - PyString_AS_STRING (lower_str), - PyString_AS_STRING (upper_str)); -#else - { - PyObject *lower_pybytes_obj; - PyObject *upper_pybytes_obj; - - lower_pybytes_obj = PyUnicode_AsUTF8String (lower_str); - if (!lower_pybytes_obj) { - goto utf8_fail; - } - - upper_pybytes_obj = PyUnicode_AsUTF8String (upper_str); - if (!upper_pybytes_obj) { - Py_DECREF(lower_pybytes_obj); - goto utf8_fail; - } - - PyErr_Format (PyExc_ValueError, "Must range from %s to %s", - PyBytes_AsString (lower_pybytes_obj), - PyBytes_AsString (upper_pybytes_obj)); - Py_DECREF (lower_pybytes_obj); - Py_DECREF (upper_pybytes_obj); - } -utf8_fail: -#endif - retval = 0; - -check_number_error_release: - Py_XDECREF (lower_str); - Py_XDECREF (upper_str); - } - -check_number_release: - Py_XDECREF (number); - Py_XDECREF (lower); - Py_XDECREF (upper); - break; - } - case GI_TYPE_TAG_GTYPE: - { - if (pyg_type_from_object (object) == 0) { - PyErr_Format (PyExc_TypeError, "Must be gobject.GType, not %s", - object->ob_type->tp_name); - retval = 0; - } - break; - } - case GI_TYPE_TAG_UNICHAR: - { - Py_ssize_t size; - if (PyUnicode_Check (object)) { - size = PyUnicode_GET_SIZE (object); -#if PY_VERSION_HEX < 0x03000000 - } else if (PyString_Check (object)) { - PyObject *pyuni = PyUnicode_FromEncodedObject (object, "UTF-8", "strict"); - size = PyUnicode_GET_SIZE (pyuni); - Py_DECREF(pyuni); -#endif - } else { - PyErr_Format (PyExc_TypeError, "Must be string, not %s", - object->ob_type->tp_name); - retval = 0; - break; - } - - if (size != 1) { - PyErr_Format (PyExc_TypeError, "Must be a one character string, not %" G_GINT64_FORMAT " characters", - (gint64)size); - retval = 0; - break; - } - - break; - } - case GI_TYPE_TAG_UTF8: - case GI_TYPE_TAG_FILENAME: - if (!PYGLIB_PyBaseString_Check (object) ) { - PyErr_Format (PyExc_TypeError, "Must be string, not %s", - object->ob_type->tp_name); - retval = 0; - } - break; - case GI_TYPE_TAG_ARRAY: - { - gssize fixed_size; - Py_ssize_t length; - GITypeInfo *item_type_info; - Py_ssize_t i; - - if (!PySequence_Check (object)) { - PyErr_Format (PyExc_TypeError, "Must be sequence, not %s", - object->ob_type->tp_name); - retval = 0; - break; - } - - length = PySequence_Length (object); - if (length < 0) { - retval = -1; - break; - } - - fixed_size = g_type_info_get_array_fixed_size (type_info); - if (fixed_size >= 0 && length != fixed_size) { - PyErr_Format (PyExc_ValueError, "Must contain %zd items, not %zd", - fixed_size, length); - retval = 0; - break; - } - - item_type_info = g_type_info_get_param_type (type_info, 0); - g_assert (item_type_info != NULL); - - /* FIXME: This is insain. We really should only check the first - * object and perhaps have a debugging mode. Large arrays - * will cause apps to slow to a crawl. - */ - for (i = 0; i < length; i++) { - PyObject *item; - - item = PySequence_GetItem (object, i); - if (item == NULL) { - retval = -1; - break; - } - - retval = _pygi_g_type_info_check_object (item_type_info, item, TRUE); - - Py_DECREF (item); - - if (retval < 0) { - break; - } - if (!retval) { - _PyGI_ERROR_PREFIX ("Item %zd: ", i); - break; - } - } - - g_base_info_unref ( (GIBaseInfo *) item_type_info); - - break; - } - case GI_TYPE_TAG_INTERFACE: - { - GIBaseInfo *info; - - info = g_type_info_get_interface (type_info); - g_assert (info != NULL); - - retval = _pygi_g_type_interface_check_object(info, object); - - g_base_info_unref (info); - break; - } - case GI_TYPE_TAG_GLIST: - case GI_TYPE_TAG_GSLIST: - { - Py_ssize_t length; - GITypeInfo *item_type_info; - Py_ssize_t i; - - if (!PySequence_Check (object)) { - PyErr_Format (PyExc_TypeError, "Must be sequence, not %s", - object->ob_type->tp_name); - retval = 0; - break; - } - - length = PySequence_Length (object); - if (length < 0) { - retval = -1; - break; - } - - item_type_info = g_type_info_get_param_type (type_info, 0); - g_assert (item_type_info != NULL); - - for (i = 0; i < length; i++) { - PyObject *item; - - item = PySequence_GetItem (object, i); - if (item == NULL) { - retval = -1; - break; - } - - retval = _pygi_g_type_info_check_object (item_type_info, item, TRUE); - - Py_DECREF (item); - - if (retval < 0) { - break; - } - if (!retval) { - _PyGI_ERROR_PREFIX ("Item %zd: ", i); - break; - } - } - - g_base_info_unref ( (GIBaseInfo *) item_type_info); - break; - } - case GI_TYPE_TAG_GHASH: - { - Py_ssize_t length; - PyObject *keys; - PyObject *values; - GITypeInfo *key_type_info; - GITypeInfo *value_type_info; - Py_ssize_t i; - - keys = PyMapping_Keys (object); - if (keys == NULL) { - PyErr_Format (PyExc_TypeError, "Must be mapping, not %s", - object->ob_type->tp_name); - retval = 0; - break; - } - - length = PyMapping_Length (object); - if (length < 0) { - Py_DECREF (keys); - retval = -1; - break; - } - - values = PyMapping_Values (object); - if (values == NULL) { - retval = -1; - Py_DECREF (keys); - break; - } - - key_type_info = g_type_info_get_param_type (type_info, 0); - g_assert (key_type_info != NULL); - - value_type_info = g_type_info_get_param_type (type_info, 1); - g_assert (value_type_info != NULL); - - for (i = 0; i < length; i++) { - PyObject *key; - PyObject *value; - - key = PyList_GET_ITEM (keys, i); - value = PyList_GET_ITEM (values, i); - - retval = _pygi_g_type_info_check_object (key_type_info, key, TRUE); - if (retval < 0) { - break; - } - if (!retval) { - _PyGI_ERROR_PREFIX ("Key %zd :", i); - break; - } - - retval = _pygi_g_type_info_check_object (value_type_info, value, TRUE); - if (retval < 0) { - break; - } - if (!retval) { - _PyGI_ERROR_PREFIX ("Value %zd :", i); - break; - } - } - - g_base_info_unref ( (GIBaseInfo *) key_type_info); - g_base_info_unref ( (GIBaseInfo *) value_type_info); - Py_DECREF (values); - Py_DECREF (keys); - break; - } - case GI_TYPE_TAG_ERROR: - PyErr_SetString (PyExc_NotImplementedError, "Error marshalling is not supported yet"); - /* TODO */ - break; + GIArgInfo length_arg_info; + GITypeInfo length_type_info; + GIArgument length_arg; + gssize array_len = -1; + GValue *values = (GValue *)user_data1; + GICallableInfo *callable_info = (GICallableInfo *)user_data2; + + g_callable_info_load_arg (callable_info, (gint)length_arg_index, &length_arg_info); + g_arg_info_load_type (&length_arg_info, &length_type_info); + + length_arg = _pygi_argument_from_g_value (&(values[length_arg_index]), + &length_type_info); + if (!pygi_argument_to_gssize (&length_arg, + g_type_info_get_tag (&length_type_info), + &array_len)) { + return -1; } - return retval; + return array_len; } /** * _pygi_argument_to_array * @arg: The argument to convert - * @args: Arguments to method invocation, possibly contaning the array length. - * Set to %NULL if this is not for a method call or @args_values is - * specified. - * @args_values: GValue Arguments to method invocation, possibly contaning the - * array length. Set to %NULL if this is not for a method call or - * @args is specified. - * @callable_info: Info on the callable, if this a method call; otherwise %NULL + * @array_length_policy: Closure for marshalling the array length argument when needed. + * @user_data1: Generic user data passed to the array_length_policy. + * @user_data2: Generic user data passed to the array_length_policy. * @type_info: The type info for @arg * @out_free_array: A return location for a gboolean that indicates whether * or not the wrapped GArray should be freed @@ -784,9 +241,9 @@ check_number_release: */ GArray * _pygi_argument_to_array (GIArgument *arg, - GIArgument *args[], - const GValue *args_values, - GICallableInfo *callable_info, + PyGIArgArrayLengthPolicy array_length_policy, + void *user_data1, + void *user_data2, GITypeInfo *type_info, gboolean *out_free_array) { @@ -812,52 +269,46 @@ _pygi_argument_to_array (GIArgument *arg, g_base_info_unref ( (GIBaseInfo *) item_type_info); if (is_zero_terminated) { - length = g_strv_length (arg->v_pointer); + if (item_size == sizeof(gpointer)) + length = g_strv_length ((gchar **)arg->v_pointer); + else if (item_size == 1) + length = strlen ((gchar*)arg->v_pointer); + else if (item_size == sizeof(int)) + for (length = 0; *(((int*)arg->v_pointer) + length); length++); + else if (item_size == sizeof(short)) + for (length = 0; *(((short*)arg->v_pointer) + length); length++); + else + g_assert_not_reached (); } else { length = g_type_info_get_array_fixed_size (type_info); if (length < 0) { gint length_arg_pos; - GIArgInfo length_arg_info; - GITypeInfo length_type_info; - if (G_UNLIKELY (args == NULL && args_values == NULL)) { + if (G_UNLIKELY (array_length_policy == NULL)) { g_critical ("Unable to determine array length for %p", arg->v_pointer); - g_array = g_array_new (is_zero_terminated, FALSE, item_size); + g_array = g_array_new (is_zero_terminated, FALSE, (guint)item_size); *out_free_array = TRUE; return g_array; } length_arg_pos = g_type_info_get_array_length (type_info); g_assert (length_arg_pos >= 0); - g_assert (callable_info); - g_callable_info_load_arg (callable_info, length_arg_pos, &length_arg_info); - g_arg_info_load_type (&length_arg_info, &length_type_info); - - if (args != NULL) { - if (!gi_argument_to_gssize (args[length_arg_pos], - g_type_info_get_tag (&length_type_info), - &length)) - return NULL; - } else { - /* get it from args_values */ - GIArgument length_arg = _pygi_argument_from_g_value (&(args_values[length_arg_pos]), - &length_type_info); - if (!gi_argument_to_gssize (&length_arg, - g_type_info_get_tag (&length_type_info), - &length)) - return NULL; + + length = array_length_policy (length_arg_pos, user_data1, user_data2); + if (length < 0) { + return NULL; } } } g_assert (length >= 0); - g_array = g_array_new (is_zero_terminated, FALSE, item_size); + g_array = g_array_new (is_zero_terminated, FALSE, (guint)item_size); g_free (g_array->data); g_array->data = arg->v_pointer; - g_array->len = length; + g_array->len = (guint)length; *out_free_array = TRUE; break; case GI_ARRAY_TYPE_ARRAY: @@ -894,25 +345,21 @@ _pygi_argument_from_object (PyObject *object, { GIArgument arg; GITypeTag type_tag; + gpointer cleanup_data = NULL; memset(&arg, 0, sizeof(GIArgument)); type_tag = g_type_info_get_tag (type_info); - if (_pygi_marshal_from_py_basic_type (object, &arg, type_tag, transfer) || - PyErr_Occurred()) { - return arg; - } - switch (type_tag) { case GI_TYPE_TAG_ARRAY: { - Py_ssize_t length; + Py_ssize_t py_length; + guint length, i; gboolean is_zero_terminated; GITypeInfo *item_type_info; gsize item_size; GArray *array; GITransfer item_transfer; - Py_ssize_t i; if (object == Py_None) { arg.v_pointer = NULL; @@ -921,18 +368,17 @@ _pygi_argument_from_object (PyObject *object, /* Note, strings are sequences, but we cannot accept them here */ if (!PySequence_Check (object) || -#if PY_VERSION_HEX < 0x03000000 - PyString_Check (object) || -#endif PyUnicode_Check (object)) { PyErr_SetString (PyExc_TypeError, "expected sequence"); break; } - length = PySequence_Length (object); - if (length < 0) { + py_length = PySequence_Length (object); + if (py_length < 0) + break; + + if (!pygi_guint_from_pyssize (py_length, &length)) break; - } is_zero_terminated = g_type_info_is_zero_terminated (type_info); item_type_info = g_type_info_get_param_type (type_info, 0); @@ -943,7 +389,7 @@ _pygi_argument_from_object (PyObject *object, else item_size = sizeof (GIArgument); - array = g_array_sized_new (is_zero_terminated, FALSE, item_size, length); + array = g_array_sized_new (is_zero_terminated, FALSE, (guint)item_size, length); if (array == NULL) { g_base_info_unref ( (GIBaseInfo *) item_type_info); PyErr_NoMemory(); @@ -951,9 +397,9 @@ _pygi_argument_from_object (PyObject *object, } if (g_type_info_get_tag (item_type_info) == GI_TYPE_TAG_UINT8 && - PYGLIB_PyBytes_Check(object)) { + PyBytes_Check (object)) { - memcpy(array->data, PYGLIB_PyBytes_AsString(object), length); + memcpy(array->data, PyBytes_AsString (object), length); array->len = length; goto array_success; } @@ -987,7 +433,7 @@ array_item_error: GI_TRANSFER_NOTHING, GI_DIRECTION_IN); array = NULL; - _PyGI_ERROR_PREFIX ("Item %zd: ", i); + _PyGI_ERROR_PREFIX ("Item %u: ", i); break; } @@ -1016,9 +462,11 @@ array_success: { GType g_type; PyObject *py_type; + gboolean is_foreign = (info_type == GI_INFO_TYPE_STRUCT) && + (g_struct_info_is_foreign ((GIStructInfo *) info)); g_type = g_registered_type_info_get_g_type ( (GIRegisteredTypeInfo *) info); - py_type = _pygi_type_import_by_gi_info ( (GIBaseInfo *) info); + py_type = pygi_type_import_by_gi_info ( (GIBaseInfo *) info); /* Note for G_TYPE_VALUE g_type: * This will currently leak the GValue that is allocated and @@ -1027,40 +475,44 @@ array_success: * Further re-factoring is needed to fix this leak. * See: https://bugzilla.gnome.org/show_bug.cgi?id=693405 */ - _pygi_marshal_from_py_interface_struct (object, - &arg, - NULL, /*arg_name*/ - info, /*interface_info*/ - type_info, - g_type, - py_type, - transfer, - FALSE, /*copy_reference*/ - g_struct_info_is_foreign (info)); + pygi_arg_struct_from_py_marshal (object, + &arg, + NULL, /*arg_name*/ + info, /*interface_info*/ + g_type, + py_type, + transfer, + FALSE, /*copy_reference*/ + is_foreign, + g_type_info_is_pointer (type_info)); Py_DECREF (py_type); break; } case GI_INFO_TYPE_ENUM: - case GI_INFO_TYPE_FLAGS: { - PyObject *int_; + GType g_type; - int_ = PYGLIB_PyNumber_Long (object); - if (int_ == NULL) { + g_type = g_registered_type_info_get_g_type ( (GIRegisteredTypeInfo *) info); + if (pyg_enum_get_value(g_type, object, &arg.v_int) < 0) break; - } - arg.v_int = PYGLIB_PyLong_AsLong (int_); + break; + } + case GI_INFO_TYPE_FLAGS: + { + GType g_type; - Py_DECREF (int_); + g_type = g_registered_type_info_get_g_type ( (GIRegisteredTypeInfo *) info); + if (pyg_flags_get_value(g_type, object, &arg.v_uint) < 0) + break; break; } case GI_INFO_TYPE_INTERFACE: case GI_INFO_TYPE_OBJECT: /* An error within this call will result in a NULL arg */ - _pygi_marshal_from_py_gobject_out_arg (object, &arg, transfer); + pygi_arg_gobject_out_arg_from_py (object, &arg, transfer); break; default: @@ -1218,7 +670,7 @@ list_item_error: } g_hash_table_insert (hash_table, key.v_pointer, - _pygi_arg_to_hash_pointer (&value, g_type_info_get_tag (value_type_info))); + _pygi_arg_to_hash_pointer (&value, value_type_info)); continue; hash_table_item_error: @@ -1245,7 +697,9 @@ hash_table_release: /* TODO */ break; default: - g_assert_not_reached (); + /* Ignores cleanup data for now. */ + pygi_marshal_from_py_basic_type (object, &arg, type_tag, transfer, &cleanup_data); + break; } return arg; @@ -1272,9 +726,6 @@ _pygi_argument_to_object (GIArgument *arg, PyObject *object = NULL; type_tag = g_type_info_get_tag (type_info); - object = _pygi_marshal_to_py_basic_type (arg, type_tag, transfer); - if (object) - return object; switch (type_tag) { case GI_TYPE_TAG_VOID: @@ -1314,7 +765,7 @@ _pygi_argument_to_object (GIArgument *arg, if (item_type_tag == GI_TYPE_TAG_UINT8) { /* Return as a byte array */ - object = PYGLIB_PyBytes_FromStringAndSize (array->data, array->len); + object = PyBytes_FromStringAndSize (array->data, array->len); } else { object = PyList_New (array->len); if (object == NULL) { @@ -1362,21 +813,23 @@ _pygi_argument_to_object (GIArgument *arg, { PyObject *py_type; GType g_type = g_registered_type_info_get_g_type ( (GIRegisteredTypeInfo *) info); + gboolean is_foreign = (info_type == GI_INFO_TYPE_STRUCT) && + (g_struct_info_is_foreign ((GIStructInfo *) info)); /* Special case variant and none to force loading from py module. */ if (g_type == G_TYPE_VARIANT || g_type == G_TYPE_NONE) { - py_type = _pygi_type_import_by_gi_info (info); + py_type = pygi_type_import_by_gi_info (info); } else { - py_type = _pygi_type_get_from_g_type (g_type); + py_type = pygi_type_get_from_g_type (g_type); } - object = _pygi_marshal_to_py_interface_struct (arg, - info, /*interface_info*/ - g_type, - py_type, - transfer, - FALSE, /*is_allocated*/ - g_struct_info_is_foreign (info)); + object = pygi_arg_struct_to_py_marshal (arg, + info, /*interface_info*/ + g_type, + py_type, + transfer, + FALSE, /*is_allocated*/ + is_foreign); Py_XDECREF (py_type); break; @@ -1390,14 +843,14 @@ _pygi_argument_to_object (GIArgument *arg, if (type == G_TYPE_NONE) { /* An enum with a GType of None is an enum without GType */ - PyObject *py_type = _pygi_type_import_by_gi_info (info); + PyObject *py_type = pygi_type_import_by_gi_info (info); PyObject *py_args = NULL; if (!py_type) return NULL; py_args = PyTuple_New (1); - if (PyTuple_SetItem (py_args, 0, PyLong_FromLong (arg->v_int)) != 0) { + if (PyTuple_SetItem (py_args, 0, pygi_gint_to_py (arg->v_int)) != 0) { Py_DECREF (py_args); Py_DECREF (py_type); return NULL; @@ -1418,26 +871,7 @@ _pygi_argument_to_object (GIArgument *arg, } case GI_INFO_TYPE_INTERFACE: case GI_INFO_TYPE_OBJECT: - /* HACK: - * The following hack is to work around GTK+ sending signals which - * contain floating widgets in them. This assumes control of how - * references are added by the PyGObject wrapper and avoids the sink - * behavior by explicitly passing GI_TRANSFER_EVERYTHING as the transfer - * mode and then re-forcing the object as floating afterwards. - * - * This can be deleted once the following ticket is fixed: - * https://bugzilla.gnome.org/show_bug.cgi?id=693400 - */ - if (arg->v_pointer && - !G_IS_PARAM_SPEC (arg->v_pointer) && - transfer == GI_TRANSFER_NOTHING && - g_object_is_floating (arg->v_pointer)) { - g_object_ref (arg->v_pointer); - object = _pygi_marshal_to_py_object (arg, GI_TRANSFER_EVERYTHING); - g_object_force_floating (arg->v_pointer); - } else { - object = _pygi_marshal_to_py_object (arg, transfer); - } + object = pygi_arg_gobject_to_py_called_from_c (arg, transfer); break; default: @@ -1529,7 +963,7 @@ _pygi_argument_to_object (GIArgument *arg, break; } - _pygi_hash_pointer_to_arg (&value, g_type_info_get_tag (value_type_info)); + _pygi_hash_pointer_to_arg (&value, value_type_info); py_value = _pygi_argument_to_object (&value, value_type_info, item_transfer); if (py_value == NULL) { Py_DECREF (py_key); @@ -1556,12 +990,12 @@ _pygi_argument_to_object (GIArgument *arg, GError *error = (GError *) arg->v_pointer; if (error != NULL && transfer == GI_TRANSFER_NOTHING) { /* If we have not been transferred the ownership we must copy - * the error, because pyglib_error_check() is going to free it. + * the error, because pygi_error_check() is going to free it. */ error = g_error_copy (error); } - if (pyglib_error_check (&error)) { + if (pygi_error_check (&error)) { PyObject *err_type; PyObject *err_value; PyObject *err_trace; @@ -1578,138 +1012,13 @@ _pygi_argument_to_object (GIArgument *arg, } default: { - g_assert_not_reached(); + object = pygi_marshal_to_py_basic_type (arg, type_tag, transfer); } } return object; } - -GIArgument -_pygi_argument_from_g_value(const GValue *value, - GITypeInfo *type_info) -{ - GIArgument arg = { 0, }; - - GITypeTag type_tag = g_type_info_get_tag (type_info); - - /* For the long handling: long can be equivalent to - int32 or int64, depending on the architecture, but - gi doesn't tell us (and same for ulong) - */ - switch (type_tag) { - case GI_TYPE_TAG_BOOLEAN: - arg.v_boolean = g_value_get_boolean (value); - break; - case GI_TYPE_TAG_INT8: - case GI_TYPE_TAG_INT16: - case GI_TYPE_TAG_INT32: - if (g_type_is_a (G_VALUE_TYPE (value), G_TYPE_LONG)) - arg.v_int = g_value_get_long (value); - else - arg.v_int = g_value_get_int (value); - break; - case GI_TYPE_TAG_INT64: - if (g_type_is_a (G_VALUE_TYPE (value), G_TYPE_LONG)) - arg.v_int64 = g_value_get_long (value); - else - arg.v_int64 = g_value_get_int64 (value); - break; - case GI_TYPE_TAG_UINT8: - case GI_TYPE_TAG_UINT16: - case GI_TYPE_TAG_UINT32: - if (g_type_is_a (G_VALUE_TYPE (value), G_TYPE_ULONG)) - arg.v_uint = g_value_get_ulong (value); - else - arg.v_uint = g_value_get_uint (value); - break; - case GI_TYPE_TAG_UINT64: - if (g_type_is_a (G_VALUE_TYPE (value), G_TYPE_ULONG)) - arg.v_uint64 = g_value_get_ulong (value); - else - arg.v_uint64 = g_value_get_uint64 (value); - break; - case GI_TYPE_TAG_UNICHAR: - arg.v_uint32 = g_value_get_schar (value); - break; - case GI_TYPE_TAG_FLOAT: - arg.v_float = g_value_get_float (value); - break; - case GI_TYPE_TAG_DOUBLE: - arg.v_double = g_value_get_double (value); - break; - case GI_TYPE_TAG_GTYPE: - arg.v_long = g_value_get_gtype (value); - break; - case GI_TYPE_TAG_UTF8: - case GI_TYPE_TAG_FILENAME: - arg.v_string = g_value_dup_string (value); - break; - case GI_TYPE_TAG_GLIST: - case GI_TYPE_TAG_GSLIST: - arg.v_pointer = g_value_get_pointer (value); - break; - case GI_TYPE_TAG_ARRAY: - case GI_TYPE_TAG_GHASH: - if (G_VALUE_HOLDS_BOXED (value)) - arg.v_pointer = g_value_get_boxed (value); - else - /* e. g. GSettings::change-event */ - arg.v_pointer = g_value_get_pointer (value); - break; - case GI_TYPE_TAG_INTERFACE: - { - GIBaseInfo *info; - GIInfoType info_type; - - info = g_type_info_get_interface (type_info); - info_type = g_base_info_get_type (info); - - g_base_info_unref (info); - - switch (info_type) { - case GI_INFO_TYPE_FLAGS: - arg.v_uint = g_value_get_flags (value); - break; - case GI_INFO_TYPE_ENUM: - arg.v_int = g_value_get_enum (value); - break; - case GI_INFO_TYPE_INTERFACE: - case GI_INFO_TYPE_OBJECT: - if (G_VALUE_HOLDS_PARAM (value)) - arg.v_pointer = g_value_get_param (value); - else - arg.v_pointer = g_value_get_object (value); - break; - case GI_INFO_TYPE_BOXED: - case GI_INFO_TYPE_STRUCT: - case GI_INFO_TYPE_UNION: - if (G_VALUE_HOLDS(value, G_TYPE_BOXED)) { - arg.v_pointer = g_value_get_boxed (value); - } else if (G_VALUE_HOLDS(value, G_TYPE_VARIANT)) { - arg.v_pointer = g_value_get_variant (value); - } else { - arg.v_pointer = g_value_get_pointer (value); - } - break; - default: - g_warning("Converting of type '%s' is not implemented", g_info_type_to_string(info_type)); - g_assert_not_reached(); - } - break; - } - case GI_TYPE_TAG_ERROR: - arg.v_pointer = g_value_get_boxed (value); - break; - case GI_TYPE_TAG_VOID: - arg.v_pointer = g_value_get_pointer (value); - break; - } - - return arg; -} - void _pygi_argument_release (GIArgument *arg, GITypeInfo *type_info, @@ -1770,9 +1079,9 @@ _pygi_argument_release (GIArgument *arg, /* Free the items */ for (i = 0; i < array->len; i++) { - GIArgument *item; - item = &_g_array_index (array, GIArgument, i); - _pygi_argument_release (item, item_type_info, item_transfer, direction); + GIArgument item; + memcpy (&item, array->data + (g_array_get_element_size (array) * i), sizeof (GIArgument)); + _pygi_argument_release (&item, item_type_info, item_transfer, direction); } g_base_info_unref ( (GIBaseInfo *) item_type_info); @@ -1827,7 +1136,8 @@ _pygi_argument_release (GIArgument *arg, if (direction == GI_DIRECTION_IN && transfer == GI_TRANSFER_NOTHING) { g_closure_unref (arg->v_pointer); } - } else if (g_struct_info_is_foreign ( (GIStructInfo*) info)) { + } else if (info_type == GI_INFO_TYPE_STRUCT && + g_struct_info_is_foreign ((GIStructInfo*) info)) { if (direction == GI_DIRECTION_OUT && transfer == GI_TRANSFER_EVERYTHING) { pygi_struct_foreign_release (info, arg->v_pointer); } @@ -1972,13 +1282,8 @@ _pygi_argument_release (GIArgument *arg, g_slice_free (GError *, arg->v_pointer); break; } + default: + break; } } -void -_pygi_argument_init (void) -{ - PyDateTime_IMPORT; - _pygobject_import(); -} - diff --git a/gi/pygi-argument.h b/gi/pygi-argument.h index ed88214..2e889dd 100644 --- a/gi/pygi-argument.h +++ b/gi/pygi-argument.h @@ -14,9 +14,7 @@ * 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 + * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ #ifndef __PYGI_ARGUMENT_H__ @@ -30,28 +28,24 @@ G_BEGIN_DECLS /* Private */ -gpointer _pygi_arg_to_hash_pointer (const GIArgument *arg, - GITypeTag type_tag); - -void _pygi_hash_pointer_to_arg (GIArgument *arg, - GITypeTag type_tag); - -gint _pygi_g_type_interface_check_object (GIBaseInfo *info, - PyObject *object); +typedef gssize (*PyGIArgArrayLengthPolicy) (gsize item_index, + void *user_data1, + void *user_data2); -gint _pygi_g_type_info_check_object (GITypeInfo *type_info, - PyObject *object, - gboolean allow_none); +gssize _pygi_argument_array_length_marshal (gsize length_arg_index, + void *user_data1, + void *user_data2); -gint _pygi_g_registered_type_info_check_object (GIRegisteredTypeInfo *info, - gboolean is_instance, - PyObject *object); +gpointer _pygi_arg_to_hash_pointer (const GIArgument *arg, + GITypeInfo *type_info); +void _pygi_hash_pointer_to_arg (GIArgument *arg, + GITypeInfo *type_info); GArray* _pygi_argument_to_array (GIArgument *arg, - GIArgument *args[], - const GValue *args_values, - GICallableInfo *callable_info, + PyGIArgArrayLengthPolicy array_length_policy, + void *user_data1, + void *user_data2, GITypeInfo *type_info, gboolean *out_free_array); @@ -63,15 +57,14 @@ PyObject* _pygi_argument_to_object (GIArgument *arg, GITypeInfo *type_info, GITransfer transfer); -GIArgument _pygi_argument_from_g_value(const GValue *value, - GITypeInfo *type_info); - void _pygi_argument_release (GIArgument *arg, GITypeInfo *type_info, GITransfer transfer, GIDirection direction); -void _pygi_argument_init (void); +gboolean pygi_argument_to_gssize (GIArgument *arg_in, + GITypeTag type_tag, + gssize *gssize_out); G_END_DECLS diff --git a/gi/pygi-array.c b/gi/pygi-array.c new file mode 100644 index 0000000..d5b817f --- /dev/null +++ b/gi/pygi-array.c @@ -0,0 +1,978 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- + * vim: tabstop=4 shiftwidth=4 expandtab + * + * Copyright (C) 2011 John (J5) Palmieri <johnp@redhat.com> + * Copyright (C) 2014 Simon Feltman <sfeltman@gnome.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <Python.h> +#include <glib.h> + +#include "pygi-array.h" +#include "pygi-info.h" +#include "pygi-marshal-cleanup.h" +#include "pygi-basictype.h" +#include "pygi-util.h" + +/* Needed for _pygi_marshal_cleanup_from_py_interface_struct_gvalue hack */ +#include "pygi-struct-marshal.h" + +/* + * GArray to Python + */ + +static gboolean +gi_argument_from_py_ssize_t (GIArgument *arg_out, + Py_ssize_t size_in, + GITypeTag type_tag) +{ + switch (type_tag) { + case GI_TYPE_TAG_VOID: + case GI_TYPE_TAG_BOOLEAN: + goto unhandled_type; + + case GI_TYPE_TAG_INT8: + if (size_in >= G_MININT8 && size_in <= G_MAXINT8) { + arg_out->v_int8 = (gint8)size_in; + return TRUE; + } else { + goto overflow; + } + + case GI_TYPE_TAG_UINT8: + if (size_in >= 0 && size_in <= G_MAXUINT8) { + arg_out->v_uint8 = (guint8)size_in; + return TRUE; + } else { + goto overflow; + } + + case GI_TYPE_TAG_INT16: + if (size_in >= G_MININT16 && size_in <= G_MAXINT16) { + arg_out->v_int16 = (gint16)size_in; + return TRUE; + } else { + goto overflow; + } + + case GI_TYPE_TAG_UINT16: + if (size_in >= 0 && size_in <= G_MAXUINT16) { + arg_out->v_uint16 = (guint16)size_in; + return TRUE; + } else { + goto overflow; + } + + /* Ranges assume two's complement */ + case GI_TYPE_TAG_INT32: + if (size_in >= G_MININT32 && size_in <= G_MAXINT32) { + arg_out->v_int32 = (gint32)size_in; + return TRUE; + } else { + goto overflow; + } + + case GI_TYPE_TAG_UINT32: + if (size_in >= 0 && (gsize)size_in <= G_MAXUINT32) { + arg_out->v_uint32 = (guint32)size_in; + return TRUE; + } else { + goto overflow; + } + + case GI_TYPE_TAG_INT64: + arg_out->v_int64 = size_in; + return TRUE; + + case GI_TYPE_TAG_UINT64: + if (size_in >= 0) { + arg_out->v_uint64 = size_in; + return TRUE; + } else { + goto overflow; + } + + case GI_TYPE_TAG_FLOAT: + case GI_TYPE_TAG_DOUBLE: + case GI_TYPE_TAG_GTYPE: + case GI_TYPE_TAG_UTF8: + case GI_TYPE_TAG_FILENAME: + case GI_TYPE_TAG_ARRAY: + case GI_TYPE_TAG_INTERFACE: + case GI_TYPE_TAG_GLIST: + case GI_TYPE_TAG_GSLIST: + case GI_TYPE_TAG_GHASH: + case GI_TYPE_TAG_ERROR: + case GI_TYPE_TAG_UNICHAR: + default: + goto unhandled_type; + } + + overflow: + PyErr_Format (PyExc_OverflowError, + "Unable to marshal C Py_ssize_t %zd to %s", + size_in, + g_type_tag_to_string (type_tag)); + return FALSE; + + unhandled_type: + PyErr_Format (PyExc_TypeError, + "Unable to marshal C Py_ssize_t %zd to %s", + size_in, + g_type_tag_to_string (type_tag)); + return FALSE; +} + +static gboolean +gi_argument_to_gsize (GIArgument *arg_in, + gsize *gsize_out, + GITypeTag type_tag) +{ + switch (type_tag) { + case GI_TYPE_TAG_INT8: + *gsize_out = arg_in->v_int8; + return TRUE; + case GI_TYPE_TAG_UINT8: + *gsize_out = arg_in->v_uint8; + return TRUE; + case GI_TYPE_TAG_INT16: + *gsize_out = arg_in->v_int16; + return TRUE; + case GI_TYPE_TAG_UINT16: + *gsize_out = arg_in->v_uint16; + return TRUE; + case GI_TYPE_TAG_INT32: + *gsize_out = arg_in->v_int32; + return TRUE; + case GI_TYPE_TAG_UINT32: + *gsize_out = arg_in->v_uint32; + return TRUE; + case GI_TYPE_TAG_INT64: + if (arg_in->v_uint64 > G_MAXSIZE) { + PyErr_Format (PyExc_TypeError, + "Unable to marshal %s to gsize", + g_type_tag_to_string (type_tag)); + return FALSE; + } + *gsize_out = (gsize)arg_in->v_int64; + return TRUE; + case GI_TYPE_TAG_UINT64: + if (arg_in->v_uint64 > G_MAXSIZE) { + PyErr_Format (PyExc_TypeError, + "Unable to marshal %s to gsize", + g_type_tag_to_string (type_tag)); + return FALSE; + } + *gsize_out = (gsize)arg_in->v_uint64; + return TRUE; + default: + PyErr_Format (PyExc_TypeError, + "Unable to marshal %s to gsize", + g_type_tag_to_string (type_tag)); + return FALSE; + } +} + +static gboolean +_pygi_marshal_from_py_array (PyGIInvokeState *state, + PyGICallableCache *callable_cache, + PyGIArgCache *arg_cache, + PyObject *py_arg, + GIArgument *arg, + gpointer *cleanup_data) +{ + PyGIMarshalFromPyFunc from_py_marshaller; + guint i = 0; + gsize success_count = 0; + Py_ssize_t py_length; + guint length; + guint item_size; + gboolean is_ptr_array; + GArray *array_ = NULL; + PyGISequenceCache *sequence_cache = (PyGISequenceCache *)arg_cache; + PyGIArgGArray *array_cache = (PyGIArgGArray *)arg_cache; + GITransfer cleanup_transfer = arg_cache->transfer; + + + if (py_arg == Py_None) { + arg->v_pointer = NULL; + return TRUE; + } + + if (!PySequence_Check (py_arg)) { + PyErr_Format (PyExc_TypeError, "Must be sequence, not %s", + Py_TYPE (py_arg)->tp_name); + return FALSE; + } + + py_length = PySequence_Length (py_arg); + if (py_length < 0) + return FALSE; + + if (!pygi_guint_from_pyssize (py_length, &length)) + return FALSE; + + if (array_cache->fixed_size >= 0 && + (guint)array_cache->fixed_size != length) { + PyErr_Format (PyExc_ValueError, "Must contain %zd items, not %u", + array_cache->fixed_size, length); + + return FALSE; + } + + item_size = (guint)array_cache->item_size; + is_ptr_array = (array_cache->array_type == GI_ARRAY_TYPE_PTR_ARRAY); + if (is_ptr_array) { + array_ = (GArray *)g_ptr_array_sized_new (length); + } else { + array_ = g_array_sized_new (array_cache->is_zero_terminated, + TRUE, + item_size, + length); + } + + if (array_ == NULL) { + PyErr_NoMemory (); + return FALSE; + } + + if (sequence_cache->item_cache->type_tag == GI_TYPE_TAG_UINT8 && + PyBytes_Check (py_arg)) { + gchar *data = PyBytes_AsString (py_arg); + + /* Avoid making a copy if the data + * is not transferred to the C function + * and cannot not be modified by it. + */ + if (array_cache->array_type == GI_ARRAY_TYPE_C && + arg_cache->transfer == GI_TRANSFER_NOTHING && + !array_cache->is_zero_terminated) { + g_free (array_->data); + array_->data = data; + cleanup_transfer = GI_TRANSFER_EVERYTHING; + } else { + memcpy (array_->data, data, length); + } + array_->len = length; + if (array_cache->is_zero_terminated) { + /* If array_ has been created with zero_termination, space for the + * terminator is properly allocated, so we're not off-by-one here. */ + array_->data[length] = '\0'; + } + goto array_success; + } + + from_py_marshaller = sequence_cache->item_cache->from_py_marshaller; + for (i = 0, success_count = 0; i < length; i++) { + GIArgument item = {0}; + gpointer item_cleanup_data = NULL; + PyObject *py_item = PySequence_GetItem (py_arg, i); + if (py_item == NULL) + goto err; + + if (!from_py_marshaller ( state, + callable_cache, + sequence_cache->item_cache, + py_item, + &item, + &item_cleanup_data)) { + Py_DECREF (py_item); + goto err; + } + Py_DECREF (py_item); + + if (item_cleanup_data != NULL && item_cleanup_data != item.v_pointer) { + /* We only support one level of data discrepancy between an items + * data and its cleanup data. This is because we only track a single + * extra cleanup data pointer per-argument and cannot track the entire + * array of items differing data and cleanup_data. + * For example, this would fail if trying to marshal an array of + * callback closures marked with SCOPE call type where the cleanup data + * is different from the items v_pointer, likewise an array of arrays. + */ + PyErr_SetString(PyExc_RuntimeError, "Cannot cleanup item data for array due to " + "the items data its cleanup data being different."); + goto err; + } + + /* FIXME: it is much more efficent to have seperate marshaller + * for ptr arrays than doing the evaluation + * and casting each loop iteration + */ + if (is_ptr_array) { + g_ptr_array_add((GPtrArray *)array_, item.v_pointer); + } else if (sequence_cache->item_cache->is_pointer) { + /* if the item is a pointer, simply copy the pointer */ + g_assert (item_size == sizeof (item.v_pointer)); + g_array_insert_val (array_, i, item); + } else if (sequence_cache->item_cache->type_tag == GI_TYPE_TAG_INTERFACE) { + /* Special case handling of flat arrays of gvalue/boxed/struct */ + PyGIInterfaceCache *item_iface_cache = (PyGIInterfaceCache *) sequence_cache->item_cache; + GIBaseInfo *base_info = (GIBaseInfo *) item_iface_cache->interface_info; + GIInfoType info_type = g_base_info_get_type (base_info); + + switch (info_type) { + case GI_INFO_TYPE_UNION: + case GI_INFO_TYPE_STRUCT: + { + PyGIArgCache *item_arg_cache = (PyGIArgCache *)item_iface_cache; + PyGIMarshalCleanupFunc from_py_cleanup = item_arg_cache->from_py_cleanup; + + if (g_type_is_a (item_iface_cache->g_type, G_TYPE_VALUE)) { + /* Special case GValue flat arrays to properly init and copy the contents. */ + GValue* dest = (GValue*)(void*)(array_->data + (i * item_size)); + if (item.v_pointer != NULL) { + memset (dest, 0, item_size); + g_value_init (dest, G_VALUE_TYPE ((GValue*) item.v_pointer)); + g_value_copy ((GValue*) item.v_pointer, dest); + } + /* Manually increment the length because we are manually setting the memory. */ + array_->len++; + + } else { + /* Handles flat arrays of boxed or struct types. */ + g_array_insert_vals (array_, i, item.v_pointer, 1); + } + + /* Cleanup any memory left by the per-item marshaler because + * _pygi_marshal_cleanup_from_py_array will not know about this + * due to "item" being a temporarily marshaled value done on the stack. + */ + if (from_py_cleanup) + from_py_cleanup (state, item_arg_cache, py_item, item_cleanup_data, TRUE); + + break; + } + default: + g_array_insert_val (array_, i, item); + } + } else { + /* default value copy of a simple type */ + g_array_insert_val (array_, i, item); + } + + success_count++; + } + goto array_success; + +err: + if (sequence_cache->item_cache->from_py_cleanup != NULL) { + gsize j; + PyGIMarshalCleanupFunc cleanup_func = + sequence_cache->item_cache->from_py_cleanup; + + /* Only attempt per item cleanup on pointer items */ + if (sequence_cache->item_cache->is_pointer) { + for(j = 0; j < success_count; j++) { + PyObject *py_seq_item = PySequence_GetItem (py_arg, j); + cleanup_func (state, + sequence_cache->item_cache, + py_seq_item, + is_ptr_array ? + g_ptr_array_index ((GPtrArray *)array_, j) : + g_array_index (array_, gpointer, j), + TRUE); + Py_DECREF (py_seq_item); + } + } + } + + if (is_ptr_array) + g_ptr_array_free ( ( GPtrArray *)array_, TRUE); + else + g_array_free (array_, TRUE); + _PyGI_ERROR_PREFIX ("Item %u: ", i); + return FALSE; + +array_success: + if (array_cache->len_arg_index >= 0) { + /* we have an child arg to handle */ + PyGIArgCache *child_cache = + _pygi_callable_cache_get_arg (callable_cache, (guint)array_cache->len_arg_index); + + if (!gi_argument_from_py_ssize_t (&state->args[child_cache->c_arg_index].arg_value, + length, + child_cache->type_tag)) { + goto err; + } + } + + if (array_cache->array_type == GI_ARRAY_TYPE_C) { + /* In the case of GI_ARRAY_C, we give the data directly as the argument + * but keep the array_ wrapper as cleanup data so we don't have to find + * it's length again. + */ + arg->v_pointer = array_->data; + + if (cleanup_transfer == GI_TRANSFER_EVERYTHING) { + g_array_free (array_, FALSE); + *cleanup_data = NULL; + } else { + *cleanup_data = array_; + } + } else { + arg->v_pointer = array_; + + if (cleanup_transfer == GI_TRANSFER_NOTHING) { + /* Free everything in cleanup. */ + *cleanup_data = array_; + } else if (cleanup_transfer == GI_TRANSFER_CONTAINER) { + /* Make a shallow copy so we can free the elements later in cleanup + * because it is possible invoke will free the list before our cleanup. */ + *cleanup_data = is_ptr_array ? + (gpointer)g_ptr_array_ref ((GPtrArray *)array_) : + (gpointer)g_array_ref (array_); + } else { /* GI_TRANSFER_EVERYTHING */ + /* No cleanup, everything is given to the callee. */ + *cleanup_data = NULL; + } + } + + return TRUE; +} + +static void +_pygi_marshal_cleanup_from_py_array (PyGIInvokeState *state, + PyGIArgCache *arg_cache, + PyObject *py_arg, + gpointer data, + gboolean was_processed) +{ + if (was_processed) { + GArray *array_ = NULL; + GPtrArray *ptr_array_ = NULL; + PyGISequenceCache *sequence_cache = (PyGISequenceCache *)arg_cache; + PyGIArgGArray *array_cache = (PyGIArgGArray *)arg_cache; + + if (array_cache->array_type == GI_ARRAY_TYPE_PTR_ARRAY) { + ptr_array_ = (GPtrArray *) data; + } else { + array_ = (GArray *) data; + } + + /* clean up items first */ + if (sequence_cache->item_cache->from_py_cleanup != NULL) { + gsize i; + guint len; + PyGIMarshalCleanupFunc cleanup_func = + sequence_cache->item_cache->from_py_cleanup; + + g_assert (array_ || ptr_array_); + len = (array_ != NULL) ? array_->len : ptr_array_->len; + + for (i = 0; i < len; i++) { + gpointer item; + PyObject *py_item = NULL; + + /* case 1: GPtrArray */ + if (ptr_array_ != NULL) + item = g_ptr_array_index (ptr_array_, i); + /* case 2: C array or GArray with object pointers */ + else if (sequence_cache->item_cache->is_pointer) + item = g_array_index (array_, gpointer, i); + /* case 3: C array or GArray with simple types or structs */ + else { + item = array_->data + i * array_cache->item_size; + /* special-case hack: GValue array items do not get slice + * allocated in _pygi_marshal_from_py_array(), so we must + * not try to deallocate it as a slice and thus + * short-circuit cleanup_func. */ + if (cleanup_func == pygi_arg_gvalue_from_py_cleanup) { + g_value_unset ((GValue*) item); + continue; + } + } + + py_item = PySequence_GetItem (py_arg, i); + cleanup_func (state, sequence_cache->item_cache, py_item, item, TRUE); + Py_XDECREF (py_item); + } + } + + /* Only free the array when we didn't transfer ownership */ + if (array_cache->array_type == GI_ARRAY_TYPE_C) { + /* always free the GArray wrapper created in from_py marshaling and + * passed back as cleanup_data + */ + g_array_free (array_, arg_cache->transfer == GI_TRANSFER_NOTHING); + } else { + if (array_ != NULL) + g_array_unref (array_); + else + g_ptr_array_unref (ptr_array_); + } + } +} + +/* + * GArray from Python + */ +static PyObject * +_pygi_marshal_to_py_array (PyGIInvokeState *state, + PyGICallableCache *callable_cache, + PyGIArgCache *arg_cache, + GIArgument *arg, + gpointer *cleanup_data) +{ + GArray *array_; + PyObject *py_obj = NULL; + PyGISequenceCache *seq_cache = (PyGISequenceCache *)arg_cache; + PyGIArgGArray *array_cache = (PyGIArgGArray *)arg_cache; + guint processed_items = 0; + + /* GArrays make it easier to iterate over arrays + * with different element sizes but requires that + * we allocate a GArray if the argument was a C array + */ + if (array_cache->array_type == GI_ARRAY_TYPE_C) { + gsize len; + if (array_cache->fixed_size >= 0) { + g_assert(arg->v_pointer != NULL); + len = array_cache->fixed_size; + } else if (array_cache->is_zero_terminated) { + if (arg->v_pointer == NULL) { + len = 0; + } else if (array_cache->item_size == 1) { + len = strlen (arg->v_pointer); + } else if (array_cache->item_size == sizeof(gpointer)) { + len = g_strv_length ((gchar **)arg->v_pointer); + } else if (array_cache->item_size == sizeof(int)) { + for (len = 0; *(((int*)arg->v_pointer) + len); len++); + } else if (array_cache->item_size == sizeof(short)) { + for (len = 0; *(((short*)arg->v_pointer) + len); len++); + } else { + g_assert_not_reached (); + } + } else { + GIArgument *len_arg = &state->args[array_cache->len_arg_index].arg_value; + PyGIArgCache *sub_cache = _pygi_callable_cache_get_arg (callable_cache, + (guint)array_cache->len_arg_index); + + if (!gi_argument_to_gsize (len_arg, &len, sub_cache->type_tag)) { + return NULL; + } + } + + array_ = g_array_new (FALSE, + FALSE, + (guint)array_cache->item_size); + if (array_ == NULL) { + PyErr_NoMemory (); + + if (arg_cache->transfer == GI_TRANSFER_EVERYTHING && arg->v_pointer != NULL) + g_free (arg->v_pointer); + + return NULL; + } + + if (array_->data != NULL) + g_free (array_->data); + array_->data = arg->v_pointer; + array_->len = (guint)len; + } else { + array_ = arg->v_pointer; + } + + if (seq_cache->item_cache->type_tag == GI_TYPE_TAG_UINT8) { + if (arg->v_pointer == NULL) { + py_obj = PyBytes_FromString (""); + } else { + py_obj = PyBytes_FromStringAndSize (array_->data, array_->len); + } + } else { + if (arg->v_pointer == NULL) { + py_obj = PyList_New (0); + } else { + guint i; + + gsize item_size; + PyGIMarshalToPyFunc item_to_py_marshaller; + PyGIArgCache *item_arg_cache; + GPtrArray *item_cleanups; + + py_obj = PyList_New (array_->len); + if (py_obj == NULL) + goto err; + + item_cleanups = g_ptr_array_sized_new (array_->len); + *cleanup_data = item_cleanups; + + item_arg_cache = seq_cache->item_cache; + item_to_py_marshaller = item_arg_cache->to_py_marshaller; + + item_size = g_array_get_element_size (array_); + + for (i = 0; i < array_->len; i++) { + GIArgument item_arg = {0}; + PyObject *py_item; + gpointer item_cleanup_data = NULL; + + /* If we are receiving an array of pointers, simply assign the pointer + * and move on, letting the per-item marshaler deal with the + * various transfer modes and ref counts (e.g. g_variant_ref_sink). + */ + if (array_cache->array_type == GI_ARRAY_TYPE_PTR_ARRAY) { + item_arg.v_pointer = g_ptr_array_index ( ( GPtrArray *)array_, i); + + } else if (item_arg_cache->is_pointer) { + item_arg.v_pointer = g_array_index (array_, gpointer, i); + + } 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() */ + switch (g_base_info_get_type (iface_cache->interface_info)) { + case GI_INFO_TYPE_STRUCT: + if (arg_cache->transfer == GI_TRANSFER_EVERYTHING && + !g_type_is_a (iface_cache->g_type, G_TYPE_BOXED)) { + /* array elements are structs */ + gpointer *_struct = g_malloc (item_size); + memcpy (_struct, array_->data + i * item_size, + item_size); + item_arg.v_pointer = _struct; + } else { + item_arg.v_pointer = array_->data + i * item_size; + } + break; + case GI_INFO_TYPE_ENUM: + memcpy (&item_arg, array_->data + i * item_size, item_size); + break; + default: + item_arg.v_pointer = g_array_index (array_, gpointer, i); + break; + } + } else { + memcpy (&item_arg, array_->data + i * item_size, item_size); + } + + py_item = item_to_py_marshaller ( state, + callable_cache, + item_arg_cache, + &item_arg, + &item_cleanup_data); + + g_ptr_array_index (item_cleanups, i) = item_cleanup_data; + + if (py_item == NULL) { + Py_CLEAR (py_obj); + + if (array_cache->array_type == GI_ARRAY_TYPE_C) + g_array_unref (array_); + + g_ptr_array_unref (item_cleanups); + + goto err; + } + PyList_SET_ITEM (py_obj, i, py_item); + processed_items++; + } + } + } + + if (array_cache->array_type == GI_ARRAY_TYPE_C) + g_array_free (array_, FALSE); + + return py_obj; + +err: + if (array_cache->array_type == GI_ARRAY_TYPE_C) { + g_array_free (array_, arg_cache->transfer == GI_TRANSFER_EVERYTHING); + } else { + /* clean up unprocessed items */ + if (seq_cache->item_cache->to_py_cleanup != NULL) { + guint j; + PyGIMarshalToPyCleanupFunc cleanup_func = seq_cache->item_cache->to_py_cleanup; + for (j = processed_items; j < array_->len; j++) { + cleanup_func (state, + seq_cache->item_cache, + NULL, + g_array_index (array_, gpointer, j), + FALSE); + } + } + + if (arg_cache->transfer == GI_TRANSFER_EVERYTHING) + g_array_free (array_, TRUE); + } + + return NULL; +} + +static GArray* +_wrap_c_array (PyGIInvokeState *state, + PyGIArgGArray *array_cache, + gpointer data) +{ + GArray *array_; + gsize len = 0; + + if (array_cache->fixed_size >= 0) { + len = array_cache->fixed_size; + } else if (array_cache->is_zero_terminated) { + if (array_cache->item_size == sizeof(gpointer)) + len = g_strv_length ((gchar **)data); + else if (array_cache->item_size == 1) + len = strlen ((gchar*)data); + else if (array_cache->item_size == sizeof(int)) + for (len = 0; *(((int*)data) + len); len++); + else if (array_cache->item_size == sizeof(short)) + for (len = 0; *(((short*)data) + len); len++); + else + g_assert_not_reached (); + } else if (array_cache->len_arg_index >= 0) { + GIArgument *len_arg = &state->args[array_cache->len_arg_index].arg_value; + len = len_arg->v_long; + } + + array_ = g_array_new (FALSE, + FALSE, + (guint)array_cache->item_size); + + if (array_ == NULL) + return NULL; + + g_free (array_->data); + array_->data = data; + array_->len = (guint)len; + + return array_; +} + +static void +_pygi_marshal_cleanup_to_py_array (PyGIInvokeState *state, + PyGIArgCache *arg_cache, + gpointer cleanup_data, + gpointer data, + gboolean was_processed) +{ + GArray *array_ = NULL; + GPtrArray *ptr_array_ = NULL; + PyGISequenceCache *sequence_cache = (PyGISequenceCache *)arg_cache; + PyGIArgGArray *array_cache = (PyGIArgGArray *)arg_cache; + gboolean free_array = FALSE; + gboolean free_array_full = TRUE; + + if (arg_cache->transfer == GI_TRANSFER_EVERYTHING || + arg_cache->transfer == GI_TRANSFER_CONTAINER) { + free_array = TRUE; + } + + /* If this isn't a garray create one to help process variable sized + array elements */ + if (array_cache->array_type == GI_ARRAY_TYPE_C) { + array_ = _wrap_c_array (state, array_cache, data); + + if (array_ == NULL) + return; + + free_array = TRUE; + free_array_full = arg_cache->transfer != GI_TRANSFER_NOTHING; + } else if (array_cache->array_type == GI_ARRAY_TYPE_PTR_ARRAY) { + ptr_array_ = (GPtrArray *) data; + } else { + array_ = (GArray *) data; + } + + if (sequence_cache->item_cache->to_py_cleanup != NULL) { + GPtrArray *item_cleanups = (GPtrArray *) cleanup_data; + gsize i; + guint len; + PyGIMarshalToPyCleanupFunc cleanup_func = sequence_cache->item_cache->to_py_cleanup; + + g_assert (array_ || ptr_array_); + len = (array_ != NULL) ? array_->len : ptr_array_->len; + + for (i = 0; i < len; i++) { + cleanup_func (state, + sequence_cache->item_cache, + g_ptr_array_index(item_cleanups, i), + (array_ != NULL) ? g_array_index (array_, gpointer, i) : g_ptr_array_index (ptr_array_, i), + was_processed); + } + } + + if (cleanup_data) + g_ptr_array_unref ((GPtrArray *) cleanup_data); + + if (free_array) { + if (array_ != NULL) + g_array_free (array_, free_array_full); + else + g_ptr_array_free (ptr_array_, free_array_full); + } +} + +static void +_array_cache_free_func (PyGIArgGArray *cache) +{ + if (cache != NULL) { + pygi_arg_cache_free (((PyGISequenceCache *)cache)->item_cache); + g_slice_free (PyGIArgGArray, cache); + } +} + +PyGIArgCache* +pygi_arg_garray_len_arg_setup (PyGIArgCache *arg_cache, + GITypeInfo *type_info, + PyGICallableCache *callable_cache, + PyGIDirection direction, + gssize arg_index, + gssize *py_arg_index) +{ + PyGIArgGArray *seq_cache = (PyGIArgGArray *)arg_cache; + + /* attempt len_arg_index setup for the first time */ + if (seq_cache->len_arg_index < 0) { + seq_cache->len_arg_index = g_type_info_get_array_length (type_info); + + /* offset by self arg for methods and vfuncs */ + if (seq_cache->len_arg_index >= 0 && callable_cache != NULL) { + seq_cache->len_arg_index += callable_cache->args_offset; + } + } + + if (seq_cache->len_arg_index >= 0) { + PyGIArgCache *child_cache = NULL; + + child_cache = _pygi_callable_cache_get_arg (callable_cache, + (guint)seq_cache->len_arg_index); + if (child_cache == NULL) { + child_cache = pygi_arg_cache_alloc (); + } else { + /* If the "length" arg cache already exists (the length comes before + * the array in the argument list), remove it from the to_py_args list + * because it does not belong in "to python" return tuple. The length + * will implicitly be a part of the returned Python list. + */ + if (direction & PYGI_DIRECTION_TO_PYTHON) { + callable_cache->to_py_args = + g_slist_remove (callable_cache->to_py_args, child_cache); + } + + /* This is a case where the arg cache already exists and has been + * setup by another array argument sharing the same length argument. + * See: gi_marshalling_tests_multi_array_key_value_in + */ + if (child_cache->meta_type == PYGI_META_ARG_TYPE_CHILD) + return child_cache; + } + + /* There is a length argument for this array, so increment the number + * of "to python" child arguments when applicable. + */ + if (direction & PYGI_DIRECTION_TO_PYTHON) + callable_cache->n_to_py_child_args++; + + child_cache->meta_type = PYGI_META_ARG_TYPE_CHILD; + child_cache->direction = direction; + child_cache->to_py_marshaller = pygi_marshal_to_py_basic_type_cache_adapter; + child_cache->from_py_marshaller = pygi_marshal_from_py_basic_type_cache_adapter; + child_cache->py_arg_index = -1; + + /* ugly edge case code: + * + * When the length comes before the array parameter we need to update + * indexes of arguments after the index argument. + */ + if (seq_cache->len_arg_index < arg_index && direction & PYGI_DIRECTION_FROM_PYTHON) { + guint i; + (*py_arg_index) -= 1; + callable_cache->n_py_args -= 1; + + for (i = (guint)seq_cache->len_arg_index + 1; + (gsize)i < _pygi_callable_cache_args_len (callable_cache); i++) { + PyGIArgCache *update_cache = _pygi_callable_cache_get_arg (callable_cache, i); + if (update_cache == NULL) + break; + + update_cache->py_arg_index -= 1; + } + } + + _pygi_callable_cache_set_arg (callable_cache, (guint)seq_cache->len_arg_index, child_cache); + return child_cache; + } + + return NULL; +} + +static gboolean +pygi_arg_garray_setup (PyGIArgGArray *sc, + GITypeInfo *type_info, + GIArgInfo *arg_info, /* may be NULL for return arguments */ + GITransfer transfer, + PyGIDirection direction, + PyGICallableCache *callable_cache) +{ + GITypeInfo *item_type_info; + PyGIArgCache *arg_cache = (PyGIArgCache *)sc; + + if (!pygi_arg_sequence_setup ((PyGISequenceCache *)sc, + type_info, + arg_info, + transfer, + direction, + callable_cache)) { + return FALSE; + } + + ((PyGIArgCache *)sc)->destroy_notify = (GDestroyNotify)_array_cache_free_func; + sc->array_type = g_type_info_get_array_type (type_info); + sc->is_zero_terminated = g_type_info_is_zero_terminated (type_info); + sc->fixed_size = g_type_info_get_array_fixed_size (type_info); + sc->len_arg_index = -1; /* setup by pygi_arg_garray_len_arg_setup */ + + item_type_info = g_type_info_get_param_type (type_info, 0); + sc->item_size = _pygi_g_type_info_size (item_type_info); + g_base_info_unref ( (GIBaseInfo *)item_type_info); + + if (direction & PYGI_DIRECTION_FROM_PYTHON) { + arg_cache->from_py_marshaller = _pygi_marshal_from_py_array; + arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_array; + } + + if (direction & PYGI_DIRECTION_TO_PYTHON) { + arg_cache->to_py_marshaller = _pygi_marshal_to_py_array; + arg_cache->to_py_cleanup = _pygi_marshal_cleanup_to_py_array; + } + + return TRUE; +} + +PyGIArgCache * +pygi_arg_garray_new_from_info (GITypeInfo *type_info, + GIArgInfo *arg_info, + GITransfer transfer, + PyGIDirection direction, + PyGICallableCache *callable_cache) +{ + PyGIArgGArray *array_cache = g_slice_new0 (PyGIArgGArray); + if (array_cache == NULL) + return NULL; + + if (!pygi_arg_garray_setup (array_cache, + type_info, + arg_info, + transfer, + direction, + callable_cache)) { + pygi_arg_cache_free ( (PyGIArgCache *)array_cache); + return NULL; + } + + return (PyGIArgCache *)array_cache; +} diff --git a/gi/pygi-array.h b/gi/pygi-array.h new file mode 100644 index 0000000..718c7cd --- /dev/null +++ b/gi/pygi-array.h @@ -0,0 +1,43 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- + * vim: tabstop=4 shiftwidth=4 expandtab + * + * Copyright (C) 2014 Simon Feltman <sfeltman@gnome.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __PYGI_ARRAY_H__ +#define __PYGI_ARRAY_H__ + +#include <girepository.h> +#include "pygi-cache.h" + +G_BEGIN_DECLS + +PyGIArgCache *pygi_arg_garray_new_from_info (GITypeInfo *type_info, + GIArgInfo *arg_info, /* may be null */ + GITransfer transfer, + PyGIDirection direction, + PyGICallableCache *callable_cache); + +PyGIArgCache *pygi_arg_garray_len_arg_setup (PyGIArgCache *arg_cache, + GITypeInfo *type_info, + PyGICallableCache *callable_cache, + PyGIDirection direction, + gssize arg_index, + gssize *py_arg_index); + +G_END_DECLS + +#endif /*__PYGI_ARRAY_H__*/ diff --git a/gi/pygi-basictype.c b/gi/pygi-basictype.c new file mode 100644 index 0000000..82f8a85 --- /dev/null +++ b/gi/pygi-basictype.c @@ -0,0 +1,1338 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- + * vim: tabstop=4 shiftwidth=4 expandtab + * + * Copyright (C) 2011 John (J5) Palmieri <johnp@redhat.com> + * Copyright (C) 2014 Simon Feltman <sfeltman@gnome.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <Python.h> + +#include "pygi-type.h" +#include "pygi-basictype.h" +#include "pygi-argument.h" +#include "pygi-util.h" + +#if defined(G_OS_WIN32) +#include <float.h> +static gboolean +pygi_isfinite (gdouble value) { + return _finite (value); +} +#else +#include <math.h> +static gboolean +pygi_isfinite (gdouble value) { + return isfinite (value); +} +#endif + +static gboolean +pygi_gpointer_from_py (PyObject *py_arg, gpointer *result) +{ + void* temp; + + if (py_arg == Py_None) { + *result = NULL; + return TRUE; + } else if (PyCapsule_CheckExact (py_arg)) { + temp = PyCapsule_GetPointer (py_arg, NULL); + if (temp == NULL) + return FALSE; + *result = temp; + return TRUE; + } else if (PyLong_Check(py_arg)) { + temp = PyLong_AsVoidPtr (py_arg); + if (PyErr_Occurred ()) + return FALSE; + *result = temp; + return TRUE; + } else { + PyErr_SetString(PyExc_ValueError, + "Pointer arguments are restricted to integers, capsules, and None. " + "See: https://bugzilla.gnome.org/show_bug.cgi?id=683599"); + return FALSE; + } +} + +static gboolean +marshal_from_py_void (PyGIInvokeState *state, + PyGICallableCache *callable_cache, + PyGIArgCache *arg_cache, + PyObject *py_arg, + GIArgument *arg, + gpointer *cleanup_data) +{ + g_warn_if_fail (arg_cache->transfer == GI_TRANSFER_NOTHING); + + if (pygi_gpointer_from_py (py_arg, &(arg->v_pointer))) { + *cleanup_data = arg->v_pointer; + return TRUE; + } + + return FALSE; +} + +PyObject * +pygi_gsize_to_py (gsize value) +{ + return PyLong_FromSize_t (value); +} + +PyObject * +pygi_gssize_to_py (gssize value) +{ + return PyLong_FromSsize_t (value); +} + +static PyObject * +base_float_checks (PyObject *object) +{ + if (!PyNumber_Check (object)) { + PyErr_Format (PyExc_TypeError, "Must be number, not %s", + Py_TYPE (object)->tp_name); + return NULL; + } + + return PyNumber_Float (object); +} + +gboolean +pygi_gdouble_from_py (PyObject *py_arg, gdouble *result) +{ + PyObject *py_float; + gdouble temp; + + py_float = base_float_checks (py_arg); + if (py_float == NULL) + return FALSE; + + temp = PyFloat_AsDouble (py_float); + Py_DECREF (py_float); + + if (PyErr_Occurred ()) + return FALSE; + + *result = temp; + + return TRUE; +} + +PyObject * +pygi_gdouble_to_py (gdouble value) +{ + return PyFloat_FromDouble (value); +} + +gboolean +pygi_gfloat_from_py (PyObject *py_arg, gfloat *result) +{ + gdouble double_; + PyObject *py_float; + + py_float = base_float_checks (py_arg); + if (py_float == NULL) + return FALSE; + + double_ = PyFloat_AsDouble (py_float); + if (PyErr_Occurred ()) { + Py_DECREF (py_float); + return FALSE; + } + + if (pygi_isfinite (double_) && (double_ < -G_MAXFLOAT || double_ > G_MAXFLOAT)) { + PyObject *min, *max; + + min = pygi_gfloat_to_py (-G_MAXFLOAT); + max = pygi_gfloat_to_py (G_MAXFLOAT); + PyErr_Format ( + PyExc_OverflowError, "%S not in range %S to %S", + py_float, min, max); + Py_DECREF (min); + Py_DECREF (max); + Py_DECREF (py_float); + return FALSE; + } + + Py_DECREF (py_float); + *result = (gfloat)double_; + + return TRUE; +} + +PyObject * +pygi_gfloat_to_py (gfloat value) +{ + return PyFloat_FromDouble (value); +} + +gboolean +pygi_gunichar_from_py (PyObject *py_arg, gunichar *result) +{ + Py_ssize_t size; + gchar *string_; + + if (py_arg == Py_None) { + *result = 0; + return FALSE; + } + + if (PyUnicode_Check (py_arg)) { + PyObject *py_bytes; + + size = PyUnicode_GET_LENGTH (py_arg); + py_bytes = PyUnicode_AsUTF8String (py_arg); + if (!py_bytes) + return FALSE; + + string_ = g_strdup(PyBytes_AsString (py_bytes)); + Py_DECREF (py_bytes); + } else { + PyErr_Format (PyExc_TypeError, "Must be string, not %s", + Py_TYPE (py_arg)->tp_name); + return FALSE; + } + + if (size != 1) { + PyErr_Format (PyExc_TypeError, "Must be a one character string, not %lld characters", + (long long) size); + g_free (string_); + return FALSE; + } + + *result = g_utf8_get_char (string_); + g_free (string_); + + return TRUE; +} + +static PyObject * +pygi_gunichar_to_py (gunichar value) +{ + PyObject *py_obj = NULL; + + /* Preserve the bidirectional mapping between 0 and "" */ + if (value == 0) { + py_obj = PyUnicode_FromString (""); + } else if (g_unichar_validate (value)) { + gchar utf8[6]; + gint bytes; + + bytes = g_unichar_to_utf8 (value, utf8); + py_obj = PyUnicode_FromStringAndSize ((char*)utf8, bytes); + } else { + /* TODO: Convert the error to an exception. */ + PyErr_Format (PyExc_TypeError, + "Invalid unicode codepoint %" G_GUINT32_FORMAT, + value); + } + + return py_obj; +} + +static gboolean +pygi_gtype_from_py (PyObject *py_arg, GType *type) +{ + GType temp = pyg_type_from_object (py_arg); + + if (temp == 0) { + if (!PyErr_Occurred ()) { + PyErr_SetString (PyExc_ValueError, "Invalid GType"); + return FALSE; + } + PyErr_Format (PyExc_TypeError, "Must be GObject.GType, not %s", + Py_TYPE (py_arg)->tp_name); + return FALSE; + } + + *type = temp; + + return TRUE; +} + +gboolean +pygi_utf8_from_py (PyObject *py_arg, gchar **result) +{ + gchar *string_; + + if (py_arg == Py_None) { + *result = NULL; + return TRUE; + } + + if (PyUnicode_Check (py_arg)) { + PyObject *pystr_obj = PyUnicode_AsUTF8String (py_arg); + if (!pystr_obj) + return FALSE; + + string_ = g_strdup (PyBytes_AsString (pystr_obj)); + Py_DECREF (pystr_obj); + } + else { + PyErr_Format (PyExc_TypeError, "Must be string, not %s", + Py_TYPE (py_arg)->tp_name); + return FALSE; + } + + *result = string_; + return TRUE; +} + +G_GNUC_UNUSED +static gboolean +filename_from_py_unix (PyObject *py_arg, gchar **result) +{ + gchar *filename; + + if (py_arg == Py_None) { + *result = NULL; + return TRUE; + } + + if (PyBytes_Check (py_arg)) { + char *buffer; + + if (PyBytes_AsStringAndSize (py_arg, &buffer, NULL) == -1) + return FALSE; + + filename = g_strdup (buffer); + } else if (PyUnicode_Check (py_arg)) { + PyObject *bytes; + char *buffer; + + bytes = PyUnicode_EncodeFSDefault (py_arg); + + if (!bytes) + return FALSE; + + if (PyBytes_AsStringAndSize (bytes, &buffer, NULL) == -1) { + Py_DECREF (bytes); + return FALSE; + } + + filename = g_strdup (buffer); + Py_DECREF (bytes); + } else { + PyErr_Format (PyExc_TypeError, "Must be bytes, not %s", + Py_TYPE (py_arg)->tp_name); + return FALSE; + } + + *result = filename; + return TRUE; +} + +G_GNUC_UNUSED +static gboolean +filename_from_py_win32 (PyObject *py_arg, gchar **result) +{ + gchar *filename; + + if (py_arg == Py_None) { + *result = NULL; + return TRUE; + } + + if (PyBytes_Check (py_arg)) { + PyObject *uni_arg; + gboolean temp_result; + char *buffer; + + if (PyBytes_AsStringAndSize (py_arg, &buffer, NULL) == -1) + return FALSE; + + uni_arg = PyUnicode_DecodeFSDefault (buffer); + if (!uni_arg) + return FALSE; + temp_result = filename_from_py_win32 (uni_arg, result); + Py_DECREF (uni_arg); + return temp_result; + } else if (PyUnicode_Check (py_arg)) { + PyObject *bytes, *temp_uni; + char *buffer; + + /* The roundtrip merges lone surrogates, so we get the same output as + * with Py 2. Requires 3.4+ because of https://bugs.python.org/issue27971 + * Separated lone surrogates can occur when concatenating two paths. + */ + bytes = PyUnicode_AsEncodedString (py_arg, "utf-16-le", "surrogatepass"); + if (!bytes) + return FALSE; + temp_uni = PyUnicode_FromEncodedObject (bytes, "utf-16-le", "surrogatepass"); + Py_DECREF (bytes); + if (!temp_uni) + return FALSE; + /* glib uses utf-8, so encode to that and allow surrogates so we can + * represent all possible path values + */ + bytes = PyUnicode_AsEncodedString (temp_uni, "utf-8", "surrogatepass"); + Py_DECREF (temp_uni); + if (!bytes) + return FALSE; + + if (PyBytes_AsStringAndSize (bytes, &buffer, NULL) == -1) { + Py_DECREF (bytes); + return FALSE; + } + + filename = g_strdup (buffer); + Py_DECREF (bytes); + } else { + PyErr_Format (PyExc_TypeError, "Must be str, not %s", + Py_TYPE (py_arg)->tp_name); + return FALSE; + } + + *result = filename; + return TRUE; +} + +static gboolean +pygi_filename_from_py (PyObject *py_arg, gchar **result) +{ +#ifdef G_OS_WIN32 + return filename_from_py_win32 (py_arg, result); +#else + return filename_from_py_unix (py_arg, result); +#endif +} + +static PyObject * +base_number_checks (PyObject *object) +{ + PyObject *number; + + if (!PyNumber_Check (object)) { + PyErr_Format (PyExc_TypeError, "Must be number, not %s", + Py_TYPE (object)->tp_name); + return NULL; + } + + number = PyNumber_Long (object); + + if (number == NULL) { + PyErr_SetString (PyExc_TypeError, "expected int argument"); + return NULL; + } + + return number; +} + +gboolean +pygi_gboolean_from_py (PyObject *object, gboolean *result) +{ + int value = PyObject_IsTrue (object); + if (value == -1) + return FALSE; + *result = (gboolean)value; + return TRUE; +} + +PyObject * +pygi_gboolean_to_py (gboolean value) +{ + return PyBool_FromLong (value); +} + +/* A super set of pygi_gint8_from_py (also handles unicode) */ +gboolean +pygi_gschar_from_py (PyObject *object, gint8 *result) +{ + if (PyUnicode_Check (object)) { + gunichar uni; + PyObject *temp; + gboolean status; + + if (!pygi_gunichar_from_py (object, &uni)) + return FALSE; + + temp = pygi_guint32_to_py (uni); + status = pygi_gint8_from_py (temp, result); + Py_DECREF (temp); + return status; + } else { + /* pygi_gint8_from_py handles numbers and bytes */ + return pygi_gint8_from_py (object, result); + } + + return FALSE; +} + +/* A super set of pygi_guint8_from_py (also handles unicode) */ +gboolean +pygi_guchar_from_py (PyObject *object, guchar *result) +{ + if (PyUnicode_Check (object)) { + gunichar uni; + PyObject *temp; + gboolean status; + gint8 codepoint; + + if (!pygi_gunichar_from_py (object, &uni)) + return FALSE; + + temp = pygi_guint32_to_py (uni); + status = pygi_gint8_from_py (temp, &codepoint); + Py_DECREF (temp); + if (status) + *result = (guchar)codepoint; + return status; + } else { + /* pygi_guint8_from_py handles numbers and bytes */ + return pygi_guint8_from_py (object, result); + } +} + +gboolean +pygi_gint_from_py (PyObject *object, gint *result) +{ + long long_value; + PyObject *number; + + number = base_number_checks (object); + if (number == NULL) + return FALSE; + + long_value = PyLong_AsLong (number); + if (PyErr_Occurred ()) { + if (PyErr_ExceptionMatches (PyExc_OverflowError)) + goto overflow; + Py_DECREF (number); + return FALSE; + } else if (long_value < G_MININT || long_value > G_MAXINT) { + goto overflow; + } + + Py_DECREF (number); + *result = (gint)long_value; + return TRUE; + +overflow: + PyErr_Clear (); + PyErr_Format ( + PyExc_OverflowError, "%S not in range %d to %d", + number, (int)G_MININT, (int)G_MAXINT); + Py_DECREF (number); + return FALSE; +} + +PyObject * +pygi_gint_to_py (gint value) +{ + return PyLong_FromLong (value); +} + +gboolean +pygi_guint_from_py (PyObject *object, guint *result) +{ + unsigned long long_value; + PyObject *number; + + number = base_number_checks (object); + if (number == NULL) + return FALSE; + + long_value = PyLong_AsUnsignedLong (number); + if (PyErr_Occurred ()) { + if (PyErr_ExceptionMatches (PyExc_OverflowError)) + goto overflow; + Py_DECREF (number); + return FALSE; + } else if (long_value > G_MAXUINT) { + goto overflow; + } + + Py_DECREF (number); + *result = (gint)long_value; + return TRUE; + +overflow: + PyErr_Clear (); + PyErr_Format ( + PyExc_OverflowError, "%S not in range %ld to %lu", + number, (long)0, (unsigned long)G_MAXUINT); + Py_DECREF (number); + return FALSE; +} + +PyObject * +pygi_guint_to_py (guint value) +{ +#if (G_MAXUINT <= LONG_MAX) + return PyLong_FromLong ((long) value); +#else + if (value <= LONG_MAX) + return PyLong_FromLong ((long) value); + return PyLong_FromUnsignedLong (value); +#endif +} + +gboolean +pygi_glong_from_py (PyObject *object, glong *result) +{ + long long_value; + PyObject *number; + + number = base_number_checks (object); + if (number == NULL) + return FALSE; + + long_value = PyLong_AsLong (number); + if (long_value == -1 && PyErr_Occurred ()) { + if (PyErr_ExceptionMatches (PyExc_OverflowError)) + goto overflow; + Py_DECREF (number); + return FALSE; + } + + Py_DECREF (number); + *result = (glong)long_value; + return TRUE; + +overflow: + PyErr_Clear (); + PyErr_Format ( + PyExc_OverflowError, "%S not in range %ld to %ld", + number, (long)G_MINLONG, (long)G_MAXLONG); + Py_DECREF (number); + return FALSE; +} + +PyObject * +pygi_glong_to_py (glong value) +{ + return PyLong_FromLong (value); +} + +gboolean +pygi_gulong_from_py (PyObject *object, gulong *result) +{ + unsigned long long_value; + PyObject *number; + + number = base_number_checks (object); + if (number == NULL) + return FALSE; + + long_value = PyLong_AsUnsignedLong (number); + if (PyErr_Occurred ()) { + if (PyErr_ExceptionMatches (PyExc_OverflowError)) + goto overflow; + Py_DECREF (number); + return FALSE; + } + + Py_DECREF (number); + *result = (gulong)long_value; + return TRUE; + +overflow: + PyErr_Clear (); + PyErr_Format ( + PyExc_OverflowError, "%S not in range %ld to %lu", + number, (long)0, (unsigned long)G_MAXULONG); + Py_DECREF (number); + return FALSE; +} + +PyObject * +pygi_gulong_to_py (gulong value) +{ + if (value <= LONG_MAX) + return PyLong_FromLong ((long) value); + else + return PyLong_FromUnsignedLong (value); +} + +gboolean +pygi_gint8_from_py (PyObject *object, gint8 *result) +{ + long long_value; + PyObject *number; + + if (PyBytes_Check (object)) { + if (PyBytes_Size (object) != 1) { + PyErr_Format (PyExc_TypeError, "Must be a single character"); + return FALSE; + } + + *result = (gint8)(PyBytes_AsString (object)[0]); + return TRUE; + } + + number = base_number_checks (object); + if (number == NULL) + return FALSE; + + long_value = PyLong_AsLong (number); + if (long_value == -1 && PyErr_Occurred()) { + if (PyErr_ExceptionMatches (PyExc_OverflowError)) + goto overflow; + Py_DECREF (number); + return FALSE; + } else if (long_value < G_MININT8 || long_value > G_MAXINT8) { + goto overflow; + } + + Py_DECREF (number); + *result = (gint8)long_value; + return TRUE; + +overflow: + PyErr_Clear (); + PyErr_Format ( + PyExc_OverflowError, "%S not in range %ld to %ld", + number, (long)G_MININT8, (long)G_MAXINT8); + Py_DECREF (number); + return FALSE; +} + +PyObject * +pygi_gint8_to_py (gint8 value) +{ + return PyLong_FromLong (value); +} + +gboolean +pygi_guint8_from_py (PyObject *object, guint8 *result) +{ + long long_value; + PyObject *number; + + if (PyBytes_Check (object)) { + if (PyBytes_Size (object) != 1) { + PyErr_Format (PyExc_TypeError, "Must be a single character"); + return FALSE; + } + + *result = (guint8)(PyBytes_AsString (object)[0]); + return TRUE; + } + + number = base_number_checks (object); + if (number == NULL) + return FALSE; + + long_value = PyLong_AsLong (number); + if (long_value == -1 && PyErr_Occurred()) { + if (PyErr_ExceptionMatches (PyExc_OverflowError)) + goto overflow; + Py_DECREF (number); + return FALSE; + } else if (long_value < 0 || long_value > G_MAXUINT8) { + goto overflow; + } + + Py_DECREF (number); + *result = (guint8)long_value; + return TRUE; + +overflow: + PyErr_Clear (); + PyErr_Format ( + PyExc_OverflowError, "%S not in range %ld to %ld", + number, (long)0, (long)G_MAXUINT8); + Py_DECREF (number); + return FALSE; +} + +PyObject * +pygi_guint8_to_py (guint8 value) +{ + return PyLong_FromLong (value); +} + +static gboolean +pygi_gint16_from_py (PyObject *object, gint16 *result) +{ + long long_value; + PyObject *number; + + number = base_number_checks (object); + if (number == NULL) + return FALSE; + + long_value = PyLong_AsLong (number); + if (long_value == -1 && PyErr_Occurred()) { + if (PyErr_ExceptionMatches (PyExc_OverflowError)) + goto overflow; + Py_DECREF (number); + return FALSE; + } else if (long_value < G_MININT16 || long_value > G_MAXINT16) { + goto overflow; + } + + Py_DECREF (number); + *result = (gint16)long_value; + return TRUE; + +overflow: + PyErr_Clear (); + PyErr_Format ( + PyExc_OverflowError, "%S not in range %ld to %ld", + number, (long)G_MININT16, (long)G_MAXINT16); + Py_DECREF (number); + return FALSE; +} + +static PyObject * +pygi_gint16_to_py (gint16 value) +{ + return PyLong_FromLong (value); +} + +static gboolean +pygi_guint16_from_py (PyObject *object, guint16 *result) +{ + long long_value; + PyObject *number; + + number = base_number_checks (object); + if (number == NULL) + return FALSE; + + long_value = PyLong_AsLong (number); + if (long_value == -1 && PyErr_Occurred()) { + if (PyErr_ExceptionMatches (PyExc_OverflowError)) + goto overflow; + Py_DECREF (number); + return FALSE; + } else if (long_value < 0 || long_value > G_MAXUINT16) { + goto overflow; + } + + Py_DECREF (number); + *result = (guint16)long_value; + return TRUE; + +overflow: + PyErr_Clear (); + PyErr_Format ( + PyExc_OverflowError, "%S not in range %ld to %ld", + number, (long)0, (long)G_MAXUINT16); + Py_DECREF (number); + return FALSE; +} + +static PyObject * +pygi_guint16_to_py (guint16 value) +{ + return PyLong_FromLong (value); +} + +static gboolean +pygi_gint32_from_py (PyObject *object, gint32 *result) +{ + long long_value; + PyObject *number; + + number = base_number_checks (object); + if (number == NULL) + return FALSE; + + long_value = PyLong_AsLong (number); + if (long_value == -1 && PyErr_Occurred()) { + if (PyErr_ExceptionMatches (PyExc_OverflowError)) + goto overflow; + Py_DECREF (number); + return FALSE; + } else if (long_value < G_MININT32 || long_value > G_MAXINT32) { + goto overflow; + } + + Py_DECREF (number); + *result = (gint32)long_value; + return TRUE; + +overflow: + PyErr_Clear (); + PyErr_Format ( + PyExc_OverflowError, "%S not in range %ld to %ld", + number, (long)G_MININT32, (long)G_MAXINT32); + Py_DECREF (number); + return FALSE; +} + +static PyObject * +pygi_gint32_to_py (gint32 value) +{ + return PyLong_FromLong (value); +} + +static gboolean +pygi_guint32_from_py (PyObject *object, guint32 *result) +{ + long long long_value; + PyObject *number; + + number = base_number_checks (object); + if (number == NULL) + return FALSE; + + long_value = PyLong_AsLongLong (number); + if (PyErr_Occurred ()) { + if (PyErr_ExceptionMatches (PyExc_OverflowError)) + goto overflow; + Py_DECREF (number); + return FALSE; + } else if (long_value < 0 || long_value > G_MAXUINT32) { + goto overflow; + } + + Py_DECREF (number); + *result = (guint32)long_value; + return TRUE; + +overflow: + PyErr_Clear (); + PyErr_Format ( + PyExc_OverflowError, "%S not in range %ld to %lu", + number, (long)0, (unsigned long)G_MAXUINT32); + Py_DECREF (number); + return FALSE; +} + +PyObject * +pygi_guint32_to_py (guint32 value) +{ +#if (G_MAXUINT <= LONG_MAX) + return PyLong_FromLong (value); +#else + if (value <= LONG_MAX) + return PyLong_FromLong((long) value); + else + return PyLong_FromLongLong (value); +#endif +} + +gboolean +pygi_gint64_from_py (PyObject *object, gint64 *result) +{ + long long long_value; + PyObject *number, *min, *max; + + number = base_number_checks (object); + if (number == NULL) + return FALSE; + + long_value = PyLong_AsLongLong (number); + if (PyErr_Occurred ()) { + if (PyErr_ExceptionMatches (PyExc_OverflowError)) + goto overflow; + Py_DECREF (number); + return FALSE; + } else if (long_value < G_MININT64 || long_value > G_MAXINT64) { + goto overflow; + } + + Py_DECREF (number); + *result = (gint64)long_value; + return TRUE; + +overflow: + PyErr_Clear (); + min = pygi_gint64_to_py (G_MININT64); + max = pygi_gint64_to_py (G_MAXINT64); + PyErr_Format ( + PyExc_OverflowError, "%S not in range %S to %S", + number, min, max); + Py_DECREF (number); + Py_DECREF (min); + Py_DECREF (max); + return FALSE; +} + +PyObject * +pygi_gint64_to_py (gint64 value) +{ + if (LONG_MIN <= value && value <= LONG_MAX) + return PyLong_FromLong((long) value); + else + return PyLong_FromLongLong (value); +} + +gboolean +pygi_guint64_from_py (PyObject *object, guint64 *result) +{ + unsigned long long long_value; + PyObject *number, *max; + + number = base_number_checks (object); + if (number == NULL) + return FALSE; + + long_value = PyLong_AsUnsignedLongLong (number); + if (PyErr_Occurred ()) { + if (PyErr_ExceptionMatches (PyExc_OverflowError)) + goto overflow; + Py_DECREF (number); + return FALSE; + } else if (long_value > G_MAXUINT64) { + goto overflow; + } + + Py_DECREF (number); + *result = (guint64)long_value; + return TRUE; + +overflow: + PyErr_Clear (); + max = pygi_guint64_to_py (G_MAXUINT64); + PyErr_Format ( + PyExc_OverflowError, "%S not in range %ld to %S", + number, (long)0, max); + Py_DECREF (number); + Py_DECREF (max); + return FALSE; +} + +PyObject * +pygi_guint64_to_py (guint64 value) +{ + if (value <= LONG_MAX) + return PyLong_FromLong((long) value); + else + return PyLong_FromUnsignedLongLong (value); +} + +gboolean +pygi_marshal_from_py_basic_type (PyObject *object, /* in */ + GIArgument *arg, /* out */ + GITypeTag type_tag, + GITransfer transfer, + gpointer *cleanup_data /* out */) +{ + switch (type_tag) { + case GI_TYPE_TAG_VOID: + g_warn_if_fail (transfer == GI_TRANSFER_NOTHING); + if (pygi_gpointer_from_py (object, &(arg->v_pointer))) { + *cleanup_data = arg->v_pointer; + return TRUE; + } + return FALSE; + + case GI_TYPE_TAG_INT8: + return pygi_gint8_from_py (object, &(arg->v_int8)); + + case GI_TYPE_TAG_UINT8: + return pygi_guint8_from_py (object, &(arg->v_uint8)); + + case GI_TYPE_TAG_INT16: + return pygi_gint16_from_py (object, &(arg->v_int16)); + + case GI_TYPE_TAG_UINT16: + return pygi_guint16_from_py (object, &(arg->v_uint16)); + + case GI_TYPE_TAG_INT32: + return pygi_gint32_from_py (object, &(arg->v_int32)); + + case GI_TYPE_TAG_UINT32: + return pygi_guint32_from_py (object, &(arg->v_uint32)); + + case GI_TYPE_TAG_INT64: + return pygi_gint64_from_py (object, &(arg->v_int64)); + + case GI_TYPE_TAG_UINT64: + return pygi_guint64_from_py (object, &(arg->v_uint64)); + + case GI_TYPE_TAG_BOOLEAN: + return pygi_gboolean_from_py (object, &(arg->v_boolean)); + + case GI_TYPE_TAG_FLOAT: + return pygi_gfloat_from_py (object, &(arg->v_float)); + + case GI_TYPE_TAG_DOUBLE: + return pygi_gdouble_from_py (object, &(arg->v_double)); + + case GI_TYPE_TAG_GTYPE: + return pygi_gtype_from_py (object, &(arg->v_size)); + + case GI_TYPE_TAG_UNICHAR: + return pygi_gunichar_from_py (object, &(arg->v_uint32)); + + case GI_TYPE_TAG_UTF8: + if (pygi_utf8_from_py (object, &(arg->v_string))) { + *cleanup_data = arg->v_string; + return TRUE; + } + return FALSE; + + case GI_TYPE_TAG_FILENAME: + if (pygi_filename_from_py (object, &(arg->v_string))) { + *cleanup_data = arg->v_string; + return TRUE; + } + return FALSE; + + default: + PyErr_Format (PyExc_TypeError, "Type tag %d not supported", + type_tag); + return FALSE; + } + + return TRUE; +} + +gboolean +pygi_marshal_from_py_basic_type_cache_adapter (PyGIInvokeState *state, + PyGICallableCache *callable_cache, + PyGIArgCache *arg_cache, + PyObject *py_arg, + GIArgument *arg, + gpointer *cleanup_data) +{ + return pygi_marshal_from_py_basic_type (py_arg, + arg, + arg_cache->type_tag, + arg_cache->transfer, + cleanup_data); +} + +static void +marshal_cleanup_from_py_utf8 (PyGIInvokeState *state, + PyGIArgCache *arg_cache, + PyObject *py_arg, + gpointer data, + gboolean was_processed) +{ + /* We strdup strings so free unless ownership is transferred to C. */ + if (was_processed && arg_cache->transfer == GI_TRANSFER_NOTHING) + g_free (data); +} + +static PyObject * +marshal_to_py_void (PyGIInvokeState *state, + PyGICallableCache *callable_cache, + PyGIArgCache *arg_cache, + GIArgument *arg, + gpointer *cleanup_data) +{ + if (arg_cache->is_pointer) { + return PyLong_FromVoidPtr (arg->v_pointer); + } + Py_RETURN_NONE; +} + +PyObject * +pygi_utf8_to_py (gchar *value) +{ + if (value == NULL) { + Py_RETURN_NONE; + } + + return PyUnicode_FromString (value); +} + +PyObject * +pygi_filename_to_py (gchar *value) +{ + PyObject *py_obj; + + if (value == NULL) { + Py_RETURN_NONE; + } + +#ifdef G_OS_WIN32 + py_obj = PyUnicode_DecodeUTF8 (value, strlen(value), + "surrogatepass"); +#else + py_obj = PyUnicode_DecodeFSDefault (value); +#endif + + return py_obj; +} + +/** + * pygi_marshal_to_py_basic_type: + * @arg: The argument to convert to an object. + * @type_tag: Type tag for @arg + * @transfer: Transfer annotation + * + * Convert the given argument to a Python object. This function + * is restricted to simple types that only require the GITypeTag + * and GITransfer. For a more complete conversion routine, use: + * _pygi_argument_to_object. + * + * Returns: A PyObject representing @arg or NULL if it cannot convert + * the argument. + */ +PyObject * +pygi_marshal_to_py_basic_type (GIArgument *arg, + GITypeTag type_tag, + GITransfer transfer) +{ + switch (type_tag) { + case GI_TYPE_TAG_BOOLEAN: + return pygi_gboolean_to_py (arg->v_boolean); + + case GI_TYPE_TAG_INT8: + return pygi_gint8_to_py (arg->v_int8); + + case GI_TYPE_TAG_UINT8: + return pygi_guint8_to_py (arg->v_uint8); + + case GI_TYPE_TAG_INT16: + return pygi_gint16_to_py (arg->v_int16); + + case GI_TYPE_TAG_UINT16: + return pygi_guint16_to_py (arg->v_uint16); + + case GI_TYPE_TAG_INT32: + return pygi_gint32_to_py (arg->v_int32); + + case GI_TYPE_TAG_UINT32: + return pygi_guint32_to_py (arg->v_uint32); + + case GI_TYPE_TAG_INT64: + return pygi_gint64_to_py (arg->v_int64); + + case GI_TYPE_TAG_UINT64: + return pygi_guint64_to_py (arg->v_uint64); + + case GI_TYPE_TAG_FLOAT: + return pygi_gfloat_to_py (arg->v_float); + + case GI_TYPE_TAG_DOUBLE: + return pygi_gdouble_to_py (arg->v_double); + + case GI_TYPE_TAG_GTYPE: + return pyg_type_wrapper_new ( (GType) arg->v_size); + + case GI_TYPE_TAG_UNICHAR: + return pygi_gunichar_to_py (arg->v_uint32); + + case GI_TYPE_TAG_UTF8: + return pygi_utf8_to_py (arg->v_string); + + case GI_TYPE_TAG_FILENAME: + return pygi_filename_to_py (arg->v_string); + + default: + PyErr_Format (PyExc_TypeError, "Type tag %d not supported", + type_tag); + return NULL; + } +} + +PyObject * +pygi_marshal_to_py_basic_type_cache_adapter (PyGIInvokeState *state, + PyGICallableCache *callable_cache, + PyGIArgCache *arg_cache, + GIArgument *arg, + gpointer *cleanup_data) +{ + return pygi_marshal_to_py_basic_type (arg, + arg_cache->type_tag, + arg_cache->transfer); +} + +static void +marshal_cleanup_to_py_utf8 (PyGIInvokeState *state, + PyGIArgCache *arg_cache, + gpointer cleanup_data, + gpointer data, + gboolean was_processed) +{ + /* Python copies the string so we need to free it + if the interface is transfering ownership, + whether or not it has been processed yet */ + if (arg_cache->transfer == GI_TRANSFER_EVERYTHING) + g_free (data); +} + +static gboolean +arg_basic_type_setup_from_info (PyGIArgCache *arg_cache, + GITypeInfo *type_info, + GIArgInfo *arg_info, + GITransfer transfer, + PyGIDirection direction) +{ + GITypeTag type_tag = g_type_info_get_tag (type_info); + + if (!pygi_arg_base_setup (arg_cache, type_info, arg_info, transfer, direction)) + return FALSE; + + switch (type_tag) { + case GI_TYPE_TAG_VOID: + if (direction & PYGI_DIRECTION_FROM_PYTHON) + arg_cache->from_py_marshaller = marshal_from_py_void; + + if (direction & PYGI_DIRECTION_TO_PYTHON) + arg_cache->to_py_marshaller = marshal_to_py_void; + + break; + case GI_TYPE_TAG_BOOLEAN: + arg_cache->allow_none = TRUE; + /* fall through */ + case GI_TYPE_TAG_INT8: + case GI_TYPE_TAG_UINT8: + case GI_TYPE_TAG_INT16: + case GI_TYPE_TAG_UINT16: + case GI_TYPE_TAG_INT32: + case GI_TYPE_TAG_UINT32: + case GI_TYPE_TAG_INT64: + case GI_TYPE_TAG_UINT64: + case GI_TYPE_TAG_FLOAT: + case GI_TYPE_TAG_DOUBLE: + case GI_TYPE_TAG_UNICHAR: + case GI_TYPE_TAG_GTYPE: + if (direction & PYGI_DIRECTION_FROM_PYTHON) + arg_cache->from_py_marshaller = pygi_marshal_from_py_basic_type_cache_adapter; + + if (direction & PYGI_DIRECTION_TO_PYTHON) + arg_cache->to_py_marshaller = pygi_marshal_to_py_basic_type_cache_adapter; + + break; + case GI_TYPE_TAG_UTF8: + case GI_TYPE_TAG_FILENAME: + if (direction & PYGI_DIRECTION_FROM_PYTHON) { + arg_cache->from_py_marshaller = pygi_marshal_from_py_basic_type_cache_adapter; + arg_cache->from_py_cleanup = marshal_cleanup_from_py_utf8; + } + + if (direction & PYGI_DIRECTION_TO_PYTHON) { + arg_cache->to_py_marshaller = pygi_marshal_to_py_basic_type_cache_adapter; + arg_cache->to_py_cleanup = marshal_cleanup_to_py_utf8; + } + + break; + default: + g_assert_not_reached (); + } + + return TRUE; +} + +PyGIArgCache * +pygi_arg_basic_type_new_from_info (GITypeInfo *type_info, + GIArgInfo *arg_info, + GITransfer transfer, + PyGIDirection direction) +{ + gboolean res = FALSE; + PyGIArgCache *arg_cache = pygi_arg_cache_alloc (); + + res = arg_basic_type_setup_from_info (arg_cache, + type_info, + arg_info, + transfer, + direction); + if (res) { + return arg_cache; + } else { + pygi_arg_cache_free (arg_cache); + return NULL; + } +} diff --git a/gi/pygi-basictype.h b/gi/pygi-basictype.h new file mode 100644 index 0000000..04d520a --- /dev/null +++ b/gi/pygi-basictype.h @@ -0,0 +1,89 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- + * vim: tabstop=4 shiftwidth=4 expandtab + * + * Copyright (C) 2014 Simon Feltman <sfeltman@gnome.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __PYGI_ARG_BASICTYPE_H__ +#define __PYGI_ARG_BASICTYPE_H__ + +#include <girepository.h> +#include "pygi-cache.h" + +G_BEGIN_DECLS + +gboolean pygi_marshal_from_py_basic_type (PyObject *object, /* in */ + GIArgument *arg, /* out */ + GITypeTag type_tag, + GITransfer transfer, + gpointer *cleanup_data); +gboolean pygi_marshal_from_py_basic_type_cache_adapter (PyGIInvokeState *state, + PyGICallableCache *callable_cache, + PyGIArgCache *arg_cache, + PyObject *py_arg, + GIArgument *arg, + gpointer *cleanup_data); + +PyObject *pygi_marshal_to_py_basic_type (GIArgument *arg, /* in */ + GITypeTag type_tag, + GITransfer transfer); +PyObject *pygi_marshal_to_py_basic_type_cache_adapter (PyGIInvokeState *state, + PyGICallableCache *callable_cache, + PyGIArgCache *arg_cache, + GIArgument *arg, + gpointer *cleanup_data); + +PyGIArgCache *pygi_arg_basic_type_new_from_info (GITypeInfo *type_info, + GIArgInfo *arg_info, /* may be null */ + GITransfer transfer, + PyGIDirection direction); + +PyObject *pygi_gint64_to_py (gint64 value); +PyObject *pygi_guint64_to_py (guint64 value); +PyObject *pygi_gfloat_to_py (gfloat value); +PyObject *pygi_gdouble_to_py (gdouble value); +PyObject *pygi_gboolean_to_py (gboolean value); +PyObject *pygi_gint8_to_py (gint8 value); +PyObject *pygi_guint8_to_py (guint8 value); +PyObject *pygi_utf8_to_py (gchar *value); +PyObject *pygi_gint_to_py (gint value); +PyObject *pygi_glong_to_py (glong value); +PyObject *pygi_guint_to_py (guint value); +PyObject *pygi_gulong_to_py (gulong value); +PyObject *pygi_filename_to_py (gchar *value); +PyObject *pygi_gsize_to_py (gsize value); +PyObject *pygi_gssize_to_py (gssize value); +PyObject *pygi_guint32_to_py (guint32 value); + +gboolean pygi_gboolean_from_py (PyObject *object, gboolean *result); +gboolean pygi_gint64_from_py (PyObject *object, gint64 *result); +gboolean pygi_guint64_from_py (PyObject *object, guint64 *result); +gboolean pygi_gfloat_from_py (PyObject *py_arg, gfloat *result); +gboolean pygi_gdouble_from_py (PyObject *py_arg, gdouble *result); +gboolean pygi_utf8_from_py (PyObject *py_arg, gchar **result); +gboolean pygi_glong_from_py (PyObject *object, glong *result); +gboolean pygi_gulong_from_py (PyObject *object, gulong *result); +gboolean pygi_gint_from_py (PyObject *object, gint *result); +gboolean pygi_guint_from_py (PyObject *object, guint *result); +gboolean pygi_gunichar_from_py (PyObject *py_arg, gunichar *result); +gboolean pygi_gint8_from_py (PyObject *object, gint8 *result); +gboolean pygi_gschar_from_py (PyObject *object, gint8 *result); +gboolean pygi_guint8_from_py (PyObject *object, guint8 *result); +gboolean pygi_guchar_from_py (PyObject *object, guchar *result); + +G_END_DECLS + +#endif /*__PYGI_ARG_BASICTYPE_H__*/ diff --git a/gi/pygi-boxed.c b/gi/pygi-boxed.c index 5bf2c19..9deb62a 100644 --- a/gi/pygi-boxed.c +++ b/gi/pygi-boxed.c @@ -16,38 +16,66 @@ * 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 + * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ -#include "pygi-private.h" +#include "pygi-boxed.h" +#include "pygi-info.h" +#include "pygboxed.h" +#include "pygi-type.h" +#include "pygi-basictype.h" +#include "pygi-util.h" -#include <pygobject.h> #include <girepository.h> -#include <pyglib-python-compat.h> + +struct _PyGIBoxed { + PyGBoxed base; + gboolean slice_allocated; + gsize size; +}; static void -_boxed_dealloc (PyGIBoxed *self) +boxed_clear (PyGIBoxed *self) { - GType g_type; + gpointer boxed = pyg_boxed_get_ptr (self); + GType g_type = ((PyGBoxed *)self)->gtype; - if ( ( (PyGBoxed *) self)->free_on_dealloc) { + if ( ( (PyGBoxed *) self)->free_on_dealloc && boxed != NULL) { if (self->slice_allocated) { - g_slice_free1 (self->size, ( (PyGBoxed *) self)->boxed); + if (g_type && g_type_is_a (g_type, G_TYPE_VALUE)) + g_value_unset (boxed); + g_slice_free1 (self->size, boxed); + self->slice_allocated = FALSE; + self->size = 0; } else { - g_type = pyg_type_from_object ( (PyObject *) self); - g_boxed_free (g_type, ( (PyGBoxed *) self)->boxed); + g_boxed_free (g_type, boxed); } } + pyg_boxed_set_ptr (self, NULL); +} - Py_TYPE( (PyGObject *) self)->tp_free ( (PyObject *) self); +static PyObject * +boxed_clear_wrapper (PyGIBoxed *self) +{ + boxed_clear (self); + + Py_RETURN_NONE; +} + + +static void +boxed_dealloc (PyGIBoxed *self) +{ + boxed_clear (self); + + Py_TYPE (self)->tp_free ((PyObject *)self); } void * -_pygi_boxed_alloc (GIBaseInfo *info, gsize *size_out) +pygi_boxed_alloc (GIBaseInfo *info, gsize *size_out) { - gsize size; + gpointer boxed = NULL; + gsize size = 0; switch (g_base_info_get_type (info)) { case GI_INFO_TYPE_UNION: @@ -64,28 +92,33 @@ _pygi_boxed_alloc (GIBaseInfo *info, gsize *size_out) return NULL; } + if (size == 0) { + PyErr_Format (PyExc_TypeError, + "boxed cannot be created directly; try using a constructor, see: help(%s.%s)", + g_base_info_get_namespace (info), + g_base_info_get_name (info)); + return NULL; + } + if( size_out != NULL) *size_out = size; - return g_slice_alloc0 (size); + boxed = g_slice_alloc0 (size); + if (boxed == NULL) + PyErr_NoMemory(); + return boxed; } static PyObject * -_boxed_new (PyTypeObject *type, +boxed_new (PyTypeObject *type, PyObject *args, PyObject *kwargs) { - static char *kwlist[] = { NULL }; - GIBaseInfo *info; gsize size = 0; gpointer boxed; PyGIBoxed *self = NULL; - if (!PyArg_ParseTupleAndKeywords (args, kwargs, "", kwlist)) { - return NULL; - } - info = _pygi_object_get_gi_info ( (PyObject *) type, &PyGIBaseInfo_Type); if (info == NULL) { if (PyErr_ExceptionMatches (PyExc_AttributeError)) { @@ -94,13 +127,12 @@ _boxed_new (PyTypeObject *type, return NULL; } - boxed = _pygi_boxed_alloc (info, &size); + boxed = pygi_boxed_alloc (info, &size); if (boxed == NULL) { - PyErr_NoMemory(); goto out; } - self = (PyGIBoxed *) _pygi_boxed_new (type, boxed, TRUE, size); + self = (PyGIBoxed *) pygi_boxed_new (type, boxed, TRUE, size); if (self == NULL) { g_slice_free1 (size, boxed); goto out; @@ -116,21 +148,30 @@ out: } static int -_boxed_init (PyObject *self, +boxed_init (PyObject *self, PyObject *args, PyObject *kwargs) { + static char *kwlist[] = { NULL }; + + if (!PyArg_ParseTupleAndKeywords (args, kwargs, "", kwlist)) { + PyErr_Clear (); + PyErr_Warn (PyExc_DeprecationWarning, + "Passing arguments to gi.types.Boxed.__init__() is deprecated. " + "All arguments passed will be ignored."); + } + /* Don't call PyGBoxed's init, which raises an exception. */ return 0; } -PYGLIB_DEFINE_TYPE("gi.Boxed", PyGIBoxed_Type, PyGIBoxed); +PYGI_DEFINE_TYPE("gi.Boxed", PyGIBoxed_Type, PyGIBoxed); PyObject * -_pygi_boxed_new (PyTypeObject *type, - gpointer boxed, - gboolean free_on_dealloc, - gsize allocated_slice) +pygi_boxed_new (PyTypeObject *type, + gpointer boxed, + gboolean free_on_dealloc, + gsize allocated_slice) { PyGIBoxed *self; @@ -149,8 +190,8 @@ _pygi_boxed_new (PyTypeObject *type, } ( (PyGBoxed *) self)->gtype = pyg_type_from_object ( (PyObject *) type); - ( (PyGBoxed *) self)->boxed = boxed; ( (PyGBoxed *) self)->free_on_dealloc = free_on_dealloc; + pyg_boxed_set_ptr (self, boxed); if (allocated_slice > 0) { self->size = allocated_slice; self->slice_allocated = TRUE; @@ -162,30 +203,57 @@ _pygi_boxed_new (PyTypeObject *type, return (PyObject *) self; } -static PyObject * -_pygi_boxed_get_free_on_dealloc(PyGIBoxed *self, void *closure) +/** + * pygi_boxed_copy_in_place: + * + * Replace the boxed pointer held by this wrapper with a boxed copy + * freeing the previously held pointer (when free_on_dealloc is TRUE). + * This can be used in cases where Python is passed a reference which + * it does not own and the wrapper is held by the Python program + * longer than the duration of a callback it was passed to. + */ +void +pygi_boxed_copy_in_place (PyGIBoxed *self) { - return PyBool_FromLong( ((PyGBoxed *)self)->free_on_dealloc ); + PyGBoxed *pygboxed = (PyGBoxed *)self; + gpointer ptr = pyg_boxed_get_ptr (self); + gpointer copy = NULL; + + if (ptr) + copy = g_boxed_copy (pygboxed->gtype, ptr); + + boxed_clear (self); + pyg_boxed_set_ptr (pygboxed, copy); + pygboxed->free_on_dealloc = TRUE; } -static PyGetSetDef pygi_boxed_getsets[] = { - { "_free_on_dealloc", (getter)_pygi_boxed_get_free_on_dealloc, (setter)0 }, - { NULL, 0, 0 } +static PyMethodDef boxed_methods[] = { + { "_clear_boxed", (PyCFunction)boxed_clear_wrapper, METH_NOARGS }, + { NULL, NULL, 0 } }; -void -_pygi_boxed_register_types (PyObject *m) +/** + * Returns 0 on success, or -1 and sets an exception. + */ +int +pygi_boxed_register_types (PyObject *m) { - Py_TYPE(&PyGIBoxed_Type) = &PyType_Type; + Py_SET_TYPE(&PyGIBoxed_Type, &PyType_Type); + g_assert (Py_TYPE (&PyGBoxed_Type) != NULL); PyGIBoxed_Type.tp_base = &PyGBoxed_Type; - PyGIBoxed_Type.tp_new = (newfunc) _boxed_new; - PyGIBoxed_Type.tp_init = (initproc) _boxed_init; - PyGIBoxed_Type.tp_dealloc = (destructor) _boxed_dealloc; + PyGIBoxed_Type.tp_new = (newfunc) boxed_new; + PyGIBoxed_Type.tp_init = (initproc) boxed_init; + PyGIBoxed_Type.tp_dealloc = (destructor) boxed_dealloc; PyGIBoxed_Type.tp_flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE); - PyGIBoxed_Type.tp_getset = pygi_boxed_getsets; + PyGIBoxed_Type.tp_methods = boxed_methods; - if (PyType_Ready (&PyGIBoxed_Type)) - return; - if (PyModule_AddObject (m, "Boxed", (PyObject *) &PyGIBoxed_Type)) - return; + if (PyType_Ready (&PyGIBoxed_Type) < 0) + return -1; + Py_INCREF ((PyObject *) &PyGIBoxed_Type); + if (PyModule_AddObject (m, "Boxed", (PyObject *) &PyGIBoxed_Type) < 0) { + Py_DECREF ((PyObject *) &PyGIBoxed_Type); + return -1; + } + + return 0; } diff --git a/gi/pygi-boxed.h b/gi/pygi-boxed.h index 38ac928..18c4448 100644 --- a/gi/pygi-boxed.h +++ b/gi/pygi-boxed.h @@ -14,29 +14,32 @@ * 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 + * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ #ifndef __PYGI_BOXED_H__ #define __PYGI_BOXED_H__ #include <Python.h> +#include <girepository.h> +#include "pygobject-internal.h" G_BEGIN_DECLS +typedef struct _PyGIBoxed PyGIBoxed; + extern PyTypeObject PyGIBoxed_Type; -PyObject * _pygi_boxed_new (PyTypeObject *type, - gpointer boxed, - gboolean free_on_dealloc, - gsize allocated_slice); +PyObject * pygi_boxed_new (PyTypeObject *type, + gpointer boxed, + gboolean free_on_dealloc, + gsize allocated_slice); + +void * pygi_boxed_alloc (GIBaseInfo *info, gsize *size); -void * _pygi_boxed_alloc (GIBaseInfo *info, - gsize *size); +void pygi_boxed_copy_in_place (PyGIBoxed *self); -void _pygi_boxed_register_types (PyObject *m); +int pygi_boxed_register_types (PyObject *m); G_END_DECLS diff --git a/gi/pygi-cache.c b/gi/pygi-cache.c index 2f807f8..c6630de 100644 --- a/gi/pygi-cache.c +++ b/gi/pygi-cache.c @@ -2,6 +2,7 @@ * vim: tabstop=4 shiftwidth=4 expandtab * * Copyright (C) 2011 John (J5) Palmieri <johnp@redhat.com> + * Copyright (C) 2013 Simon Feltman <sfeltman@gnome.org> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -14,37 +15,99 @@ * 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 + * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ +#include <Python.h> +#include <girepository.h> + +#include "pygi-type.h" #include "pygi-info.h" #include "pygi-cache.h" -#include "pygi-marshal-to-py.h" -#include "pygi-marshal-from-py.h" #include "pygi-marshal-cleanup.h" #include "pygi-type.h" -#include <girepository.h> +#include "pygi-hashtable.h" +#include "pygi-basictype.h" +#include "pygi-list.h" +#include "pygi-array.h" +#include "pygi-closure.h" +#include "pygi-error.h" +#include "pygi-object.h" +#include "pygi-struct-marshal.h" +#include "pygi-enum-marshal.h" +#include "pygi-resulttuple.h" +#include "pygi-invoke.h" + + +/* _arg_info_default_value + * info: + * arg: (out): GIArgument to fill in with default value. + * + * This is currently a place holder API which only supports "allow-none" pointer args. + * Once defaults are part of the GI API, we can replace this with: g_arg_info_default_value + * https://bugzilla.gnome.org/show_bug.cgi?id=558620 + * + * Returns: TRUE if the given argument supports a default value and was filled in. + */ +static gboolean +_arg_info_default_value (GIArgInfo *info, GIArgument *arg) +{ + if (g_arg_info_may_be_null (info)) { + arg->v_pointer = NULL; + return TRUE; + } + return FALSE; +} -PyGIArgCache * _arg_cache_new (GITypeInfo *type_info, - PyGICallableCache *callable_cache, - GIArgInfo *arg_info, - GITransfer transfer, - PyGIDirection direction, - gssize c_arg_index, - gssize py_arg_index); - -PyGIArgCache * _arg_cache_new_for_interface (GIInterfaceInfo *iface_info, - PyGICallableCache *callable_cache, - GIArgInfo *arg_info, - GITransfer transfer, - PyGIDirection direction, - gssize c_arg_index, - gssize py_arg_index); -/* cleanup */ -static void -_pygi_arg_cache_free (PyGIArgCache *cache) +/* pygi_arg_base_setup: + * arg_cache: argument cache to initialize + * type_info: source for type related attributes to cache + * arg_info: (allow-none): source for argument related attributes to cache + * transfer: transfer mode to store in the argument cache + * direction: marshaling direction to store in the cache + * + * Initializer for PyGIArgCache + * + * Returns: TRUE on success and FALSE on failure + */ +gboolean +pygi_arg_base_setup (PyGIArgCache *arg_cache, + GITypeInfo *type_info, + GIArgInfo *arg_info, /* may be NULL for return arguments */ + GITransfer transfer, + PyGIDirection direction) +{ + arg_cache->direction = direction; + arg_cache->transfer = transfer; + arg_cache->py_arg_index = -1; + arg_cache->c_arg_index = -1; + + if (type_info != NULL) { + arg_cache->is_pointer = g_type_info_is_pointer (type_info); + arg_cache->type_tag = g_type_info_get_tag (type_info); + g_base_info_ref ( (GIBaseInfo *) type_info); + arg_cache->type_info = type_info; + } + + if (arg_info != NULL) { + if (!arg_cache->has_default) { + /* It is possible has_default was set somewhere else */ + arg_cache->has_default = _arg_info_default_value (arg_info, + &arg_cache->default_value); + } + arg_cache->arg_name = g_base_info_get_name ((GIBaseInfo *) arg_info); + arg_cache->allow_none = g_arg_info_may_be_null (arg_info); + + if (arg_cache->type_tag == GI_TYPE_TAG_INTERFACE || arg_cache->type_tag == GI_TYPE_TAG_ARRAY) + arg_cache->is_caller_allocates = g_arg_info_is_caller_allocates (arg_info); + else + arg_cache->is_caller_allocates = FALSE; + } + return TRUE; +} + +void +pygi_arg_cache_free (PyGIArgCache *cache) { if (cache == NULL) return; @@ -57,6 +120,8 @@ _pygi_arg_cache_free (PyGIArgCache *cache) g_slice_free (PyGIArgCache, cache); } +/* PyGIInterfaceCache */ + static void _interface_cache_free_func (PyGIInterfaceCache *cache) { @@ -70,1136 +135,1050 @@ _interface_cache_free_func (PyGIInterfaceCache *cache) } } -static void -_hash_cache_free_func (PyGIHashCache *cache) +/* pygi_arg_interface_setup: + * arg_cache: argument cache to initialize + * type_info: source for type related attributes to cache + * arg_info: (allow-none): source for argument related attributes to cache + * transfer: transfer mode to store in the argument cache + * direction: marshaling direction to store in the cache + * iface_info: interface info to cache + * + * Initializer for PyGIInterfaceCache + * + * Returns: TRUE on success and FALSE on failure + */ +gboolean +pygi_arg_interface_setup (PyGIInterfaceCache *iface_cache, + GITypeInfo *type_info, + GIArgInfo *arg_info, /* may be NULL for return arguments */ + GITransfer transfer, + PyGIDirection direction, + GIInterfaceInfo *iface_info) { - if (cache != NULL) { - _pygi_arg_cache_free (cache->key_cache); - _pygi_arg_cache_free (cache->value_cache); - g_slice_free (PyGIHashCache, cache); + if (!pygi_arg_base_setup ((PyGIArgCache *)iface_cache, + type_info, + arg_info, + transfer, + direction)) { + return FALSE; } -} -static void -_sequence_cache_free_func (PyGISequenceCache *cache) -{ - if (cache != NULL) { - _pygi_arg_cache_free (cache->item_cache); - g_slice_free (PyGISequenceCache, cache); - } -} + ( (PyGIArgCache *)iface_cache)->destroy_notify = (GDestroyNotify)_interface_cache_free_func; -static void -_callback_cache_free_func (PyGICallbackCache *cache) -{ - if (cache != NULL) { - if (cache->interface_info != NULL) - g_base_info_unref ( (GIBaseInfo *)cache->interface_info); + g_base_info_ref ( (GIBaseInfo *)iface_info); + iface_cache->interface_info = iface_info; + iface_cache->arg_cache.type_tag = GI_TYPE_TAG_INTERFACE; + iface_cache->type_name = _pygi_g_base_info_get_fullname (iface_info); + iface_cache->g_type = g_registered_type_info_get_g_type ( (GIRegisteredTypeInfo *)iface_info); + iface_cache->py_type = pygi_type_import_by_gi_info ( (GIBaseInfo *) iface_info); - g_slice_free (PyGICallbackCache, cache); + if (iface_cache->py_type == NULL) { + return FALSE; } + + return TRUE; } -void -_pygi_callable_cache_free (PyGICallableCache *cache) +PyGIArgCache * +pygi_arg_interface_new_from_info (GITypeInfo *type_info, + GIArgInfo *arg_info, /* may be NULL for return arguments */ + GITransfer transfer, + PyGIDirection direction, + GIInterfaceInfo *iface_info) { - gssize i; - - if (cache == NULL) - return; - - g_slist_free (cache->to_py_args); - g_slist_free (cache->arg_name_list); - g_hash_table_destroy (cache->arg_name_hash); + PyGIInterfaceCache *ic; - for (i = 0; i < cache->n_args; i++) { - PyGIArgCache *tmp = cache->args_cache[i]; - _pygi_arg_cache_free (tmp); + ic = g_slice_new0 (PyGIInterfaceCache); + if (!pygi_arg_interface_setup (ic, + type_info, + arg_info, + transfer, + direction, + iface_info)) { + pygi_arg_cache_free ((PyGIArgCache *)ic); + return NULL; } - if (cache->return_cache != NULL) - _pygi_arg_cache_free (cache->return_cache); - g_slice_free1 (cache->n_args * sizeof (PyGIArgCache *), cache->args_cache); - g_slice_free (PyGICallableCache, cache); + return (PyGIArgCache *)ic; } -/* cache generation */ +/* PyGISequenceCache */ -static PyGIInterfaceCache * -_interface_cache_new (GIInterfaceInfo *iface_info) +static void +_sequence_cache_free_func (PyGISequenceCache *cache) { - PyGIInterfaceCache *ic; - - ic = g_slice_new0 (PyGIInterfaceCache); - ( (PyGIArgCache *)ic)->destroy_notify = (GDestroyNotify)_interface_cache_free_func; - ic->g_type = g_registered_type_info_get_g_type ( (GIRegisteredTypeInfo *)iface_info); - ic->py_type = _pygi_type_import_by_gi_info ( (GIBaseInfo *) iface_info); - - if (ic->py_type == NULL) - return NULL; - - ic->type_name = _pygi_g_base_info_get_fullname (iface_info); - return ic; + if (cache != NULL) { + pygi_arg_cache_free (cache->item_cache); + g_slice_free (PyGISequenceCache, cache); + } } -static PyGISequenceCache * -_sequence_cache_new (GITypeInfo *type_info, - GIDirection direction, - GITransfer transfer, - gssize child_offset) +/* pygi_arg_sequence_setup: + * sc: sequence cache to initialize + * type_info: source for type related attributes to cache + * arg_info: (allow-none): source for argument related attributes to cache + * transfer: transfer mode to store in the argument cache + * direction: marshaling direction to store in the cache + * iface_info: interface info to cache + * + * Initializer for PyGISequenceCache used for holding list and array argument + * caches. + * + * Returns: TRUE on success and FALSE on failure + */ +gboolean +pygi_arg_sequence_setup (PyGISequenceCache *sc, + GITypeInfo *type_info, + GIArgInfo *arg_info, /* may be NULL for return arguments */ + GITransfer transfer, + PyGIDirection direction, + PyGICallableCache *callable_cache) { - PyGISequenceCache *sc; GITypeInfo *item_type_info; GITransfer item_transfer; - sc = g_slice_new0 (PyGISequenceCache); - ( (PyGIArgCache *)sc)->destroy_notify = (GDestroyNotify)_sequence_cache_free_func; - - sc->is_zero_terminated = g_type_info_is_zero_terminated (type_info); - sc->fixed_size = g_type_info_get_array_fixed_size (type_info); - sc->len_arg_index = g_type_info_get_array_length (type_info); - if (sc->len_arg_index >= 0) - sc->len_arg_index += child_offset; + if (!pygi_arg_base_setup ((PyGIArgCache *)sc, + type_info, + arg_info, + transfer, + direction)) { + return FALSE; + } + sc->arg_cache.destroy_notify = (GDestroyNotify)_sequence_cache_free_func; item_type_info = g_type_info_get_param_type (type_info, 0); - item_transfer = transfer == GI_TRANSFER_CONTAINER ? GI_TRANSFER_NOTHING : transfer; - sc->item_cache = _arg_cache_new (item_type_info, - NULL, - NULL, - item_transfer, - direction, - 0, 0); + sc->item_cache = pygi_arg_cache_new (item_type_info, + NULL, + item_transfer, + direction, + callable_cache, + 0, 0); - if (sc->item_cache == NULL) { - _pygi_arg_cache_free ( (PyGIArgCache *)sc); - return NULL; - } - - sc->item_size = _pygi_g_type_info_size (item_type_info); g_base_info_unref ( (GIBaseInfo *)item_type_info); - return sc; -} -static PyGIHashCache * -_hash_cache_new (GITypeInfo *type_info, - GIDirection direction, - GITransfer transfer) -{ - PyGIHashCache *hc; - GITypeInfo *key_type_info; - GITypeInfo *value_type_info; - GITransfer item_transfer; - - hc = g_slice_new0 (PyGIHashCache); - ( (PyGIArgCache *)hc)->destroy_notify = (GDestroyNotify)_hash_cache_free_func; - key_type_info = g_type_info_get_param_type (type_info, 0); - value_type_info = g_type_info_get_param_type (type_info, 1); - - item_transfer = - transfer == GI_TRANSFER_CONTAINER ? GI_TRANSFER_NOTHING : transfer; - - hc->key_cache = _arg_cache_new (key_type_info, - NULL, - NULL, - item_transfer, - direction, - 0, 0); - - if (hc->key_cache == NULL) { - _pygi_arg_cache_free ( (PyGIArgCache *)hc); - return NULL; - } - - hc->value_cache = _arg_cache_new (value_type_info, - NULL, - NULL, - item_transfer, - direction, - 0, 0); - - if (hc->value_cache == NULL) { - _pygi_arg_cache_free ( (PyGIArgCache *)hc); - return NULL; + if (sc->item_cache == NULL) { + return FALSE; } - g_base_info_unref( (GIBaseInfo *)key_type_info); - g_base_info_unref( (GIBaseInfo *)value_type_info); - - return hc; + return TRUE; } -static PyGICallbackCache * -_callback_cache_new (GIArgInfo *arg_info, - GIInterfaceInfo *iface_info, - gssize child_offset) +PyGIArgCache * +pygi_arg_cache_alloc (void) { - PyGICallbackCache *cc; - - cc = g_slice_new0 (PyGICallbackCache); - ( (PyGIArgCache *)cc)->destroy_notify = (GDestroyNotify)_callback_cache_free_func; - - cc->user_data_index = g_arg_info_get_closure (arg_info); - if (cc->user_data_index != -1) - cc->user_data_index += child_offset; - cc->destroy_notify_index = g_arg_info_get_destroy (arg_info); - if (cc->destroy_notify_index != -1) - cc->destroy_notify_index += child_offset; - cc->scope = g_arg_info_get_scope (arg_info); - g_base_info_ref( (GIBaseInfo *)iface_info); - cc->interface_info = iface_info; - return cc; + return g_slice_new0 (PyGIArgCache); } static PyGIArgCache * -_arg_cache_alloc (void) +_arg_cache_new_for_interface (GIInterfaceInfo *iface_info, + GITypeInfo *type_info, + GIArgInfo *arg_info, + GITransfer transfer, + PyGIDirection direction, + PyGICallableCache *callable_cache) { - return g_slice_new0 (PyGIArgCache); -} + GIInfoType info_type; -static void -_arg_cache_from_py_basic_type_setup (PyGIArgCache *arg_cache) -{ - arg_cache->from_py_marshaller = _pygi_marshal_from_py_basic_type_cache_adapter; -} + info_type = g_base_info_get_type ( (GIBaseInfo *)iface_info); -static void -_arg_cache_to_py_basic_type_setup (PyGIArgCache *arg_cache) -{ - arg_cache->to_py_marshaller = _pygi_marshal_to_py_basic_type_cache_adapter; -} + switch (info_type) { + case GI_INFO_TYPE_CALLBACK: + return pygi_arg_callback_new_from_info (type_info, + arg_info, + transfer, + direction, + iface_info, + callable_cache); + case GI_INFO_TYPE_OBJECT: + case GI_INFO_TYPE_INTERFACE: + return pygi_arg_gobject_new_from_info (type_info, + arg_info, + transfer, + direction, + iface_info, + callable_cache); + case GI_INFO_TYPE_BOXED: + case GI_INFO_TYPE_STRUCT: + case GI_INFO_TYPE_UNION: + return pygi_arg_struct_new_from_info (type_info, + arg_info, + transfer, + direction, + iface_info); + case GI_INFO_TYPE_ENUM: + return pygi_arg_enum_new_from_info (type_info, + arg_info, + transfer, + direction, + iface_info); + case GI_INFO_TYPE_FLAGS: + return pygi_arg_flags_new_from_info (type_info, + arg_info, + transfer, + direction, + iface_info); + default: + g_assert_not_reached (); + } -static void -_arg_cache_from_py_void_setup (PyGIArgCache *arg_cache) -{ - arg_cache->from_py_marshaller = _pygi_marshal_from_py_void; + return NULL; } -static void -_arg_cache_to_py_void_setup (PyGIArgCache *arg_cache) +PyGIArgCache * +pygi_arg_cache_new (GITypeInfo *type_info, + GIArgInfo *arg_info, /* may be null */ + GITransfer transfer, + PyGIDirection direction, + PyGICallableCache *callable_cache, + gssize c_arg_index, + gssize py_arg_index) { - arg_cache->to_py_marshaller = _pygi_marshal_to_py_void; -} + PyGIArgCache *arg_cache = NULL; + GITypeTag type_tag; -static void -_arg_cache_from_py_utf8_setup (PyGIArgCache *arg_cache, - GITransfer transfer) -{ - arg_cache->from_py_marshaller = _pygi_marshal_from_py_basic_type_cache_adapter; - arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_utf8; -} + type_tag = g_type_info_get_tag (type_info); -static void -_arg_cache_to_py_utf8_setup (PyGIArgCache *arg_cache, - GITransfer transfer) -{ - arg_cache->to_py_marshaller = _pygi_marshal_to_py_basic_type_cache_adapter; - arg_cache->to_py_cleanup = _pygi_marshal_cleanup_to_py_utf8; -} + switch (type_tag) { + case GI_TYPE_TAG_VOID: + case GI_TYPE_TAG_BOOLEAN: + case GI_TYPE_TAG_INT8: + case GI_TYPE_TAG_UINT8: + case GI_TYPE_TAG_INT16: + case GI_TYPE_TAG_UINT16: + case GI_TYPE_TAG_INT32: + case GI_TYPE_TAG_UINT32: + case GI_TYPE_TAG_INT64: + case GI_TYPE_TAG_UINT64: + case GI_TYPE_TAG_FLOAT: + case GI_TYPE_TAG_DOUBLE: + case GI_TYPE_TAG_UNICHAR: + case GI_TYPE_TAG_GTYPE: + case GI_TYPE_TAG_UTF8: + case GI_TYPE_TAG_FILENAME: + arg_cache = pygi_arg_basic_type_new_from_info (type_info, + arg_info, + transfer, + direction); + break; -static gboolean -_arg_cache_from_py_array_setup (PyGIArgCache *arg_cache, - PyGICallableCache *callable_cache, - GITypeInfo *type_info, - GITransfer transfer, - PyGIDirection direction, - gssize arg_index) -{ - PyGISequenceCache *seq_cache = (PyGISequenceCache *)arg_cache; - seq_cache->array_type = g_type_info_get_array_type (type_info); + case GI_TYPE_TAG_ARRAY: + { + arg_cache = pygi_arg_garray_new_from_info (type_info, + arg_info, + transfer, + direction, + callable_cache); + if (arg_cache == NULL) + return NULL; + + pygi_arg_garray_len_arg_setup (arg_cache, + type_info, + callable_cache, + direction, + c_arg_index, + &py_arg_index); + } + break; - arg_cache->from_py_marshaller = _pygi_marshal_from_py_array; + case GI_TYPE_TAG_GLIST: + arg_cache = pygi_arg_glist_new_from_info (type_info, + arg_info, + transfer, + direction, + callable_cache); + break; - if (seq_cache->len_arg_index >= 0) { - PyGIArgCache *child_cache = - callable_cache->args_cache[seq_cache->len_arg_index]; + case GI_TYPE_TAG_GSLIST: + arg_cache = pygi_arg_gslist_new_from_info (type_info, + arg_info, + transfer, + direction, + callable_cache); + break; - if (child_cache == NULL) { - child_cache = _arg_cache_alloc (); - } else if (child_cache->meta_type == PYGI_META_ARG_TYPE_CHILD || - child_cache->meta_type == PYGI_META_ARG_TYPE_CHILD_NEEDS_UPDATE) { - arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_array; - return TRUE; - } + case GI_TYPE_TAG_GHASH: + arg_cache = pygi_arg_hash_table_new_from_info (type_info, + arg_info, + transfer, + direction, + callable_cache); + break; - if (seq_cache->len_arg_index < arg_index) - child_cache->meta_type = PYGI_META_ARG_TYPE_CHILD_NEEDS_UPDATE; - else - child_cache->meta_type = PYGI_META_ARG_TYPE_CHILD; + case GI_TYPE_TAG_INTERFACE: + { + GIInterfaceInfo *interface_info = g_type_info_get_interface (type_info); + arg_cache = _arg_cache_new_for_interface (interface_info, + type_info, + arg_info, + transfer, + direction, + callable_cache); - child_cache->direction = direction; - child_cache->to_py_marshaller = NULL; - child_cache->from_py_marshaller = NULL; + g_base_info_unref ( (GIBaseInfo *)interface_info); + } + break; - callable_cache->args_cache[seq_cache->len_arg_index] = child_cache; + case GI_TYPE_TAG_ERROR: + arg_cache = pygi_arg_gerror_new_from_info (type_info, + arg_info, + transfer, + direction); + break; + default: + break; } - arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_array; - - return TRUE; -} - -static gboolean -_arg_cache_to_py_array_setup (PyGIArgCache *arg_cache, - PyGICallableCache *callable_cache, - GITypeInfo *type_info, - GITransfer transfer, - PyGIDirection direction, - gssize arg_index) -{ - PyGISequenceCache *seq_cache = (PyGISequenceCache *)arg_cache; - arg_cache->to_py_marshaller = _pygi_marshal_to_py_array; - arg_cache->to_py_cleanup = _pygi_marshal_cleanup_to_py_array; - - seq_cache->array_type = g_type_info_get_array_type (type_info); - - if (seq_cache->len_arg_index >= 0) { - PyGIArgCache *child_cache = callable_cache->args_cache[seq_cache->len_arg_index]; - if (seq_cache->len_arg_index < arg_index) - callable_cache->n_to_py_child_args++; - - if (child_cache != NULL) { - callable_cache->to_py_args = - g_slist_remove (callable_cache->to_py_args, child_cache); - - if (child_cache->meta_type == PYGI_META_ARG_TYPE_CHILD || - child_cache->meta_type == PYGI_META_ARG_TYPE_CHILD_NEEDS_UPDATE) - return TRUE; - } else { - child_cache = _arg_cache_alloc (); - } - - child_cache->meta_type = PYGI_META_ARG_TYPE_CHILD; - child_cache->direction = direction; - child_cache->to_py_marshaller = NULL; - child_cache->from_py_marshaller = NULL; - - callable_cache->args_cache[seq_cache->len_arg_index] = child_cache; + if (arg_cache != NULL) { + arg_cache->py_arg_index = py_arg_index; + arg_cache->c_arg_index = c_arg_index; } - return TRUE; + return arg_cache; } -static void -_arg_cache_from_py_glist_setup (PyGIArgCache *arg_cache, - GITransfer transfer) -{ - arg_cache->from_py_marshaller = _pygi_marshal_from_py_glist; - arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_glist; -} +/* PyGICallableCache */ -static void -_arg_cache_to_py_glist_setup (PyGIArgCache *arg_cache, - GITransfer transfer) +static PyGIDirection +_pygi_get_direction (PyGICallableCache *callable_cache, GIDirection gi_direction) { - arg_cache->to_py_marshaller = _pygi_marshal_to_py_glist; - arg_cache->to_py_cleanup = _pygi_marshal_cleanup_to_py_glist; + /* For vfuncs and callbacks our marshalling directions are reversed */ + if (gi_direction == GI_DIRECTION_INOUT) { + return PYGI_DIRECTION_BIDIRECTIONAL; + } else if (gi_direction == GI_DIRECTION_IN) { + if (callable_cache->calling_context != PYGI_CALLING_CONTEXT_IS_FROM_PY) + return PYGI_DIRECTION_TO_PYTHON; + return PYGI_DIRECTION_FROM_PYTHON; + } else { + if (callable_cache->calling_context != PYGI_CALLING_CONTEXT_IS_FROM_PY) + return PYGI_DIRECTION_FROM_PYTHON; + return PYGI_DIRECTION_TO_PYTHON; + } } -static void -_arg_cache_from_py_gslist_setup (PyGIArgCache *arg_cache, - GITransfer transfer) +/* Generate the cache for the callable's arguments */ +static gboolean +_callable_cache_generate_args_cache_real (PyGICallableCache *callable_cache, + GICallableInfo *callable_info) { - arg_cache->from_py_marshaller = _pygi_marshal_from_py_gslist; - arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_glist; -} + gint i; + guint arg_index; + GITypeInfo *return_info; + GITransfer return_transfer; + PyGIArgCache *return_cache; + PyGIDirection return_direction; + gssize last_explicit_arg_index; + PyObject *tuple_names; + GSList *arg_cache_item; + PyTypeObject* resulttuple_type; -static void -_arg_cache_to_py_gslist_setup (PyGIArgCache *arg_cache, - GITransfer transfer) -{ - arg_cache->to_py_marshaller = _pygi_marshal_to_py_gslist; - arg_cache->to_py_cleanup = _pygi_marshal_cleanup_to_py_glist; -} + /* Return arguments are always considered out */ + return_direction = _pygi_get_direction (callable_cache, GI_DIRECTION_OUT); -static void -_arg_cache_from_py_ghash_setup (PyGIArgCache *arg_cache) -{ - arg_cache->from_py_marshaller = _pygi_marshal_from_py_ghash; - arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_ghash; -} + /* cache the return arg */ + return_info = + g_callable_info_get_return_type (callable_info); + return_transfer = + g_callable_info_get_caller_owns (callable_info); + return_cache = + pygi_arg_cache_new (return_info, + NULL, + return_transfer, + return_direction, + callable_cache, + -1, + -1); + if (return_cache == NULL) + return FALSE; -static void -_arg_cache_to_py_ghash_setup (PyGIArgCache *arg_cache) -{ - arg_cache->to_py_marshaller = _pygi_marshal_to_py_ghash; - arg_cache->to_py_cleanup = _pygi_marshal_cleanup_to_py_ghash; -} + return_cache->is_skipped = g_callable_info_skip_return (callable_info); + callable_cache->return_cache = return_cache; + g_base_info_unref (return_info); -static void -_arg_cache_from_py_gerror_setup (PyGIArgCache *arg_cache) -{ - arg_cache->from_py_marshaller = _pygi_marshal_from_py_gerror; - arg_cache->meta_type = PYGI_META_ARG_TYPE_CHILD; -} + callable_cache->user_data_index = -1; -static void -_arg_cache_to_py_gerror_setup (PyGIArgCache *arg_cache) -{ - arg_cache->to_py_marshaller = _pygi_marshal_to_py_gerror; - arg_cache->meta_type = PYGI_META_ARG_TYPE_CHILD; -} + for (i = 0, arg_index = (guint)callable_cache->args_offset; + arg_index < _pygi_callable_cache_args_len (callable_cache); + i++, arg_index++) { + PyGIArgCache *arg_cache = NULL; + GIArgInfo *arg_info; + PyGIDirection direction; -static void -_arg_cache_from_py_interface_union_setup (PyGIArgCache *arg_cache, - GITransfer transfer) -{ - arg_cache->from_py_marshaller = _pygi_marshal_from_py_interface_struct_cache_adapter; -} + arg_info = g_callable_info_get_arg (callable_info, i); -static void -_arg_cache_to_py_interface_union_setup (PyGIArgCache *arg_cache, - GITransfer transfer) -{ - arg_cache->to_py_marshaller = _pygi_marshal_to_py_interface_struct_cache_adapter; -} + /* This only happens when dealing with callbacks */ + if (g_arg_info_get_closure (arg_info) == i) { + callable_cache->user_data_index = i; -static void -_arg_cache_from_py_interface_struct_setup (PyGIArgCache *arg_cache, - GIInterfaceInfo *iface_info, - GITransfer transfer) -{ - PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache; - iface_cache->is_foreign = g_struct_info_is_foreign ( (GIStructInfo*)iface_info); - arg_cache->from_py_marshaller = _pygi_marshal_from_py_interface_struct_cache_adapter; - - if (iface_cache->g_type == G_TYPE_VALUE) - arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_interface_struct_gvalue; - else if (iface_cache->is_foreign) - arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_interface_struct_foreign; -} + arg_cache = pygi_arg_cache_alloc (); + _pygi_callable_cache_set_arg (callable_cache, arg_index, arg_cache); -static void -_arg_cache_to_py_interface_struct_setup (PyGIArgCache *arg_cache, - GIInterfaceInfo *iface_info, - GITransfer transfer) -{ - PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache; - iface_cache->is_foreign = g_struct_info_is_foreign ( (GIStructInfo*)iface_info); - arg_cache->to_py_marshaller = _pygi_marshal_to_py_interface_struct_cache_adapter; + direction = _pygi_get_direction (callable_cache, GI_DIRECTION_IN); + arg_cache->direction = direction; + arg_cache->meta_type = PYGI_META_ARG_TYPE_CLOSURE; + arg_cache->c_arg_index = i; + arg_cache->is_pointer = TRUE; - if (iface_cache->is_foreign) - arg_cache->to_py_cleanup = _pygi_marshal_cleanup_to_py_interface_struct_foreign; -} + } else { + GITypeInfo *type_info; + + direction = _pygi_get_direction (callable_cache, + g_arg_info_get_direction (arg_info)); + type_info = g_arg_info_get_type (arg_info); + + /* must be an child arg filled in by its owner + * and continue + * fill in it's c_arg_index, add to the in count + */ + 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++; + } -static void -_arg_cache_from_py_interface_object_setup (PyGIArgCache *arg_cache, - GITransfer transfer) -{ - arg_cache->from_py_marshaller = _pygi_marshal_from_py_interface_object; - arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_interface_object; -} + if (direction & PYGI_DIRECTION_TO_PYTHON) { + callable_cache->n_to_py_args++; + } -static void -_arg_cache_to_py_interface_object_setup (PyGIArgCache *arg_cache, - GITransfer transfer) -{ - arg_cache->to_py_marshaller = _pygi_marshal_to_py_interface_object_cache_adapter; - arg_cache->to_py_cleanup = _pygi_marshal_cleanup_to_py_interface_object; -} + arg_cache->type_tag = g_type_info_get_tag (type_info); -static void -_arg_cache_from_py_interface_callback_setup (PyGIArgCache *arg_cache, - PyGICallableCache *callable_cache) -{ - PyGICallbackCache *callback_cache = (PyGICallbackCache *)arg_cache; - if (callback_cache->user_data_index >= 0) { - PyGIArgCache *user_data_arg_cache = _arg_cache_alloc (); - user_data_arg_cache->meta_type = PYGI_META_ARG_TYPE_CHILD_WITH_PYARG; - user_data_arg_cache->direction = PYGI_DIRECTION_FROM_PYTHON; - callable_cache->args_cache[callback_cache->user_data_index] = user_data_arg_cache; - } + } else { + GITransfer transfer; + gssize py_arg_index = -1; - if (callback_cache->destroy_notify_index >= 0) { - PyGIArgCache *destroy_arg_cache = _arg_cache_alloc (); - destroy_arg_cache->meta_type = PYGI_META_ARG_TYPE_CHILD; - destroy_arg_cache->direction = PYGI_DIRECTION_FROM_PYTHON; - callable_cache->args_cache[callback_cache->destroy_notify_index] = destroy_arg_cache; - } - arg_cache->from_py_marshaller = _pygi_marshal_from_py_interface_callback; - arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_interface_callback; -} + transfer = g_arg_info_get_ownership_transfer (arg_info); -static void -_arg_cache_to_py_interface_callback_setup (void) -{ - PyErr_Format(PyExc_NotImplementedError, - "Callback returns are not supported"); -} + if (direction & PYGI_DIRECTION_FROM_PYTHON) { + py_arg_index = callable_cache->n_py_args; + callable_cache->n_py_args++; + } -static void -_arg_cache_from_py_interface_enum_setup (PyGIArgCache *arg_cache, - GITransfer transfer) -{ - arg_cache->from_py_marshaller = _pygi_marshal_from_py_interface_enum; -} + arg_cache = + pygi_arg_cache_new (type_info, + arg_info, + transfer, + direction, + callable_cache, + arg_index, + py_arg_index); + + if (arg_cache == NULL) { + g_base_info_unref( (GIBaseInfo *)type_info); + g_base_info_unref( (GIBaseInfo *)arg_info); + return FALSE; + } -static void -_arg_cache_to_py_interface_enum_setup (PyGIArgCache *arg_cache, - GITransfer transfer) -{ - arg_cache->to_py_marshaller = _pygi_marshal_to_py_interface_enum; -} -static void -_arg_cache_from_py_interface_flags_setup (PyGIArgCache *arg_cache, - GITransfer transfer) -{ - arg_cache->from_py_marshaller = _pygi_marshal_from_py_interface_flags; -} + if (direction & PYGI_DIRECTION_TO_PYTHON) { + callable_cache->n_to_py_args++; -static void -_arg_cache_to_py_interface_flags_setup (PyGIArgCache *arg_cache, - GITransfer transfer) -{ - arg_cache->to_py_marshaller = _pygi_marshal_to_py_interface_flags; -} + callable_cache->to_py_args = + g_slist_append (callable_cache->to_py_args, arg_cache); + } -PyGIArgCache * -_arg_cache_new_for_interface (GIInterfaceInfo *iface_info, - PyGICallableCache *callable_cache, - GIArgInfo *arg_info, - GITransfer transfer, - PyGIDirection direction, - gssize c_arg_index, - gssize py_arg_index) -{ - PyGIInterfaceCache *iface_cache = NULL; - PyGIArgCache *arg_cache = NULL; - gssize child_offset = 0; - GIInfoType info_type; + _pygi_callable_cache_set_arg (callable_cache, arg_index, arg_cache); + } - if (callable_cache != NULL) - child_offset = - (callable_cache->function_type == PYGI_FUNCTION_TYPE_METHOD || - callable_cache->function_type == PYGI_FUNCTION_TYPE_VFUNC) ? 1: 0; + g_base_info_unref (type_info); + } - info_type = g_base_info_get_type ( (GIBaseInfo *)iface_info); + /* Ensure arguments always have a name when available */ + arg_cache->arg_name = g_base_info_get_name ((GIBaseInfo *) arg_info); - /* Callbacks are special cased */ - if (info_type != GI_INFO_TYPE_CALLBACK) { - iface_cache = _interface_cache_new (iface_info); + g_base_info_unref ( (GIBaseInfo *)arg_info); - arg_cache = (PyGIArgCache *)iface_cache; - if (arg_cache == NULL) - return NULL; } - switch (info_type) { - case GI_INFO_TYPE_UNION: - if (direction == PYGI_DIRECTION_FROM_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) - _arg_cache_from_py_interface_union_setup (arg_cache, transfer); - - if (direction == PYGI_DIRECTION_TO_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) - _arg_cache_to_py_interface_union_setup (arg_cache, transfer); - - break; - case GI_INFO_TYPE_BOXED: - case GI_INFO_TYPE_STRUCT: - if (direction == PYGI_DIRECTION_FROM_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) - _arg_cache_from_py_interface_struct_setup (arg_cache, - iface_info, - transfer); - - if (direction == PYGI_DIRECTION_TO_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) - _arg_cache_to_py_interface_struct_setup (arg_cache, - iface_info, - transfer); - break; - case GI_INFO_TYPE_OBJECT: - case GI_INFO_TYPE_INTERFACE: - if (direction == PYGI_DIRECTION_FROM_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) - _arg_cache_from_py_interface_object_setup (arg_cache, transfer); - - if (direction == PYGI_DIRECTION_TO_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) - _arg_cache_to_py_interface_object_setup (arg_cache, transfer); - - break; - case GI_INFO_TYPE_CALLBACK: - { - PyGICallbackCache *callback_cache; + if (callable_cache->arg_name_hash == NULL) { + callable_cache->arg_name_hash = g_hash_table_new (g_str_hash, g_str_equal); + } else { + g_hash_table_remove_all (callable_cache->arg_name_hash); + } + callable_cache->n_py_required_args = 0; + callable_cache->user_data_varargs_index = -1; - if (direction == PYGI_DIRECTION_TO_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) { - _arg_cache_to_py_interface_callback_setup (); - return NULL; - } + last_explicit_arg_index = -1; - callback_cache = - _callback_cache_new (arg_info, - iface_info, - child_offset); + /* Reverse loop through all the arguments to setup arg_name_list/hash + * and find the number of required arguments */ + for (i=(_pygi_callable_cache_args_len (callable_cache))-1; i >= 0; i--) { + PyGIArgCache *arg_cache = _pygi_callable_cache_get_arg (callable_cache, i); - arg_cache = (PyGIArgCache *)callback_cache; - if (arg_cache == NULL) - return NULL; + if (arg_cache->meta_type != PYGI_META_ARG_TYPE_CHILD && + arg_cache->meta_type != PYGI_META_ARG_TYPE_CLOSURE && + arg_cache->direction & PYGI_DIRECTION_FROM_PYTHON) { - if (direction == PYGI_DIRECTION_FROM_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) - _arg_cache_from_py_interface_callback_setup (arg_cache, callable_cache); + /* Setup arg_name_list and arg_name_hash */ + gpointer arg_name = (gpointer)arg_cache->arg_name; + callable_cache->arg_name_list = g_slist_prepend (callable_cache->arg_name_list, + arg_name); + if (arg_name != NULL) { + g_hash_table_insert (callable_cache->arg_name_hash, + arg_name, + GINT_TO_POINTER(i)); + } - break; + /* The first tail argument without a default will force all the preceding + * argument defaults off. This limits support of default args to the + * tail of an args list. + */ + if (callable_cache->n_py_required_args > 0) { + arg_cache->has_default = FALSE; + callable_cache->n_py_required_args += 1; + } else if (!arg_cache->has_default) { + callable_cache->n_py_required_args += 1; } - case GI_INFO_TYPE_ENUM: - if (direction == PYGI_DIRECTION_FROM_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) - _arg_cache_from_py_interface_enum_setup (arg_cache, transfer); - if (direction == PYGI_DIRECTION_TO_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) - _arg_cache_to_py_interface_enum_setup (arg_cache, transfer); + if (last_explicit_arg_index == -1) { + last_explicit_arg_index = i; - break; - case GI_INFO_TYPE_FLAGS: - if (direction == PYGI_DIRECTION_FROM_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) - _arg_cache_from_py_interface_flags_setup (arg_cache, transfer); + /* If the last "from python" argument in the args list is a child + * with pyarg (currently only callback user_data). Set it to eat + * variable args in the callable cache. + */ + if (arg_cache->meta_type == PYGI_META_ARG_TYPE_CHILD_WITH_PYARG) + callable_cache->user_data_varargs_index = i; + } + } + } - if (direction == PYGI_DIRECTION_TO_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) - _arg_cache_to_py_interface_flags_setup (arg_cache, transfer); + if (!return_cache->is_skipped && return_cache->type_tag != GI_TYPE_TAG_VOID) { + callable_cache->has_return = TRUE; + } - break; - default: - g_assert_not_reached (); + tuple_names = PyList_New (0); + if (callable_cache->has_return) { + PyList_Append (tuple_names, Py_None); } - if (arg_cache != NULL) { - arg_cache->direction = direction; - arg_cache->transfer = transfer; - arg_cache->type_tag = GI_TYPE_TAG_INTERFACE; - arg_cache->py_arg_index = py_arg_index; - arg_cache->c_arg_index = c_arg_index; + arg_cache_item = callable_cache->to_py_args; + while (arg_cache_item) { + const gchar *arg_name = ((PyGIArgCache *)arg_cache_item->data)->arg_name; + PyObject *arg_string = PyUnicode_FromString (arg_name); + PyList_Append (tuple_names, arg_string); + Py_DECREF (arg_string); + arg_cache_item = arg_cache_item->next; + } - if (iface_cache != NULL) { - g_base_info_ref ( (GIBaseInfo *)iface_info); - iface_cache->interface_info = iface_info; + /* No need to create a tuple type if there aren't multiple values */ + if (PyList_Size (tuple_names) > 1) { + resulttuple_type = pygi_resulttuple_new_type (tuple_names); + if (resulttuple_type == NULL) { + Py_DECREF (tuple_names); + return FALSE; + } else { + callable_cache->resulttuple_type = resulttuple_type; } } + Py_DECREF (tuple_names); - return arg_cache; + return TRUE; } -PyGIArgCache * -_arg_cache_new (GITypeInfo *type_info, - PyGICallableCache *callable_cache, - GIArgInfo *arg_info, - GITransfer transfer, - PyGIDirection direction, - gssize c_arg_index, - gssize py_arg_index) +static void +_callable_cache_deinit_real (PyGICallableCache *cache) { - PyGIArgCache *arg_cache = NULL; - gssize child_offset = 0; - GITypeTag type_tag; + g_clear_pointer (&cache->to_py_args, g_slist_free); + g_clear_pointer (&cache->arg_name_list, g_slist_free); + g_clear_pointer (&cache->arg_name_hash, g_hash_table_unref); + g_clear_pointer (&cache->args_cache, g_ptr_array_unref); + Py_CLEAR (cache->resulttuple_type); - type_tag = g_type_info_get_tag (type_info); + g_clear_pointer (&cache->return_cache, pygi_arg_cache_free); +} - if (callable_cache != NULL) - child_offset = - (callable_cache->function_type == PYGI_FUNCTION_TYPE_METHOD || - callable_cache->function_type == PYGI_FUNCTION_TYPE_VFUNC) ? 1: 0; +static gboolean +_callable_cache_init (PyGICallableCache *cache, + GICallableInfo *callable_info) +{ + gint n_args; + GIBaseInfo *container; + + if (cache->deinit == NULL) + cache->deinit = _callable_cache_deinit_real; + + if (cache->generate_args_cache == NULL) + cache->generate_args_cache = _callable_cache_generate_args_cache_real; + + cache->name = g_base_info_get_name ((GIBaseInfo *) callable_info); + cache->namespace = g_base_info_get_namespace ((GIBaseInfo *) callable_info); + container = g_base_info_get_container ((GIBaseInfo *) callable_info); + cache->container_name = NULL; + /* https://bugzilla.gnome.org/show_bug.cgi?id=709456 */ + if (container != NULL && g_base_info_get_type (container) != GI_INFO_TYPE_TYPE) { + cache->container_name = g_base_info_get_name (container); + } + cache->throws = g_callable_info_can_throw_gerror ((GIBaseInfo *) callable_info); - switch (type_tag) { - case GI_TYPE_TAG_VOID: - arg_cache = _arg_cache_alloc (); - if (arg_cache == NULL) - break; + if (g_base_info_is_deprecated (callable_info)) { + const gchar *deprecated = g_base_info_get_attribute (callable_info, "deprecated"); + gchar *warning; + gchar *full_name = pygi_callable_cache_get_full_name (cache); + if (deprecated != NULL) + warning = g_strdup_printf ("%s is deprecated: %s", + full_name, + deprecated); + else + warning = g_strdup_printf ("%s is deprecated", + full_name); + g_free (full_name); + PyErr_WarnEx (PyExc_DeprecationWarning, warning, 0); + g_free (warning); + } - if (direction == PYGI_DIRECTION_FROM_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) - _arg_cache_from_py_void_setup (arg_cache); + n_args = (gint)cache->args_offset + g_callable_info_get_n_args (callable_info); - if (direction == PYGI_DIRECTION_TO_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) - _arg_cache_to_py_void_setup (arg_cache); + if (n_args >= 0) { + cache->args_cache = g_ptr_array_new_full (n_args, (GDestroyNotify) pygi_arg_cache_free); + g_ptr_array_set_size (cache->args_cache, n_args); + } - break; - case GI_TYPE_TAG_BOOLEAN: - case GI_TYPE_TAG_INT8: - case GI_TYPE_TAG_UINT8: - case GI_TYPE_TAG_INT16: - case GI_TYPE_TAG_UINT16: - case GI_TYPE_TAG_INT32: - case GI_TYPE_TAG_UINT32: - case GI_TYPE_TAG_INT64: - case GI_TYPE_TAG_UINT64: - case GI_TYPE_TAG_FLOAT: - case GI_TYPE_TAG_DOUBLE: - case GI_TYPE_TAG_UNICHAR: - case GI_TYPE_TAG_GTYPE: - arg_cache = _arg_cache_alloc (); - if (arg_cache == NULL) - break; + if (!cache->generate_args_cache (cache, callable_info)) { + _callable_cache_deinit_real (cache); + return FALSE; + } - if (direction == PYGI_DIRECTION_FROM_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) - _arg_cache_from_py_basic_type_setup (arg_cache); + return TRUE; +} - if (direction == PYGI_DIRECTION_TO_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) - _arg_cache_to_py_basic_type_setup (arg_cache); +gchar * +pygi_callable_cache_get_full_name (PyGICallableCache *cache) +{ + if (cache->container_name != NULL) { + return g_strjoin (".", + cache->namespace, + cache->container_name, + cache->name, + NULL); + } else { + return g_strjoin (".", + cache->namespace, + cache->name, + NULL); + } +} - break; - case GI_TYPE_TAG_UTF8: - case GI_TYPE_TAG_FILENAME: - arg_cache = _arg_cache_alloc (); - if (arg_cache == NULL) - break; +void +pygi_callable_cache_free (PyGICallableCache *cache) +{ + cache->deinit (cache); + g_free (cache); +} - if (direction == PYGI_DIRECTION_FROM_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) - _arg_cache_from_py_utf8_setup (arg_cache, transfer); +/* PyGIFunctionCache */ - if (direction == PYGI_DIRECTION_TO_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) - _arg_cache_to_py_utf8_setup (arg_cache, transfer); +static PyObject * +_function_cache_invoke_real (PyGIFunctionCache *function_cache, + PyGIInvokeState *state, + PyObject *py_args, + PyObject *py_kwargs) +{ + return pygi_invoke_c_callable (function_cache, state, + py_args, py_kwargs); +} - break; - case GI_TYPE_TAG_ARRAY: - { - PyGISequenceCache *seq_cache = - _sequence_cache_new (type_info, - direction, - transfer, - child_offset); +static void +_function_cache_deinit_real (PyGICallableCache *callable_cache) +{ + g_function_invoker_destroy (&((PyGIFunctionCache *) callable_cache)->invoker); - arg_cache = (PyGIArgCache *)seq_cache; - if (arg_cache == NULL) - break; + _callable_cache_deinit_real (callable_cache); +} - if (direction == PYGI_DIRECTION_FROM_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) - _arg_cache_from_py_array_setup (arg_cache, - callable_cache, - type_info, - transfer, - direction, - c_arg_index); +static gboolean +_function_cache_init (PyGIFunctionCache *function_cache, + GICallableInfo *callable_info) +{ + PyGICallableCache *callable_cache = (PyGICallableCache *) function_cache; + GIFunctionInvoker *invoker = &function_cache->invoker; + GError *error = NULL; - if (direction == PYGI_DIRECTION_TO_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) - _arg_cache_to_py_array_setup (arg_cache, - callable_cache, - type_info, - transfer, - direction, - c_arg_index); - - /* ugly edge case code: - * - * length can come before the array parameter which means we - * need to update indexes if this happens - */ - if (seq_cache->len_arg_index > -1 && - callable_cache->args_cache[seq_cache->len_arg_index]->meta_type == PYGI_META_ARG_TYPE_CHILD_NEEDS_UPDATE) { - gssize i; - PyGIArgCache *child_cache = - callable_cache->args_cache[seq_cache->len_arg_index]; - - child_cache->meta_type = PYGI_META_ARG_TYPE_CHILD; - py_arg_index -= 1; - callable_cache->n_py_args -= 1; - - for (i = seq_cache->len_arg_index + 1; - i < callable_cache->n_args; - i++) { - PyGIArgCache *update_cache = callable_cache->args_cache[i]; - if (update_cache == NULL) - break; - - update_cache->py_arg_index -= 1; - } - } - - break; - } - case GI_TYPE_TAG_GLIST: - { - PyGISequenceCache *seq_cache = - _sequence_cache_new (type_info, - direction, - transfer, - child_offset); + callable_cache->calling_context = PYGI_CALLING_CONTEXT_IS_FROM_PY; - arg_cache = (PyGIArgCache *)seq_cache; - if (arg_cache == NULL) - break; + if (callable_cache->deinit == NULL) + callable_cache->deinit = _function_cache_deinit_real; - if (direction == PYGI_DIRECTION_FROM_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) - _arg_cache_from_py_glist_setup (arg_cache, transfer); + if (function_cache->invoke == NULL) + function_cache->invoke = _function_cache_invoke_real; - if (direction == PYGI_DIRECTION_TO_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) - _arg_cache_to_py_glist_setup (arg_cache, transfer); + if (!_callable_cache_init (callable_cache, callable_info)) + return FALSE; + /* Set by PyGICCallbackCache and PyGIVFuncCache */ + if (invoker->native_address == NULL) { + if (g_function_info_prep_invoker ((GIFunctionInfo *) callable_info, + invoker, + &error)) { + return TRUE; + } + } else { + if (g_function_invoker_new_for_address (invoker->native_address, + (GIFunctionInfo *) callable_info, + invoker, + &error)) { + return TRUE; + } + } - break; - } - case GI_TYPE_TAG_GSLIST: - { - PyGISequenceCache *seq_cache = - _sequence_cache_new (type_info, - direction, - transfer, - child_offset); + if (!pygi_error_check (&error)) { + PyErr_Format (PyExc_RuntimeError, + "unknown error creating invoker for %s", + g_base_info_get_name ((GIBaseInfo *) callable_info)); + } - arg_cache = (PyGIArgCache *)seq_cache; - if (arg_cache == NULL) - break; + _callable_cache_deinit_real (callable_cache); + return FALSE; +} - if (direction == PYGI_DIRECTION_FROM_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) - _arg_cache_from_py_gslist_setup (arg_cache, transfer); +PyGIFunctionCache * +pygi_function_cache_new (GICallableInfo *info) +{ + PyGIFunctionCache *function_cache; - if (direction == PYGI_DIRECTION_TO_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) - _arg_cache_to_py_gslist_setup (arg_cache, transfer); + function_cache = g_new0 (PyGIFunctionCache, 1); - break; - } - case GI_TYPE_TAG_GHASH: - arg_cache = - (PyGIArgCache *)_hash_cache_new (type_info, - direction, - transfer); + if (!_function_cache_init (function_cache, info)) { + g_free (function_cache); + return NULL; + } - if (arg_cache == NULL) - break; + return function_cache; +} - if (direction == PYGI_DIRECTION_FROM_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) - _arg_cache_from_py_ghash_setup (arg_cache); +PyObject * +pygi_function_cache_invoke (PyGIFunctionCache *function_cache, + PyObject *py_args, + PyObject *py_kwargs) +{ + PyGIInvokeState state = { 0, }; - if (direction == PYGI_DIRECTION_TO_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) { - _arg_cache_to_py_ghash_setup (arg_cache); - } + return function_cache->invoke (function_cache, &state, + py_args, py_kwargs); +} - break; - case GI_TYPE_TAG_INTERFACE: - { - GIInterfaceInfo *interface_info = g_type_info_get_interface (type_info); - arg_cache = _arg_cache_new_for_interface (interface_info, - callable_cache, - arg_info, - transfer, - direction, - c_arg_index, - py_arg_index); +/* PyGICCallbackCache */ - g_base_info_unref ( (GIBaseInfo *)interface_info); - break; - } - case GI_TYPE_TAG_ERROR: - arg_cache = _arg_cache_alloc (); - if (arg_cache == NULL) - break; +PyGIFunctionCache * +pygi_ccallback_cache_new (GICallableInfo *info, + GCallback function_ptr) +{ + PyGICCallbackCache *ccallback_cache; + PyGIFunctionCache *function_cache; - if (direction == PYGI_DIRECTION_FROM_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) - _arg_cache_from_py_gerror_setup (arg_cache); + ccallback_cache = g_new0 (PyGICCallbackCache, 1); + function_cache = (PyGIFunctionCache *) ccallback_cache; - if (direction == PYGI_DIRECTION_TO_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) - _arg_cache_to_py_gerror_setup (arg_cache); + function_cache->invoker.native_address = function_ptr; - break; - } + if (!_function_cache_init (function_cache, info)) { + g_free (ccallback_cache); + return NULL; + } - if (arg_cache != NULL) { - arg_cache->direction = direction; - arg_cache->transfer = transfer; - arg_cache->type_tag = type_tag; - arg_cache->py_arg_index = py_arg_index; - arg_cache->c_arg_index = c_arg_index; - arg_cache->is_pointer = g_type_info_is_pointer (type_info); - g_base_info_ref ( (GIBaseInfo *) type_info); - arg_cache->type_info = type_info; - } + return function_cache; +} - return arg_cache; +PyObject * +pygi_ccallback_cache_invoke (PyGICCallbackCache *ccallback_cache, + PyObject *py_args, + PyObject *py_kwargs, + gpointer user_data) +{ + PyGIFunctionCache *function_cache = (PyGIFunctionCache *) ccallback_cache; + PyGIInvokeState state = { 0, }; + + state.user_data = user_data; + + return function_cache->invoke (function_cache, &state, + py_args, py_kwargs); } -static void -_arg_name_list_generate (PyGICallableCache *callable_cache) +/* PyGIConstructorCache */ + +static PyObject * +_constructor_cache_invoke_real (PyGIFunctionCache *function_cache, + PyGIInvokeState *state, + PyObject *py_args, + PyObject *py_kwargs) { - GSList * arg_name_list = NULL; - int i; + PyGICallableCache *cache = (PyGICallableCache *) function_cache; + PyObject *constructor_class; + PyObject *ret; + + constructor_class = PyTuple_GetItem (py_args, 0); + if (constructor_class == NULL) { + gchar *full_name = pygi_callable_cache_get_full_name (cache); + PyErr_Clear (); + PyErr_Format (PyExc_TypeError, + "Constructors require the class to be passed in as an argument, " + "No arguments passed to the %s constructor.", + full_name); + g_free (full_name); - if (callable_cache->arg_name_hash == NULL) { - callable_cache->arg_name_hash = g_hash_table_new (g_str_hash, g_str_equal); - } else { - g_hash_table_remove_all (callable_cache->arg_name_hash); + return FALSE; } - for (i=0; i < callable_cache->n_args; i++) { - PyGIArgCache *arg_cache = NULL; + py_args = PyTuple_GetSlice (py_args, 1, PyTuple_Size (py_args)); + ret = _function_cache_invoke_real (function_cache, state, + py_args, py_kwargs); + Py_DECREF (py_args); - arg_cache = callable_cache->args_cache[i]; + if (ret == NULL || cache->return_cache->is_skipped) + return ret; - if (arg_cache->meta_type != PYGI_META_ARG_TYPE_CHILD && - arg_cache->meta_type != PYGI_META_ARG_TYPE_CLOSURE && - (arg_cache->direction == PYGI_DIRECTION_FROM_PYTHON || - arg_cache->direction == PYGI_DIRECTION_BIDIRECTIONAL)) { - - gpointer arg_name = (gpointer)arg_cache->arg_name; + if (ret != Py_None) { + if (!PyTuple_Check (ret)) + return ret; - arg_name_list = g_slist_prepend (arg_name_list, arg_name); - if (arg_name != NULL) { - g_hash_table_insert (callable_cache->arg_name_hash, arg_name, arg_name); - } - } + if (PyTuple_GET_ITEM (ret, 0) != Py_None) + return ret; } - callable_cache->arg_name_list = g_slist_reverse (arg_name_list); + PyErr_SetString (PyExc_TypeError, "constructor returned NULL"); + + Py_DECREF (ret); + return NULL; } -/* Generate the cache for the callable's arguments */ -static gboolean -_args_cache_generate (GICallableInfo *callable_info, - PyGICallableCache *callable_cache) +PyGIFunctionCache * +pygi_constructor_cache_new (GICallableInfo *info) { - gssize arg_index = 0; - gssize i; - GITypeInfo *return_info; - GITransfer return_transfer; - PyGIArgCache *return_cache; - PyGIDirection return_direction; - - /* determine if we are marshalling the return to or from python */ - if (callable_cache->function_type == PYGI_FUNCTION_TYPE_CALLBACK) - return_direction = PYGI_DIRECTION_FROM_PYTHON; - else - return_direction = PYGI_DIRECTION_TO_PYTHON; + PyGIConstructorCache *constructor_cache; + PyGIFunctionCache *function_cache; - /* cache the return arg */ - return_info = - g_callable_info_get_return_type (callable_info); - return_transfer = - g_callable_info_get_caller_owns (callable_info); - return_cache = - _arg_cache_new (return_info, - callable_cache, - NULL, - return_transfer, - return_direction, - -1, - -1); - if (return_cache == NULL) - return FALSE; + constructor_cache = g_new0 (PyGIConstructorCache, 1); + function_cache = (PyGIFunctionCache *) constructor_cache; - return_cache->is_skipped = g_callable_info_skip_return (callable_info); - callable_cache->return_cache = return_cache; - g_base_info_unref (return_info); + function_cache->invoke = _constructor_cache_invoke_real; - /* first arg is the instance */ - if (callable_cache->function_type == PYGI_FUNCTION_TYPE_METHOD || - callable_cache->function_type == PYGI_FUNCTION_TYPE_VFUNC) { - GIInterfaceInfo *interface_info; - PyGIArgCache *instance_cache; - PyGIDirection instance_direction; + if (!_function_cache_init (function_cache, info)) { + g_free (constructor_cache); + return NULL; + } - instance_direction = PYGI_DIRECTION_FROM_PYTHON; + return function_cache; +} +/* PyGIFunctionWithInstanceCache */ - interface_info = g_base_info_get_container ( (GIBaseInfo *)callable_info); +static gboolean +_function_with_instance_cache_generate_args_cache_real (PyGICallableCache *callable_cache, + GICallableInfo *callable_info) +{ + GIInterfaceInfo *interface_info; + PyGIArgCache *instance_cache; + GITransfer transfer; - instance_cache = - _arg_cache_new_for_interface (interface_info, - callable_cache, - NULL, - GI_TRANSFER_NOTHING, - instance_direction, - arg_index, - 0); + interface_info = g_base_info_get_container ((GIBaseInfo *) callable_info); + transfer = g_callable_info_get_instance_ownership_transfer (callable_info); - /* FIXME: marshal interfaces from_py */ - instance_cache->from_py_marshaller = _pygi_marshal_from_py_interface_instance; - g_base_info_unref ( (GIBaseInfo *)interface_info); + instance_cache = + _arg_cache_new_for_interface (interface_info, + NULL, + NULL, + transfer, + PYGI_DIRECTION_FROM_PYTHON, + callable_cache); - if (instance_cache == NULL) - return FALSE; + if (instance_cache == NULL) + return FALSE; - callable_cache->args_cache[arg_index] = instance_cache; + /* Because we are not supplied a GITypeInfo for instance arguments, + * assume some defaults. */ + instance_cache->is_pointer = TRUE; + instance_cache->py_arg_index = 0; + instance_cache->c_arg_index = 0; - arg_index++; - callable_cache->n_from_py_args++; - callable_cache->n_py_args++; - } + _pygi_callable_cache_set_arg (callable_cache, 0, instance_cache); + callable_cache->n_py_args++; - for (i=0; arg_index < callable_cache->n_args; arg_index++, i++) { - PyGIArgCache *arg_cache = NULL; - GIArgInfo *arg_info; - GITypeInfo *type_info; - GIDirection gi_direction; - PyGIDirection direction; - GITransfer transfer; - GITypeTag type_tag; - gboolean is_caller_allocates = FALSE; - gssize py_arg_index = -1; + return _callable_cache_generate_args_cache_real (callable_cache, + callable_info); +} - arg_info = g_callable_info_get_arg (callable_info, i); +static gboolean +_function_with_instance_cache_init (PyGIFunctionWithInstanceCache *fwi_cache, + GICallableInfo *info) +{ + PyGICallableCache *callable_cache = (PyGICallableCache *) fwi_cache; - if (g_arg_info_get_closure (arg_info) == i) { + callable_cache->args_offset += 1; + callable_cache->generate_args_cache = _function_with_instance_cache_generate_args_cache_real; - arg_cache = _arg_cache_alloc (); - callable_cache->args_cache[arg_index] = arg_cache; + return _function_cache_init ((PyGIFunctionCache *) fwi_cache, info); +} - arg_cache->arg_name = g_base_info_get_name ((GIBaseInfo *) arg_info); - arg_cache->direction = PYGI_DIRECTION_FROM_PYTHON; - arg_cache->meta_type = PYGI_META_ARG_TYPE_CLOSURE; - arg_cache->c_arg_index = i; +/* PyGIMethodCache */ - callable_cache->n_from_py_args++; +PyGIFunctionCache * +pygi_method_cache_new (GICallableInfo *info) +{ + PyGIMethodCache *method_cache; + PyGIFunctionWithInstanceCache *fwi_cache; - g_base_info_unref ( (GIBaseInfo *)arg_info); + method_cache = g_new0 (PyGIMethodCache, 1); + fwi_cache = (PyGIFunctionWithInstanceCache *) method_cache; - continue; - } + if (!_function_with_instance_cache_init (fwi_cache, info)) { + g_free (method_cache); + return NULL; + } - /* For vfuncs and callbacks our marshalling directions - are reversed */ - gi_direction = g_arg_info_get_direction (arg_info); - if (gi_direction == GI_DIRECTION_INOUT) { - direction = PYGI_DIRECTION_BIDIRECTIONAL; - } else if (gi_direction == GI_DIRECTION_IN) { - direction = PYGI_DIRECTION_FROM_PYTHON; - if (callable_cache->function_type == PYGI_FUNCTION_TYPE_CALLBACK) - direction = PYGI_DIRECTION_TO_PYTHON; - } else { - direction = PYGI_DIRECTION_TO_PYTHON; - if (callable_cache->function_type == PYGI_FUNCTION_TYPE_CALLBACK) - direction = PYGI_DIRECTION_FROM_PYTHON; - } + return (PyGIFunctionCache *) method_cache; +} - transfer = g_arg_info_get_ownership_transfer (arg_info); - type_info = g_arg_info_get_type (arg_info); - type_tag = g_type_info_get_tag (type_info); - - if (type_tag == GI_TYPE_TAG_INTERFACE || type_tag == GI_TYPE_TAG_ARRAY) - is_caller_allocates = g_arg_info_is_caller_allocates (arg_info); - - /* must be an child arg filled in by its owner - * and continue - * fill in it's c_arg_index, add to the in count - */ - if (callable_cache->args_cache[arg_index] != NULL) { - arg_cache = callable_cache->args_cache[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++; - } +/* PyGIVFuncCache */ - if (direction == PYGI_DIRECTION_FROM_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) { - arg_cache->c_arg_index = callable_cache->n_from_py_args; - callable_cache->n_from_py_args++; - } +static PyObject * +_vfunc_cache_invoke_real (PyGIFunctionCache *function_cache, + PyGIInvokeState *state, + PyObject *py_args, + PyObject *py_kwargs) +{ + PyGIVFuncCache *vfunc_cache = (PyGIVFuncCache *) function_cache; + PyObject *py_gtype; + GType implementor_gtype; + GError *error = NULL; + PyObject *ret; + + py_gtype = PyTuple_GetItem (py_args, 0); + if (py_gtype == NULL) { + PyErr_SetString (PyExc_TypeError, + "need the GType of the implementor class"); + return FALSE; + } - if (direction == PYGI_DIRECTION_TO_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) { - callable_cache->n_to_py_args++; - callable_cache->n_to_py_child_args++; - } + implementor_gtype = pyg_type_from_object (py_gtype); + if (implementor_gtype == G_TYPE_INVALID) + return FALSE; - arg_cache->type_tag = g_type_info_get_tag (type_info); + /* 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 *) vfunc_cache->info, + implementor_gtype, + &error); + if (pygi_error_check (&error)) { + return FALSE; + } - g_base_info_unref (type_info); - g_base_info_unref ( (GIBaseInfo *)arg_info); - continue; - } + py_args = PyTuple_GetSlice (py_args, 1, PyTuple_Size (py_args)); + ret = _function_cache_invoke_real (function_cache, state, + py_args, py_kwargs); + Py_DECREF (py_args); - if (direction == PYGI_DIRECTION_FROM_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) { - py_arg_index = callable_cache->n_py_args; - callable_cache->n_from_py_args++; - callable_cache->n_py_args++; - } + return ret; +} - arg_cache = - _arg_cache_new (type_info, - callable_cache, - arg_info, - transfer, - direction, - arg_index, - py_arg_index); +static void +_vfunc_cache_deinit_real (PyGICallableCache *callable_cache) +{ + g_base_info_unref (((PyGIVFuncCache *) callable_cache)->info); - if (arg_cache == NULL) - goto arg_err; + _function_cache_deinit_real (callable_cache); +} - arg_cache->arg_name = g_base_info_get_name ((GIBaseInfo *) arg_info); - arg_cache->allow_none = g_arg_info_may_be_null(arg_info); - arg_cache->is_caller_allocates = is_caller_allocates; +PyGIFunctionCache * +pygi_vfunc_cache_new (GICallableInfo *info) +{ + PyGIVFuncCache *vfunc_cache; + PyGIFunctionCache *function_cache; + PyGIFunctionWithInstanceCache *fwi_cache; - if (direction == PYGI_DIRECTION_TO_PYTHON || direction == PYGI_DIRECTION_BIDIRECTIONAL) { - callable_cache->n_to_py_args++; + vfunc_cache = g_new0 (PyGIVFuncCache, 1); + function_cache = (PyGIFunctionCache *) vfunc_cache; + fwi_cache = (PyGIFunctionWithInstanceCache *) vfunc_cache; - if (arg_cache == NULL) - goto arg_err; + ((PyGICallableCache *) vfunc_cache)->deinit = _vfunc_cache_deinit_real; - callable_cache->to_py_args = - g_slist_append (callable_cache->to_py_args, arg_cache); - } + /* This must be non-NULL for _function_cache_init() to create the + * invoker, the real address will be set in _vfunc_cache_invoke_real(). + */ + function_cache->invoker.native_address = (gpointer) 0xdeadbeef; - callable_cache->args_cache[arg_index] = arg_cache; - g_base_info_unref( (GIBaseInfo *)type_info); - g_base_info_unref( (GIBaseInfo *)arg_info); + function_cache->invoke = _vfunc_cache_invoke_real; - continue; -arg_err: - g_base_info_unref( (GIBaseInfo *)type_info); - g_base_info_unref( (GIBaseInfo *)arg_info); - return FALSE; + if (!_function_with_instance_cache_init (fwi_cache, info)) { + g_free (vfunc_cache); + return NULL; } - _arg_name_list_generate (callable_cache); + /* Required by _vfunc_cache_invoke_real() */ + vfunc_cache->info = g_base_info_ref ((GIBaseInfo *) info); - return TRUE; + return function_cache; } -PyGICallableCache * -_pygi_callable_cache_new (GICallableInfo *callable_info, gboolean is_ccallback) -{ - PyGICallableCache *cache; - GIInfoType type = g_base_info_get_type ( (GIBaseInfo *)callable_info); +/* PyGIClosureCache */ - cache = g_slice_new0 (PyGICallableCache); +PyGIClosureCache * +pygi_closure_cache_new (GICallableInfo *info) +{ + gssize i; + PyGIClosureCache *closure_cache; + PyGICallableCache *callable_cache; - if (cache == NULL) - return NULL; + closure_cache = g_new0 (PyGIClosureCache, 1); + callable_cache = (PyGICallableCache *) closure_cache; - cache->name = g_base_info_get_name ((GIBaseInfo *)callable_info); + callable_cache->calling_context = PYGI_CALLING_CONTEXT_IS_FROM_C; - if (g_base_info_is_deprecated (callable_info)) { - const gchar *deprecated = g_base_info_get_attribute (callable_info, "deprecated"); - gchar *warning; - if (deprecated != NULL) - warning = g_strdup_printf ("%s.%s is deprecated: %s", - g_base_info_get_namespace (callable_info), cache->name, - deprecated); - else - warning = g_strdup_printf ("%s.%s is deprecated", - g_base_info_get_namespace (callable_info), cache->name); - PyErr_WarnEx(PyExc_DeprecationWarning, warning, 0); - g_free (warning); + if (!_callable_cache_init (callable_cache, info)) { + g_free (closure_cache); + return NULL; } - if (type == GI_INFO_TYPE_FUNCTION) { - GIFunctionInfoFlags flags; + /* For backwards compatibility closures include the array's length. + * + * See: https://bugzilla.gnome.org/show_bug.cgi?id=652115 + */ + for (i = 0; (gsize)i < _pygi_callable_cache_args_len (callable_cache); i++) { + PyGIArgCache *arg_cache; + PyGIArgGArray *garray_cache; + PyGIArgCache *len_arg_cache; + + arg_cache = g_ptr_array_index (callable_cache->args_cache, i); + if (arg_cache->type_tag != GI_TYPE_TAG_ARRAY) + continue; - flags = g_function_info_get_flags ( (GIFunctionInfo *)callable_info); + garray_cache = (PyGIArgGArray *) arg_cache; + if (garray_cache->len_arg_index == -1) + continue; - if (flags & GI_FUNCTION_IS_CONSTRUCTOR) - cache->function_type = PYGI_FUNCTION_TYPE_CONSTRUCTOR; - else if (flags & GI_FUNCTION_IS_METHOD) - cache->function_type = PYGI_FUNCTION_TYPE_METHOD; - } else if (type == GI_INFO_TYPE_VFUNC) { - cache->function_type = PYGI_FUNCTION_TYPE_VFUNC; - } else if (type == GI_INFO_TYPE_CALLBACK) { - if (is_ccallback) - cache->function_type = PYGI_FUNCTION_TYPE_CCALLBACK; - else - cache->function_type = PYGI_FUNCTION_TYPE_CALLBACK; - } else { - cache->function_type = PYGI_FUNCTION_TYPE_METHOD; + len_arg_cache = g_ptr_array_index (callable_cache->args_cache, + garray_cache->len_arg_index); + len_arg_cache->meta_type = PYGI_META_ARG_TYPE_PARENT; } - cache->n_args = g_callable_info_get_n_args (callable_info); + /* Prevent guessing multiple user data arguments. + * This is required because some versions of GI + * do not recognize user_data/data arguments correctly. + */ + if (callable_cache->user_data_index == -1) { + for (i = 0; (gsize)i < _pygi_callable_cache_args_len (callable_cache); i++) { + PyGIArgCache *arg_cache; - /* if we are a method or vfunc make sure the instance parameter is counted */ - if (cache->function_type == PYGI_FUNCTION_TYPE_METHOD || - cache->function_type == PYGI_FUNCTION_TYPE_VFUNC) - cache->n_args++; + arg_cache = g_ptr_array_index (callable_cache->args_cache, i); - if (cache->n_args > 0) - cache->args_cache = g_slice_alloc0 (cache->n_args * sizeof (PyGIArgCache *)); + if (arg_cache->direction == PYGI_DIRECTION_TO_PYTHON && + arg_cache->type_tag == GI_TYPE_TAG_VOID && + arg_cache->is_pointer) { - if (!_args_cache_generate (callable_info, cache)) - goto err; + callable_cache->user_data_index = i; + break; + } + } + } - return cache; -err: - _pygi_callable_cache_free (cache); - return NULL; + return closure_cache; } diff --git a/gi/pygi-cache.h b/gi/pygi-cache.h index 6e5e0ab..fc5a616 100644 --- a/gi/pygi-cache.h +++ b/gi/pygi-cache.h @@ -2,6 +2,7 @@ * vim: tabstop=4 shiftwidth=4 expandtab * * Copyright (C) 2011 John (J5) Palmieri <johnp@redhat.com> + * Copyright (C) 2013 Simon Feltman <sfeltman@gnome.org> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -14,9 +15,7 @@ * 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 + * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ #ifndef __PYGI_CACHE_H__ @@ -24,30 +23,48 @@ #include <Python.h> #include <girepository.h> +#include <girffi.h> #include "pygi-invoke-state-struct.h" G_BEGIN_DECLS -typedef struct _PyGICallableCache PyGICallableCache; typedef struct _PyGIArgCache PyGIArgCache; +typedef struct _PyGICallableCache PyGICallableCache; +typedef struct _PyGIFunctionCache PyGIFunctionCache; +typedef struct _PyGIVFuncCache PyGIVFuncCache; + +typedef PyGIFunctionCache PyGICCallbackCache; +typedef PyGIFunctionCache PyGIConstructorCache; +typedef PyGIFunctionCache PyGIFunctionWithInstanceCache; +typedef PyGIFunctionCache PyGIMethodCache; +typedef PyGICallableCache PyGIClosureCache; typedef gboolean (*PyGIMarshalFromPyFunc) (PyGIInvokeState *state, PyGICallableCache *callable_cache, PyGIArgCache *arg_cache, PyObject *py_arg, - GIArgument *arg); + GIArgument *arg, + gpointer *cleanup_data); typedef PyObject *(*PyGIMarshalToPyFunc) (PyGIInvokeState *state, PyGICallableCache *callable_cache, PyGIArgCache *arg_cache, - GIArgument *arg); + GIArgument *arg, + gpointer *cleanup_data); typedef void (*PyGIMarshalCleanupFunc) (PyGIInvokeState *state, PyGIArgCache *arg_cache, + PyObject *py_arg, gpointer data, gboolean was_processed); +typedef void (*PyGIMarshalToPyCleanupFunc) (PyGIInvokeState *state, + PyGIArgCache *arg_cache, + gpointer cleanup_data, + gpointer data, + gboolean was_processed); + /* Argument meta types denote how we process the argument: * - PYGI_META_ARG_TYPE_PARENT - parents may or may not have children * but are always processed via the normal marshaller for their @@ -56,10 +73,6 @@ typedef void (*PyGIMarshalCleanupFunc) (PyGIInvokeState *state, * - PYGI_META_ARG_TYPE_CHILD - Children without python argument are * ignored by the marshallers and handled directly by their parents * marshaller. - * - PYGI_META_ARG_TYPE_CHILD_NEEDS_UPDATE -Sometimes children arguments - * come before the parent. In these cases they need to be flagged - * so that the argument list counts must be updated for the cache to - * be valid * - Children with pyargs (PYGI_META_ARG_TYPE_CHILD_WITH_PYARG) are processed * the same as other child args but also have an index into the * python parameters passed to the invoker @@ -67,38 +80,29 @@ typedef void (*PyGIMarshalCleanupFunc) (PyGIInvokeState *state, typedef enum { PYGI_META_ARG_TYPE_PARENT, PYGI_META_ARG_TYPE_CHILD, - PYGI_META_ARG_TYPE_CHILD_NEEDS_UPDATE, PYGI_META_ARG_TYPE_CHILD_WITH_PYARG, PYGI_META_ARG_TYPE_CLOSURE, } PyGIMetaArgType; /* - * GI determines function types via a combination of flags and info classes. - * Since for branching purposes they are mutually exclusive, the - * PyGIFunctionType enum consolidates them into one enumeration for ease of - * branching and debugging. + * Argument direction types denotes how we marshal, + * e.g. to Python or from Python or both. */ typedef enum { - PYGI_FUNCTION_TYPE_FUNCTION, - PYGI_FUNCTION_TYPE_METHOD, - PYGI_FUNCTION_TYPE_CONSTRUCTOR, - PYGI_FUNCTION_TYPE_VFUNC, - PYGI_FUNCTION_TYPE_CALLBACK, - PYGI_FUNCTION_TYPE_CCALLBACK, - } PyGIFunctionType; + PYGI_DIRECTION_TO_PYTHON = 1 << 0, + PYGI_DIRECTION_FROM_PYTHON = 1 << 1, + PYGI_DIRECTION_BIDIRECTIONAL = PYGI_DIRECTION_TO_PYTHON | PYGI_DIRECTION_FROM_PYTHON + } PyGIDirection; /* * In PyGI IN and OUT arguments mean different things depending on the context - * of the callable (e.g. is it a callback that is being called from C or a - * function that is being called from python). We don't as much care if the - * parameter is an IN or OUT C parameter, than we do if the parameter is being - * marshalled into Python or from Python. + * of the callable, e.g. is it a callback that is being called from C or a + * function that is being called from Python. */ typedef enum { - PYGI_DIRECTION_TO_PYTHON, - PYGI_DIRECTION_FROM_PYTHON, - PYGI_DIRECTION_BIDIRECTIONAL - } PyGIDirection; + PYGI_CALLING_CONTEXT_IS_FROM_C, + PYGI_CALLING_CONTEXT_IS_FROM_PY +} PyGICallingContext; struct _PyGIArgCache @@ -110,6 +114,7 @@ struct _PyGIArgCache gboolean is_caller_allocates; gboolean is_skipped; gboolean allow_none; + gboolean has_default; PyGIDirection direction; GITransfer transfer; @@ -120,24 +125,32 @@ struct _PyGIArgCache PyGIMarshalToPyFunc to_py_marshaller; PyGIMarshalCleanupFunc from_py_cleanup; - PyGIMarshalCleanupFunc to_py_cleanup; + PyGIMarshalToPyCleanupFunc to_py_cleanup; GDestroyNotify destroy_notify; gssize c_arg_index; gssize py_arg_index; + + /* Set when has_default is true. */ + GIArgument default_value; }; typedef struct _PyGISequenceCache { PyGIArgCache arg_cache; + PyGIArgCache *item_cache; +} PyGISequenceCache; + +typedef struct _PyGIArgGArray +{ + PyGISequenceCache seq_cache; gssize fixed_size; gssize len_arg_index; gboolean is_zero_terminated; gsize item_size; GIArrayType array_type; - PyGIArgCache *item_cache; -} PyGISequenceCache; +} PyGIArgGArray; typedef struct _PyGIInterfaceCache { @@ -149,48 +162,174 @@ typedef struct _PyGIInterfaceCache gchar *type_name; } PyGIInterfaceCache; -typedef struct _PyGIHashCache -{ - PyGIArgCache arg_cache; - PyGIArgCache *key_cache; - PyGIArgCache *value_cache; -} PyGIHashCache; - -typedef struct _PyGICallbackCache -{ - PyGIArgCache arg_cache; - gssize user_data_index; - gssize destroy_notify_index; - GIScopeType scope; - GIInterfaceInfo *interface_info; -} PyGICallbackCache; - struct _PyGICallableCache { const gchar *name; + const gchar *container_name; + const gchar *namespace; - PyGIFunctionType function_type; + PyGICallingContext calling_context; PyGIArgCache *return_cache; - PyGIArgCache **args_cache; + GPtrArray *args_cache; GSList *to_py_args; GSList *arg_name_list; /* for keyword arg matching */ GHashTable *arg_name_hash; + gboolean throws; + + /* Index of user_data arg passed to a callable. */ + gssize user_data_index; + + /* Index of user_data arg that can eat variable args passed to a callable. */ + gssize user_data_varargs_index; - /* counts */ - gssize n_from_py_args; + /* Number of args already added */ + gssize args_offset; + + /* 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; + + /* If the callable return value gets used */ + gboolean has_return; + + /* The type used for returning multiple values or NULL */ + PyTypeObject* resulttuple_type; + + /* Number of out args for g_function_info_invoke that will be skipped + * when marshaling to Python due to them being implicitly available + * (list/array length). + */ gssize n_to_py_child_args; - gssize n_args; + /* Number of Python arguments expected for invoking the gi function. */ gssize n_py_args; + + /* Minimum number of args required to call the callable from Python. + * This count does not include args with defaults. */ + gssize n_py_required_args; + + void (*deinit) (PyGICallableCache *callable_cache); + + gboolean (*generate_args_cache) (PyGICallableCache *callable_cache, + GICallableInfo *callable_info); +}; + +struct _PyGIFunctionCache { + PyGICallableCache callable_cache; + + /* An invoker with ffi_cif already setup */ + GIFunctionInvoker invoker; + + PyObject *(*invoke) (PyGIFunctionCache *function_cache, + PyGIInvokeState *state, + PyObject *py_args, + PyObject *py_kwargs); +} ; + +struct _PyGIVFuncCache { + PyGIFunctionWithInstanceCache fwi_cache; + + GIBaseInfo *info; }; -void _pygi_arg_cache_clear (PyGIArgCache *cache); -void _pygi_callable_cache_free (PyGICallableCache *cache); -PyGICallableCache *_pygi_callable_cache_new (GICallableInfo *callable_info, - gboolean is_ccallback); +gboolean +pygi_arg_base_setup (PyGIArgCache *arg_cache, + GITypeInfo *type_info, + GIArgInfo *arg_info, /* may be NULL for return arguments */ + GITransfer transfer, + PyGIDirection direction); + +gboolean +pygi_arg_interface_setup (PyGIInterfaceCache *iface_cache, + GITypeInfo *type_info, + GIArgInfo *arg_info, /* may be NULL for return arguments */ + GITransfer transfer, + PyGIDirection direction, + GIInterfaceInfo *iface_info); + +gboolean +pygi_arg_sequence_setup (PyGISequenceCache *sc, + GITypeInfo *type_info, + GIArgInfo *arg_info, /* may be NULL for return arguments */ + GITransfer transfer, + PyGIDirection direction, + PyGICallableCache *callable_cache); + +PyGIArgCache * +pygi_arg_interface_new_from_info (GITypeInfo *type_info, + GIArgInfo *arg_info, /* may be NULL for return arguments */ + GITransfer transfer, + PyGIDirection direction, + GIInterfaceInfo *iface_info); + +PyGIArgCache * +pygi_arg_cache_alloc (void); + +PyGIArgCache * +pygi_arg_cache_new (GITypeInfo *type_info, + GIArgInfo *arg_info, + GITransfer transfer, + PyGIDirection direction, + PyGICallableCache *callable_cache, + /* will be removed */ + gssize c_arg_index, + gssize py_arg_index); + +void +pygi_arg_cache_free (PyGIArgCache *cache); + +void +pygi_callable_cache_free (PyGICallableCache *cache); + +gchar * +pygi_callable_cache_get_full_name (PyGICallableCache *cache); + +PyGIFunctionCache * +pygi_function_cache_new (GICallableInfo *info); + +PyObject * +pygi_function_cache_invoke (PyGIFunctionCache *function_cache, + PyObject *py_args, + PyObject *py_kwargs); + +PyGIFunctionCache * +pygi_ccallback_cache_new (GICallableInfo *info, + GCallback function_ptr); + +PyObject * +pygi_ccallback_cache_invoke (PyGIFunctionCache *function_cache, + PyObject *py_args, + PyObject *py_kwargs, + gpointer user_data); + +PyGIFunctionCache * +pygi_constructor_cache_new (GICallableInfo *info); + +PyGIFunctionCache * +pygi_method_cache_new (GICallableInfo *info); + +PyGIFunctionCache * +pygi_vfunc_cache_new (GICallableInfo *info); + +PyGIClosureCache * +pygi_closure_cache_new (GICallableInfo *info); + +inline static guint +_pygi_callable_cache_args_len (PyGICallableCache *cache) { + return ((cache)->args_cache)->len; +} + +inline static PyGIArgCache * +_pygi_callable_cache_get_arg (PyGICallableCache *cache, guint index) { + return (PyGIArgCache *) g_ptr_array_index (cache->args_cache, index); +} + +inline static void +_pygi_callable_cache_set_arg (PyGICallableCache *cache, guint index, PyGIArgCache *arg_cache) { + cache->args_cache->pdata[index] = arg_cache; +} G_END_DECLS diff --git a/gi/pygi-ccallback.c b/gi/pygi-ccallback.c index 82777fb..db12f49 100644 --- a/gi/pygi-ccallback.c +++ b/gi/pygi-ccallback.c @@ -16,16 +16,13 @@ * 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 + * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ -#include "pygi-private.h" +#include "pygi-util.h" +#include "pygi-ccallback.h" -#include <pygobject.h> #include <girepository.h> -#include <pyglib-python-compat.h> static PyObject * @@ -34,21 +31,20 @@ _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 = (PyGICCallbackCache *)pygi_ccallback_cache_new (self->info, + self->callback); if (self->cache == NULL) return NULL; } - result = pygi_callable_info_invoke( (GIBaseInfo *) self->info, - args, - kwargs, - self->cache, - self->callback, - self->user_data); + result = pygi_ccallback_cache_invoke (self->cache, + args, + kwargs, + self->user_data); return result; } -PYGLIB_DEFINE_TYPE("gi.CCallback", PyGICCallback_Type, PyGICCallback); +PYGI_DEFINE_TYPE("gi.CCallback", PyGICCallback_Type, PyGICCallback); PyObject * _pygi_ccallback_new (GCallback callback, @@ -81,19 +77,33 @@ static void _ccallback_dealloc (PyGICCallback *self) { g_base_info_unref ( (GIBaseInfo *)self->info); + + if (self->cache != NULL) { + pygi_callable_cache_free ( (PyGICallableCache *)self->cache); + } + + Py_TYPE (self)->tp_free ((PyObject *)self); } -void -_pygi_ccallback_register_types (PyObject *m) +/** + * Returns 0 on success, or -1 and sets an exception. + */ +int +pygi_ccallback_register_types (PyObject *m) { - Py_TYPE(&PyGICCallback_Type) = &PyType_Type; + Py_SET_TYPE(&PyGICCallback_Type, &PyType_Type); PyGICCallback_Type.tp_flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE); PyGICCallback_Type.tp_dealloc = (destructor) _ccallback_dealloc; PyGICCallback_Type.tp_call = (ternaryfunc) _ccallback_call; - if (PyType_Ready (&PyGICCallback_Type)) - return; - if (PyModule_AddObject (m, "CCallback", (PyObject *) &PyGICCallback_Type)) - return; + if (PyType_Ready (&PyGICCallback_Type) < 0) + return -1; + Py_INCREF ((PyObject *) &PyGICCallback_Type); + if (PyModule_AddObject (m, "CCallback", (PyObject *) &PyGICCallback_Type) < 0) { + Py_INCREF ((PyObject *) &PyGICCallback_Type); + return -1; + } + + return 0; } diff --git a/gi/pygi-ccallback.h b/gi/pygi-ccallback.h index c796092..7b8439d 100644 --- a/gi/pygi-ccallback.h +++ b/gi/pygi-ccallback.h @@ -14,18 +14,27 @@ * 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 + * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ #ifndef __PYGI_CCLOSURE_H__ #define __PYGI_CCLOSURE_H__ #include <Python.h> +#include "pygi-cache.h" G_BEGIN_DECLS +typedef struct { + PyObject_HEAD + GCallback callback; + GIFunctionInfo *info; + gpointer user_data; + GIScopeType scope; + GDestroyNotify destroy_notify_func; + PyGICCallbackCache *cache; +} PyGICCallback; + extern PyTypeObject PyGICCallback_Type; PyObject * _pygi_ccallback_new (GCallback callback, @@ -34,7 +43,7 @@ PyObject * _pygi_ccallback_new (GCallback callback, GIFunctionInfo *info, GDestroyNotify destroy_notify); -void _pygi_ccallback_register_types (PyObject *m); +int pygi_ccallback_register_types (PyObject *m); G_END_DECLS diff --git a/gi/pygi-closure.c b/gi/pygi-closure.c index 2f5548a..4e19c5e 100644 --- a/gi/pygi-closure.c +++ b/gi/pygi-closure.c @@ -14,12 +14,27 @@ * 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 + * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ -#include "pygi-private.h" +#include "pygi-closure.h" +#include "pygi-error.h" +#include "pygi-marshal-cleanup.h" +#include "pygi-invoke.h" +#include "pygi-ccallback.h" +#include "pygi-info.h" + +extern PyObject *_PyGIDefaultArgPlaceholder; + +typedef struct _PyGICallbackCache +{ + PyGIArgCache arg_cache; + gssize user_data_index; + gssize destroy_notify_index; + GIScopeType scope; + GIInterfaceInfo *interface_info; + PyGIClosureCache *closure_cache; +} PyGICallbackCache; /* This maintains a list of closures which can be free'd whenever as they have been called. We will free them on the next @@ -28,493 +43,494 @@ static GSList* async_free_list; static void -_pygi_closure_assign_pyobj_to_retval (gpointer retval, PyObject *object, - GITypeInfo *type_info, - GITransfer transfer) +_pygi_closure_assign_pyobj_to_retval (gpointer retval, + GIArgument *arg, + PyGIArgCache *arg_cache) { - GIArgument arg = _pygi_argument_from_object (object, type_info, transfer); - GITypeTag type_tag; - if (PyErr_Occurred ()) - return; - - type_tag = g_type_info_get_tag (type_info); - if (retval == NULL) return; - switch (type_tag) { + switch (arg_cache->type_tag) { case GI_TYPE_TAG_BOOLEAN: - *((ffi_sarg *) retval) = arg.v_boolean; + *((ffi_sarg *) retval) = arg->v_boolean; break; case GI_TYPE_TAG_INT8: - *((ffi_sarg *) retval) = arg.v_int8; + *((ffi_sarg *) retval) = arg->v_int8; break; case GI_TYPE_TAG_UINT8: - *((ffi_arg *) retval) = arg.v_uint8; + *((ffi_arg *) retval) = arg->v_uint8; break; case GI_TYPE_TAG_INT16: - *((ffi_sarg *) retval) = arg.v_int16; + *((ffi_sarg *) retval) = arg->v_int16; break; case GI_TYPE_TAG_UINT16: - *((ffi_arg *) retval) = arg.v_uint16; + *((ffi_arg *) retval) = arg->v_uint16; break; case GI_TYPE_TAG_INT32: - *((ffi_sarg *) retval) = arg.v_int32; + *((ffi_sarg *) retval) = arg->v_int32; break; case GI_TYPE_TAG_UINT32: - *((ffi_arg *) retval) = arg.v_uint32; + *((ffi_arg *) retval) = arg->v_uint32; break; case GI_TYPE_TAG_INT64: - *((ffi_sarg *) retval) = arg.v_int64; + *((ffi_sarg *) retval) = arg->v_int64; break; case GI_TYPE_TAG_UINT64: - *((ffi_arg *) retval) = arg.v_uint64; + *((ffi_arg *) retval) = arg->v_uint64; break; case GI_TYPE_TAG_FLOAT: - *((gfloat *) retval) = arg.v_float; + *((gfloat *) retval) = arg->v_float; break; case GI_TYPE_TAG_DOUBLE: - *((gdouble *) retval) = arg.v_double; + *((gdouble *) retval) = arg->v_double; break; case GI_TYPE_TAG_GTYPE: - *((ffi_arg *) retval) = arg.v_ulong; + *((ffi_arg *) retval) = arg->v_size; break; case GI_TYPE_TAG_UNICHAR: - *((ffi_arg *) retval) = arg.v_uint32; + *((ffi_arg *) retval) = arg->v_uint32; break; case GI_TYPE_TAG_INTERFACE: { - GIBaseInfo* interface_info; - GIInfoType interface_type; + GIBaseInfo *interface_info; - interface_info = g_type_info_get_interface(type_info); - interface_type = g_base_info_get_type(interface_info); + interface_info = ((PyGIInterfaceCache *) arg_cache)->interface_info; - switch (interface_type) { + switch (g_base_info_get_type (interface_info)) { case GI_INFO_TYPE_ENUM: - *(ffi_sarg *) retval = arg.v_int; + *(ffi_sarg *) retval = arg->v_int; break; case GI_INFO_TYPE_FLAGS: - *(ffi_arg *) retval = arg.v_uint; + *(ffi_arg *) retval = arg->v_uint; break; default: - *(ffi_arg *) retval = (ffi_arg) arg.v_pointer; + *(ffi_arg *) retval = (ffi_arg) arg->v_pointer; break; } - g_base_info_unref (interface_info); break; } default: - *(ffi_arg *) retval = (ffi_arg) arg.v_pointer; + *(ffi_arg *) retval = (ffi_arg) arg->v_pointer; break; } } static void -_pygi_closure_clear_retval (GICallableInfo *callable_info, gpointer retval) -{ - GITypeInfo return_type_info; - GITypeTag return_type_tag; - - g_callable_info_load_return_type (callable_info, &return_type_info); - return_type_tag = g_type_info_get_tag (&return_type_info); - if (return_type_tag != GI_TYPE_TAG_VOID) { - *((ffi_arg *) retval) = 0; - } -} - -static void -_pygi_closure_assign_pyobj_to_out_argument (gpointer out_arg, PyObject *object, - GITypeInfo *type_info, - GITransfer transfer) +_pygi_closure_assign_pyobj_to_out_argument (gpointer out_arg, + GIArgument *arg, + PyGIArgCache *arg_cache) { - GIArgument arg = _pygi_argument_from_object (object, type_info, transfer); - GITypeTag type_tag = g_type_info_get_tag (type_info); - if (out_arg == NULL) return; - switch (type_tag) { + switch (arg_cache->type_tag) { case GI_TYPE_TAG_BOOLEAN: - *((gboolean *) out_arg) = arg.v_boolean; + *((gboolean *) out_arg) = arg->v_boolean; break; case GI_TYPE_TAG_INT8: - *((gint8 *) out_arg) = arg.v_int8; + *((gint8 *) out_arg) = arg->v_int8; break; case GI_TYPE_TAG_UINT8: - *((guint8 *) out_arg) = arg.v_uint8; + *((guint8 *) out_arg) = arg->v_uint8; break; case GI_TYPE_TAG_INT16: - *((gint16 *) out_arg) = arg.v_int16; + *((gint16 *) out_arg) = arg->v_int16; break; case GI_TYPE_TAG_UINT16: - *((guint16 *) out_arg) = arg.v_uint16; + *((guint16 *) out_arg) = arg->v_uint16; break; case GI_TYPE_TAG_INT32: - *((gint32 *) out_arg) = arg.v_int32; + *((gint32 *) out_arg) = arg->v_int32; break; case GI_TYPE_TAG_UINT32: - *((guint32 *) out_arg) = arg.v_uint32; + *((guint32 *) out_arg) = arg->v_uint32; break; case GI_TYPE_TAG_INT64: - *((gint64 *) out_arg) = arg.v_int64; + *((gint64 *) out_arg) = arg->v_int64; break; case GI_TYPE_TAG_UINT64: - *((glong *) out_arg) = arg.v_uint64; + *((guint64 *) out_arg) = arg->v_uint64; break; case GI_TYPE_TAG_FLOAT: - *((gfloat *) out_arg) = arg.v_float; + *((gfloat *) out_arg) = arg->v_float; break; case GI_TYPE_TAG_DOUBLE: - *((gdouble *) out_arg) = arg.v_double; + *((gdouble *) out_arg) = arg->v_double; break; case GI_TYPE_TAG_GTYPE: - *((gulong *) out_arg) = arg.v_ulong; + *((GType *) out_arg) = arg->v_size; break; case GI_TYPE_TAG_UNICHAR: - *((guint32 *) out_arg) = arg.v_uint32; + *((guint32 *) out_arg) = arg->v_uint32; break; case GI_TYPE_TAG_INTERFACE: { - GIBaseInfo *interface; - GIInfoType interface_type; + GIBaseInfo *interface_info; - interface = g_type_info_get_interface (type_info); - interface_type = g_base_info_get_type (interface); + interface_info = ((PyGIInterfaceCache *) arg_cache)->interface_info; - switch (interface_type) { + switch (g_base_info_get_type (interface_info)) { case GI_INFO_TYPE_ENUM: - *(gint *) out_arg = arg.v_int; + *(gint *) out_arg = arg->v_int; break; case GI_INFO_TYPE_FLAGS: - *(guint *) out_arg = arg.v_uint; + *(guint *) out_arg = arg->v_uint; break; case GI_INFO_TYPE_STRUCT: - if (!g_type_info_is_pointer (type_info)) { - if (object != Py_None) { - gsize item_size = _pygi_g_type_info_size (type_info); - memcpy (out_arg, arg.v_pointer, item_size); + if (!arg_cache->is_pointer) { + if (arg->v_pointer != NULL) { + gsize item_size = _pygi_g_type_info_size (arg_cache->type_info); + memcpy (out_arg, arg->v_pointer, item_size); } break; } - - /* Fall through if pointer */ + *((gpointer *) out_arg) = arg->v_pointer; + break; default: - *((gpointer *) out_arg) = arg.v_pointer; + *((gpointer *) out_arg) = arg->v_pointer; break; } - - g_base_info_unref (interface); break; } default: - *((gpointer *) out_arg) = arg.v_pointer; + *((gpointer *) out_arg) = arg->v_pointer; break; } } -static GIArgument * -_pygi_closure_convert_ffi_arguments (GICallableInfo *callable_info, void **args) +static void +_pygi_closure_convert_ffi_arguments (PyGIInvokeArgState *state, + PyGICallableCache *cache, + void **args) { - gint num_args, i; - GIArgInfo arg_info; - GITypeInfo arg_type; - GITypeTag tag; - GIDirection direction; - GIArgument *g_args; - - num_args = g_callable_info_get_n_args (callable_info); - g_args = g_new0 (GIArgument, num_args); - - for (i = 0; i < num_args; i++) { - g_callable_info_load_arg (callable_info, i, &arg_info); - g_arg_info_load_type (&arg_info, &arg_type); - tag = g_type_info_get_tag (&arg_type); - direction = g_arg_info_get_direction (&arg_info); - - if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT) { - g_args[i].v_pointer = * (gpointer *) args[i]; + guint i; + + for (i = 0; i < _pygi_callable_cache_args_len (cache); i++) { + PyGIArgCache *arg_cache = g_ptr_array_index (cache->args_cache, i); + gpointer arg_pointer; + + if (arg_cache->direction & PYGI_DIRECTION_FROM_PYTHON) { + state[i].arg_value.v_pointer = * (gpointer *) args[i]; + + if (state[i].arg_value.v_pointer == NULL) + continue; + + state[i].arg_pointer.v_pointer = state[i].arg_value.v_pointer; + arg_pointer = state[i].arg_value.v_pointer; } else { - switch (tag) { - case GI_TYPE_TAG_BOOLEAN: - g_args[i].v_boolean = * (gboolean *) args[i]; - break; - case GI_TYPE_TAG_INT8: - g_args[i].v_int8 = * (gint8 *) args[i]; - break; - case GI_TYPE_TAG_UINT8: - g_args[i].v_uint8 = * (guint8 *) args[i]; - break; - case GI_TYPE_TAG_INT16: - g_args[i].v_int16 = * (gint16 *) args[i]; - break; - case GI_TYPE_TAG_UINT16: - g_args[i].v_uint16 = * (guint16 *) args[i]; - break; - case GI_TYPE_TAG_INT32: - g_args[i].v_int32 = * (gint32 *) args[i]; - break; - case GI_TYPE_TAG_UINT32: - g_args[i].v_uint32 = * (guint32 *) args[i]; - break; - case GI_TYPE_TAG_INT64: - g_args[i].v_int64 = * (glong *) args[i]; - break; - case GI_TYPE_TAG_UINT64: - g_args[i].v_uint64 = * (glong *) args[i]; - break; - case GI_TYPE_TAG_FLOAT: - g_args[i].v_float = * (gfloat *) args[i]; - break; - case GI_TYPE_TAG_DOUBLE: - g_args[i].v_double = * (gdouble *) args[i]; - break; - case GI_TYPE_TAG_UTF8: - g_args[i].v_string = * (gchar **) args[i]; - break; - case GI_TYPE_TAG_INTERFACE: - { - GIBaseInfo *interface; - GIInfoType interface_type; - - interface = g_type_info_get_interface (&arg_type); - interface_type = g_base_info_get_type (interface); - - if (interface_type == GI_INFO_TYPE_OBJECT || - interface_type == GI_INFO_TYPE_INTERFACE) { - g_args[i].v_pointer = * (gpointer *) args[i]; - g_base_info_unref (interface); - break; - } else if (interface_type == GI_INFO_TYPE_ENUM || - interface_type == GI_INFO_TYPE_FLAGS) { - g_args[i].v_uint = * (guint *) args[i]; - g_base_info_unref (interface); - break; - } else if (interface_type == GI_INFO_TYPE_STRUCT || - interface_type == GI_INFO_TYPE_CALLBACK) { - g_args[i].v_pointer = * (gpointer *) args[i]; - g_base_info_unref (interface); - break; - } + arg_pointer = args[i]; + } + + switch (arg_cache->type_tag) { + case GI_TYPE_TAG_BOOLEAN: + state[i].arg_value.v_boolean = * (gboolean *) arg_pointer; + break; + case GI_TYPE_TAG_INT8: + state[i].arg_value.v_int8 = * (gint8 *) arg_pointer; + break; + case GI_TYPE_TAG_UINT8: + state[i].arg_value.v_uint8 = * (guint8 *) arg_pointer; + break; + case GI_TYPE_TAG_INT16: + state[i].arg_value.v_int16 = * (gint16 *) arg_pointer; + break; + case GI_TYPE_TAG_UINT16: + state[i].arg_value.v_uint16 = * (guint16 *) arg_pointer; + break; + case GI_TYPE_TAG_INT32: + state[i].arg_value.v_int32 = * (gint32 *) arg_pointer; + break; + case GI_TYPE_TAG_UINT32: + state[i].arg_value.v_uint32 = * (guint32 *) arg_pointer; + break; + case GI_TYPE_TAG_INT64: + state[i].arg_value.v_int64 = * (gint64 *) arg_pointer; + break; + case GI_TYPE_TAG_UINT64: + state[i].arg_value.v_uint64 = * (guint64 *) arg_pointer; + break; + case GI_TYPE_TAG_FLOAT: + state[i].arg_value.v_float = * (gfloat *) arg_pointer; + break; + case GI_TYPE_TAG_DOUBLE: + state[i].arg_value.v_double = * (gdouble *) arg_pointer; + break; + case GI_TYPE_TAG_UTF8: + state[i].arg_value.v_string = * (gchar **) arg_pointer; + break; + case GI_TYPE_TAG_INTERFACE: + { + GIBaseInfo *interface; + GIInfoType interface_type; + + interface = ((PyGIInterfaceCache *) arg_cache)->interface_info; + interface_type = g_base_info_get_type (interface); - g_base_info_unref (interface); + if (interface_type == GI_INFO_TYPE_ENUM) { + state[i].arg_value.v_int = * (gint *) arg_pointer; + } else if (interface_type == GI_INFO_TYPE_FLAGS) { + state[i].arg_value.v_uint = * (guint *) arg_pointer; + } else { + state[i].arg_value.v_pointer = * (gpointer *) arg_pointer; } - case GI_TYPE_TAG_ERROR: - case GI_TYPE_TAG_GHASH: - case GI_TYPE_TAG_GLIST: - case GI_TYPE_TAG_GSLIST: - case GI_TYPE_TAG_ARRAY: - case GI_TYPE_TAG_VOID: - g_args[i].v_pointer = * (gpointer *) args[i]; - break; - default: - g_warning ("Unhandled type tag %s", g_type_tag_to_string (tag)); - g_args[i].v_pointer = 0; + break; } + case GI_TYPE_TAG_UNICHAR: + state[i].arg_value.v_uint32 = * (guint32 *) arg_pointer; + break; + case GI_TYPE_TAG_ERROR: + case GI_TYPE_TAG_GHASH: + case GI_TYPE_TAG_GLIST: + case GI_TYPE_TAG_GSLIST: + case GI_TYPE_TAG_ARRAY: + case GI_TYPE_TAG_VOID: + state[i].arg_value.v_pointer = * (gpointer *) arg_pointer; + break; + default: + g_warning ("Unhandled type tag %s", + g_type_tag_to_string (arg_cache->type_tag)); + state[i].arg_value.v_pointer = 0; } } - return g_args; + + if (cache->throws) { + gssize error_index = _pygi_callable_cache_args_len (cache); + + state[error_index].arg_value.v_pointer = * (gpointer *) args[error_index]; + } } static gboolean -_pygi_closure_convert_arguments (GICallableInfo *callable_info, void **args, - void *user_data, PyObject **py_args, - GIArgument **out_args) +_invoke_state_init_from_cache (PyGIInvokeState *state, + PyGIClosureCache *closure_cache, + void **args) { - int n_args = g_callable_info_get_n_args (callable_info); - int n_in_args = 0; - int n_out_args = 0; - int i; - int user_data_arg = -1; - int destroy_notify_arg = -1; - - GIArgument *g_args = NULL; - - *py_args = NULL; - *py_args = PyTuple_New (n_args); - if (*py_args == NULL) - goto error; - - *out_args = NULL; - *out_args = g_new0 (GIArgument, n_args); - g_args = _pygi_closure_convert_ffi_arguments (callable_info, args); - - for (i = 0; i < n_args; i++) { - GIArgInfo arg_info; - GIDirection direction; - - /* Special case callbacks and skip over userdata and Destroy Notify */ - if (i == user_data_arg || i == destroy_notify_arg) - continue; - - g_callable_info_load_arg (callable_info, i, &arg_info); - direction = g_arg_info_get_direction (&arg_info); - - if (direction == GI_DIRECTION_IN || direction == GI_DIRECTION_INOUT) { - GITypeInfo arg_type; - GITypeTag arg_tag; - GITransfer transfer; - PyObject *value; - GIArgument *arg; - gboolean free_array; + PyGICallableCache *cache = (PyGICallableCache *) closure_cache; + + state->n_args = _pygi_callable_cache_args_len (cache); + state->n_py_in_args = state->n_args; + + /* Increment after setting the number of Python input args */ + if (cache->throws) { + state->n_args++; + } + + state->py_in_args = PyTuple_New (state->n_py_in_args); + if (state->py_in_args == NULL) { + PyErr_NoMemory (); + return FALSE; + } + + state->args = NULL; + state->error = NULL; + + if (!_pygi_invoke_arg_state_init (state)) { + return FALSE; + } + + state->ffi_args = NULL; + + _pygi_closure_convert_ffi_arguments (state->args, cache, args); + return TRUE; +} + +static void +_invoke_state_clear (PyGIInvokeState *state) +{ + _pygi_invoke_arg_state_free (state); + Py_XDECREF (state->py_in_args); +} + +static gboolean +_pygi_closure_convert_arguments (PyGIInvokeState *state, + PyGIClosureCache *closure_cache) +{ + PyGICallableCache *cache = (PyGICallableCache *) closure_cache; + gssize n_in_args = 0; + gssize i; - g_arg_info_load_type (&arg_info, &arg_type); - arg_tag = g_type_info_get_tag (&arg_type); - transfer = g_arg_info_get_ownership_transfer (&arg_info); - free_array = FALSE; + for (i = 0; (gsize)i < _pygi_callable_cache_args_len (cache); i++) { + PyGIArgCache *arg_cache; - if (direction == GI_DIRECTION_IN && arg_tag == GI_TYPE_TAG_VOID && - g_type_info_is_pointer (&arg_type)) { + arg_cache = g_ptr_array_index (cache->args_cache, i); + + if (arg_cache->direction & PYGI_DIRECTION_TO_PYTHON) { + PyObject *value; - if (user_data == NULL) { + if (cache->user_data_index == i) { + if (state->user_data == NULL) { + /* user_data can be NULL for connect functions which don't accept + * user_data or as the default for user_data in the middle of function + * arguments. + */ Py_INCREF (Py_None); value = Py_None; } else { - value = user_data; - Py_INCREF (value); + /* Extend the callbacks args with user_data as variable args. */ + gssize j, user_data_len; + PyObject *py_user_data = state->user_data; + + if (!PyTuple_Check (py_user_data)) { + PyErr_SetString (PyExc_TypeError, "expected tuple for callback user_data"); + return FALSE; + } + + user_data_len = PyTuple_Size (py_user_data); + _PyTuple_Resize (&state->py_in_args, + state->n_py_in_args + user_data_len - 1); + + for (j = 0; j < user_data_len; j++, n_in_args++) { + value = PyTuple_GetItem (py_user_data, j); + Py_INCREF (value); + PyTuple_SET_ITEM (state->py_in_args, n_in_args, value); + } + /* We can assume user_data args are never going to be inout, + * so just continue here. + */ + continue; } - } else if (direction == GI_DIRECTION_IN && - arg_tag == GI_TYPE_TAG_INTERFACE) { - /* Handle callbacks as a special case */ - GIBaseInfo *info; - GIInfoType info_type; - - info = g_type_info_get_interface (&arg_type); - info_type = g_base_info_get_type (info); - - arg = (GIArgument*) &g_args[i]; - - if (info_type == GI_INFO_TYPE_CALLBACK) { - gpointer user_data = NULL; - GDestroyNotify destroy_notify = NULL; - GIScopeType scope = g_arg_info_get_scope(&arg_info); - - user_data_arg = g_arg_info_get_closure(&arg_info); - destroy_notify_arg = g_arg_info_get_destroy(&arg_info); - - if (user_data_arg != -1) - user_data = g_args[user_data_arg].v_pointer; - - if (destroy_notify_arg != -1) - user_data = (GDestroyNotify) g_args[destroy_notify_arg].v_pointer; - - value = _pygi_ccallback_new(arg->v_pointer, - user_data, - scope, - (GIFunctionInfo *) info, - destroy_notify); - } else - value = _pygi_argument_to_object (arg, &arg_type, transfer); - - g_base_info_unref (info); - if (value == NULL) - goto error; + } else if (arg_cache->meta_type != PYGI_META_ARG_TYPE_PARENT) { + continue; } else { - if (direction == GI_DIRECTION_IN) - arg = (GIArgument*) &g_args[i]; - else - arg = (GIArgument*) g_args[i].v_pointer; - - if (g_type_info_get_tag (&arg_type) == GI_TYPE_TAG_ARRAY) - arg->v_pointer = _pygi_argument_to_array (arg, (GIArgument **) args, NULL, - callable_info, &arg_type, &free_array); - - value = _pygi_argument_to_object (arg, &arg_type, transfer); - - if (free_array) - g_array_free (arg->v_pointer, FALSE); - - if (value == NULL) - goto error; + gpointer cleanup_data = NULL; + + value = arg_cache->to_py_marshaller (state, + cache, + arg_cache, + &state->args[i].arg_value, + &cleanup_data); + state->args[i].to_py_arg_cleanup_data = cleanup_data; + + if (value == NULL) { + pygi_marshal_cleanup_args_to_py_parameter_fail (state, + cache, + i); + return FALSE; + } } - PyTuple_SET_ITEM (*py_args, n_in_args, value); - n_in_args++; - } - if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT) { - (*out_args) [n_out_args] = g_args[i]; - n_out_args++; + PyTuple_SET_ITEM (state->py_in_args, n_in_args, value); + n_in_args++; } - } - if (_PyTuple_Resize (py_args, n_in_args) == -1) - goto error; + if (_PyTuple_Resize (&state->py_in_args, n_in_args) == -1) + return FALSE; - g_free (g_args); return TRUE; - -error: - Py_CLEAR (*py_args); - g_free (*out_args); - *out_args = NULL; - g_free (g_args); - - return FALSE; } -static void -_pygi_closure_set_out_arguments (GICallableInfo *callable_info, - PyObject *py_retval, GIArgument *out_args, +static gboolean +_pygi_closure_set_out_arguments (PyGIInvokeState *state, + PyGICallableCache *cache, + PyObject *py_retval, void *resp) { - int n_args, i, i_py_retval, i_out_args; - GITypeInfo return_type_info; - GITypeTag return_type_tag; - - i_py_retval = 0; - g_callable_info_load_return_type (callable_info, &return_type_info); - return_type_tag = g_type_info_get_tag (&return_type_info); - if (return_type_tag != GI_TYPE_TAG_VOID) { - GITransfer transfer = g_callable_info_get_caller_owns (callable_info); + gssize i; + gssize i_py_retval = 0; + gboolean success; + + if (cache->return_cache->type_tag != GI_TYPE_TAG_VOID) { + PyObject *item = py_retval; + if (PyTuple_Check (py_retval)) { - PyObject *item = PyTuple_GET_ITEM (py_retval, 0); - _pygi_closure_assign_pyobj_to_retval (resp, item, - &return_type_info, transfer); - } else { - _pygi_closure_assign_pyobj_to_retval (resp, py_retval, - &return_type_info, transfer); + item = PyTuple_GET_ITEM (py_retval, 0); + } + + success = cache->return_cache->from_py_marshaller (state, + cache, + cache->return_cache, + item, + &state->return_arg, + &state->args[0].arg_cleanup_data); + + if (!success) { + pygi_marshal_cleanup_args_return_fail (state, + cache); + return FALSE; } + + _pygi_closure_assign_pyobj_to_retval (resp, &state->return_arg, + cache->return_cache); i_py_retval++; } - i_out_args = 0; - n_args = g_callable_info_get_n_args (callable_info); - for (i = 0; i < n_args; i++) { - GIArgInfo arg_info; - GITypeInfo type_info; - GIDirection direction; - g_callable_info_load_arg (callable_info, i, &arg_info); - g_arg_info_load_type (&arg_info, &type_info); - direction = g_arg_info_get_direction (&arg_info); - - if (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT) { - GITransfer transfer = g_arg_info_get_ownership_transfer (&arg_info); - - if (g_type_info_get_tag (&type_info) == GI_TYPE_TAG_ERROR) { - /* TODO: check if an exception has been set and convert it to a GError */ - out_args[i_out_args].v_pointer = NULL; - i_out_args++; + for (i = 0; (gsize)i < _pygi_callable_cache_args_len (cache); i++) { + PyGIArgCache *arg_cache = g_ptr_array_index (cache->args_cache, i); + + if (arg_cache->direction & PYGI_DIRECTION_FROM_PYTHON) { + PyObject *item = py_retval; + + if (arg_cache->type_tag == GI_TYPE_TAG_ERROR) { + * (GError **) state->args[i].arg_pointer.v_pointer = NULL; continue; } if (PyTuple_Check (py_retval)) { - PyObject *item = PyTuple_GET_ITEM (py_retval, i_py_retval); - _pygi_closure_assign_pyobj_to_out_argument ( - out_args[i_out_args].v_pointer, item, &type_info, transfer); - } else if (i_py_retval == 0) { - _pygi_closure_assign_pyobj_to_out_argument ( - out_args[i_out_args].v_pointer, py_retval, &type_info, - transfer); - } else - g_assert_not_reached(); - - i_out_args++; + item = PyTuple_GET_ITEM (py_retval, i_py_retval); + } else if (i_py_retval != 0) { + pygi_marshal_cleanup_args_to_py_parameter_fail (state, + cache, + i_py_retval); + return FALSE; + } + + success = arg_cache->from_py_marshaller (state, + cache, + arg_cache, + item, + &state->args[i].arg_value, + &state->args[i_py_retval].arg_cleanup_data); + + if (!success) { + pygi_marshal_cleanup_args_to_py_parameter_fail (state, + cache, + i_py_retval); + return FALSE; + } + + _pygi_closure_assign_pyobj_to_out_argument (state->args[i].arg_pointer.v_pointer, + &state->args[i].arg_value, arg_cache); + i_py_retval++; } } + + return TRUE; +} + +static void +_pygi_closure_clear_retvals (PyGIInvokeState *state, + PyGICallableCache *cache, + gpointer resp) +{ + gsize i; + GIArgument arg = { 0, }; + + if (cache->return_cache->type_tag != GI_TYPE_TAG_VOID) { + _pygi_closure_assign_pyobj_to_retval (resp, &arg, + cache->return_cache); + } + + for (i = 0; i < _pygi_callable_cache_args_len (cache); i++) { + PyGIArgCache *arg_cache = g_ptr_array_index (cache->args_cache, i); + + if (arg_cache->direction & PYGI_DIRECTION_FROM_PYTHON) { + _pygi_closure_assign_pyobj_to_out_argument (state->args[i].arg_pointer.v_pointer, + &arg, arg_cache); + } + } + + if (cache->throws) { + gssize error_index = state->n_args - 1; + GError **error = (GError **) state->args[error_index].arg_value.v_pointer; + + if (error != NULL) { + pygi_gerror_exception_check (error); + } + } } static void @@ -534,43 +550,56 @@ _pygi_closure_handle (ffi_cif *cif, void **args, void *data) { - PyGILState_STATE state; + PyGILState_STATE py_state; PyGICClosure *closure = data; PyObject *retval; - PyObject *py_args; - GIArgument *out_args = NULL; + gboolean success; + PyGIInvokeState state = { 0, }; + + /* Ignore closures when Python is not initialized. This can happen in cases + * where calling Python implemented vfuncs can happen at shutdown time. + * See: https://bugzilla.gnome.org/show_bug.cgi?id=722562 */ + if (!Py_IsInitialized()) { + return; + } /* Lock the GIL as we are coming into this code without the lock and we may be executing python code */ - state = PyGILState_Ensure(); + py_state = PyGILState_Ensure (); + + if (closure->cache == NULL) + goto end; + + state.user_data = closure->user_data; - if (!_pygi_closure_convert_arguments ( (GICallableInfo *) closure->info, args, - closure->user_data, - &py_args, &out_args)) { - if (PyErr_Occurred ()) - PyErr_Print(); + _invoke_state_init_from_cache (&state, closure->cache, args); + + if (!_pygi_closure_convert_arguments (&state, closure->cache)) { + _pygi_closure_clear_retvals (&state, closure->cache, result); goto end; } - retval = PyObject_CallObject ( (PyObject *) closure->function, py_args); - Py_DECREF (py_args); + retval = PyObject_CallObject ( (PyObject *) closure->function, state.py_in_args); if (retval == NULL) { - _pygi_closure_clear_retval (closure->info, result); - PyErr_Print(); + _pygi_closure_clear_retvals (&state, closure->cache, result); goto end; } - _pygi_closure_set_out_arguments (closure->info, retval, out_args, result); - if (PyErr_Occurred ()) { - _pygi_closure_clear_retval (closure->info, result); - PyErr_Print(); + pygi_marshal_cleanup_args_to_py_marshal_success (&state, closure->cache); + success = _pygi_closure_set_out_arguments (&state, closure->cache, retval, result); + + if (!success) { + pygi_marshal_cleanup_args_from_py_marshal_success (&state, closure->cache); + _pygi_closure_clear_retvals (&state, closure->cache, result); } Py_DECREF (retval); end: - g_free (out_args); + + if (PyErr_Occurred ()) + PyErr_Print (); /* Now that the closure has finished we can make a decision about how to free it. Scope call gets free'd at the end of wrap_g_function_info_invoke. @@ -591,23 +620,31 @@ end: async_free_list = g_slist_prepend (async_free_list, closure); break; default: - g_error ("Invalid scope reached inside %s. Possibly a bad annotation?", - g_base_info_get_name (closure->info)); + /* Handle new scopes added by gobject-introspection */ + g_critical ("Unknown scope reached inside %s. Please file an issue " + "at https://gitlab.gnome.org/GNOME/pygobject/issues/new", + g_base_info_get_name (closure->info)); } - PyGILState_Release (state); + _invoke_state_clear (&state); + PyGILState_Release (py_state); } -void _pygi_invoke_closure_free (gpointer data) +void _pygi_invoke_closure_free (PyGICClosure* invoke_closure) { - PyGICClosure* invoke_closure = (PyGICClosure *) data; - +#if GI_CHECK_VERSION (1, 72, 0) + g_callable_info_destroy_closure (invoke_closure->info, + invoke_closure->closure); +#else g_callable_info_free_closure (invoke_closure->info, invoke_closure->closure); +#endif if (invoke_closure->info) g_base_info_unref ( (GIBaseInfo*) invoke_closure->info); + invoke_closure->cache = NULL; + _pygi_invoke_closure_clear_py_data(invoke_closure); g_slice_free (PyGICClosure, invoke_closure); @@ -616,9 +653,10 @@ void _pygi_invoke_closure_free (gpointer data) PyGICClosure* _pygi_make_native_closure (GICallableInfo* info, + PyGIClosureCache *cache, GIScopeType scope, PyObject *py_function, - gpointer py_user_data) + PyObject *py_user_data) { PyGICClosure *closure; ffi_closure *fficlosure; @@ -631,14 +669,22 @@ _pygi_make_native_closure (GICallableInfo* info, closure = g_slice_new0 (PyGICClosure); closure->info = (GICallableInfo *) g_base_info_ref ( (GIBaseInfo *) info); closure->function = py_function; - closure->user_data = py_user_data ? py_user_data : Py_None; + closure->user_data = py_user_data; + closure->cache = cache; Py_INCREF (py_function); - Py_INCREF (closure->user_data); + Py_XINCREF (closure->user_data); +#if GI_CHECK_VERSION (1, 72, 0) + fficlosure = + g_callable_info_create_closure (info, &closure->cif, _pygi_closure_handle, + closure); +#else fficlosure = g_callable_info_prepare_closure (info, &closure->cif, _pygi_closure_handle, closure); +#endif + closure->closure = fficlosure; /* Give the closure the information it needs to determine when @@ -647,3 +693,285 @@ _pygi_make_native_closure (GICallableInfo* info, return closure; } + +/* _pygi_destroy_notify_dummy: + * + * Dummy method used in the occasion when a method has a GDestroyNotify + * argument without user data. + */ +static void +_pygi_destroy_notify_dummy (gpointer data) { +} + +static gboolean +_pygi_marshal_from_py_interface_callback (PyGIInvokeState *state, + PyGICallableCache *callable_cache, + PyGIArgCache *arg_cache, + PyObject *py_arg, + GIArgument *arg, + gpointer *cleanup_data) +{ + GICallableInfo *callable_info; + PyGICClosure *closure; + PyGIArgCache *user_data_cache = NULL; + PyGIArgCache *destroy_cache = NULL; + PyGICallbackCache *callback_cache; + PyObject *py_user_data = NULL; + + callback_cache = (PyGICallbackCache *)arg_cache; + + if (callback_cache->user_data_index > 0) { + user_data_cache = _pygi_callable_cache_get_arg (callable_cache, (guint)callback_cache->user_data_index); + if (user_data_cache->py_arg_index < state->n_py_in_args) { + /* py_user_data is a borrowed reference. */ + py_user_data = PyTuple_GetItem (state->py_in_args, user_data_cache->py_arg_index); + if (!py_user_data) + return FALSE; + /* NULL out user_data if it was not supplied and the default arg placeholder + * was used instead. + */ + if (py_user_data == _PyGIDefaultArgPlaceholder) { + py_user_data = NULL; + } else if (callable_cache->user_data_varargs_index < 0) { + /* For non-variable length user data, place the user data in a + * single item tuple which is concatenated to the callbacks arguments. + * This allows callback input arg marshaling to always expect a + * tuple for user data. Note the + */ + py_user_data = Py_BuildValue("(O)", py_user_data, NULL); + } else { + /* increment the ref borrowed from PyTuple_GetItem above */ + Py_INCREF (py_user_data); + } + } + } + + if (py_arg == Py_None) { + return TRUE; + } + + if (!PyCallable_Check (py_arg)) { + PyErr_Format (PyExc_TypeError, + "Callback needs to be a function or method not %s", + Py_TYPE (py_arg)->tp_name); + + return FALSE; + } + + callable_info = (GICallableInfo *)callback_cache->interface_info; + + closure = _pygi_make_native_closure ( + callable_info, callback_cache->closure_cache, callback_cache->scope, + py_arg, py_user_data); + +#if GI_CHECK_VERSION (1, 72, 0) + if (closure->closure != NULL) + arg->v_pointer = g_callable_info_get_closure_native_address (callable_info, closure->closure); + else + arg->v_pointer = NULL; +#else + arg->v_pointer = closure->closure; +#endif + + /* always decref the user data as _pygi_make_native_closure adds its own ref */ + Py_XDECREF (py_user_data); + + /* The PyGICClosure instance is used as user data passed into the C function. + * The return trip to python will marshal this back and pull the python user data out. + */ + if (user_data_cache != NULL) { + state->args[user_data_cache->c_arg_index].arg_value.v_pointer = closure; + } + + /* Setup a GDestroyNotify callback if this method supports it along with + * a user data field. The user data field is a requirement in order + * free resources and ref counts associated with this arguments closure. + * In case a user data field is not available, show a warning giving + * explicit information and setup a dummy notification to avoid a crash + * later on in _pygi_destroy_notify_callback_closure. + */ + if (callback_cache->destroy_notify_index > 0) { + destroy_cache = _pygi_callable_cache_get_arg (callable_cache, (guint)callback_cache->destroy_notify_index); + } + + if (destroy_cache) { + if (user_data_cache != NULL) { + state->args[destroy_cache->c_arg_index].arg_value.v_pointer = _pygi_invoke_closure_free; + } else { + char *full_name = pygi_callable_cache_get_full_name (callable_cache); + gchar *msg = g_strdup_printf("Callables passed to %s will leak references because " + "the method does not support a user_data argument. " + "See: https://bugzilla.gnome.org/show_bug.cgi?id=685598", + full_name); + g_free (full_name); + if (PyErr_WarnEx(PyExc_RuntimeWarning, msg, 2)) { + g_free(msg); + _pygi_invoke_closure_free(closure); + return FALSE; + } + g_free(msg); + state->args[destroy_cache->c_arg_index].arg_value.v_pointer = _pygi_destroy_notify_dummy; + } + } + + /* Use the PyGIClosure as data passed to cleanup for GI_SCOPE_TYPE_CALL. */ + *cleanup_data = closure; + + return TRUE; +} + +static PyObject * +_pygi_marshal_to_py_interface_callback (PyGIInvokeState *state, + PyGICallableCache *callable_cache, + PyGIArgCache *arg_cache, + GIArgument *arg, + gpointer *arg_cleanup_data) +{ + PyGICallbackCache *callback_cache = (PyGICallbackCache *) arg_cache; + gssize user_data_index; + gssize destroy_notify_index; + gpointer user_data = NULL; + GDestroyNotify destroy_notify = NULL; + + user_data_index = callback_cache->user_data_index; + destroy_notify_index = callback_cache->destroy_notify_index; + + if (user_data_index != -1) + user_data = state->args[user_data_index].arg_value.v_pointer; + + if (destroy_notify_index != -1) + destroy_notify = state->args[destroy_notify_index].arg_value.v_pointer; + + return _pygi_ccallback_new (arg->v_pointer, + user_data, + callback_cache->scope, + (GIFunctionInfo *) callback_cache->interface_info, + destroy_notify); +} + +static void +_callback_cache_free_func (PyGICallbackCache *cache) +{ + if (cache != NULL) { + if (cache->interface_info != NULL) + g_base_info_unref ( (GIBaseInfo *)cache->interface_info); + + if (cache->closure_cache != NULL) { + pygi_callable_cache_free ((PyGICallableCache *) cache->closure_cache); + cache->closure_cache = NULL; + } + + g_slice_free (PyGICallbackCache, cache); + } +} + +static void +_pygi_marshal_cleanup_from_py_interface_callback (PyGIInvokeState *state, + PyGIArgCache *arg_cache, + PyObject *py_arg, + gpointer data, + gboolean was_processed) +{ + PyGICallbackCache *callback_cache = (PyGICallbackCache *)arg_cache; + + if (was_processed && callback_cache->scope == GI_SCOPE_TYPE_CALL) { + _pygi_invoke_closure_free (data); + } +} + +static gboolean +pygi_arg_callback_setup_from_info (PyGICallbackCache *arg_cache, + GITypeInfo *type_info, + GIArgInfo *arg_info, /* may be null */ + GITransfer transfer, + PyGIDirection direction, + GIInterfaceInfo *iface_info, + PyGICallableCache *callable_cache) +{ + PyGIArgCache *cache = (PyGIArgCache *)arg_cache; + gssize child_offset = 0; + + if (!pygi_arg_base_setup ((PyGIArgCache *)arg_cache, + type_info, + arg_info, + transfer, + direction)) { + return FALSE; + } + + if (callable_cache != NULL) + child_offset = callable_cache->args_offset; + + ( (PyGIArgCache *)arg_cache)->destroy_notify = (GDestroyNotify)_callback_cache_free_func; + + arg_cache->user_data_index = g_arg_info_get_closure (arg_info); + if (arg_cache->user_data_index != -1) + arg_cache->user_data_index += child_offset; + + arg_cache->destroy_notify_index = g_arg_info_get_destroy (arg_info); + if (arg_cache->destroy_notify_index != -1) + arg_cache->destroy_notify_index += child_offset; + + if (arg_cache->user_data_index >= 0) { + PyGIArgCache *user_data_arg_cache = pygi_arg_cache_alloc (); + user_data_arg_cache->meta_type = PYGI_META_ARG_TYPE_CHILD_WITH_PYARG; + user_data_arg_cache->direction = direction; + user_data_arg_cache->has_default = TRUE; /* always allow user data with a NULL default. */ + _pygi_callable_cache_set_arg (callable_cache, (guint)arg_cache->user_data_index, + user_data_arg_cache); + } + + if (arg_cache->destroy_notify_index >= 0) { + PyGIArgCache *destroy_arg_cache = pygi_arg_cache_alloc (); + destroy_arg_cache->meta_type = PYGI_META_ARG_TYPE_CHILD; + destroy_arg_cache->direction = direction; + _pygi_callable_cache_set_arg (callable_cache, (guint)arg_cache->destroy_notify_index, + destroy_arg_cache); + } + + arg_cache->scope = g_arg_info_get_scope (arg_info); + g_base_info_ref( (GIBaseInfo *)iface_info); + arg_cache->interface_info = iface_info; + + if (direction & PYGI_DIRECTION_FROM_PYTHON) { + arg_cache->closure_cache = pygi_closure_cache_new (arg_cache->interface_info); + cache->from_py_marshaller = _pygi_marshal_from_py_interface_callback; + cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_interface_callback; + } + + if (direction & PYGI_DIRECTION_TO_PYTHON) { + cache->to_py_marshaller = _pygi_marshal_to_py_interface_callback; + } + + return TRUE; +} + +PyGIArgCache * +pygi_arg_callback_new_from_info (GITypeInfo *type_info, + GIArgInfo *arg_info, /* may be null */ + GITransfer transfer, + PyGIDirection direction, + GIInterfaceInfo *iface_info, + PyGICallableCache *callable_cache) +{ + gboolean res = FALSE; + PyGICallbackCache *callback_cache; + + callback_cache = g_slice_new0 (PyGICallbackCache); + if (callback_cache == NULL) + return NULL; + + res = pygi_arg_callback_setup_from_info (callback_cache, + type_info, + arg_info, + transfer, + direction, + iface_info, + callable_cache); + if (res) { + return (PyGIArgCache *)callback_cache; + } else { + pygi_arg_cache_free ((PyGIArgCache *)callback_cache); + return NULL; + } +} diff --git a/gi/pygi-closure.h b/gi/pygi-closure.h index 6f98339..8a52b86 100644 --- a/gi/pygi-closure.h +++ b/gi/pygi-closure.h @@ -12,9 +12,7 @@ * 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 + * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ #ifndef __PYGI_CLOSURE_H__ @@ -24,6 +22,8 @@ #include <girffi.h> #include <ffi.h> +#include "pygi-cache.h" + G_BEGIN_DECLS @@ -40,17 +40,27 @@ typedef struct _PyGICClosure GIScopeType scope; PyObject* user_data; + + PyGIClosureCache *cache; } PyGICClosure; void _pygi_closure_handle (ffi_cif *cif, void *result, void **args, void *userdata); -void _pygi_invoke_closure_free (gpointer user_data); +void _pygi_invoke_closure_free (PyGICClosure* invoke_closure); PyGICClosure* _pygi_make_native_closure (GICallableInfo* info, + PyGIClosureCache *cache, GIScopeType scope, PyObject *function, - gpointer user_data); + PyObject *user_data); + +PyGIArgCache *pygi_arg_callback_new_from_info (GITypeInfo *type_info, + GIArgInfo *arg_info, /* may be null */ + GITransfer transfer, + PyGIDirection direction, + GIInterfaceInfo *iface_info, + PyGICallableCache *callable_cache); G_END_DECLS diff --git a/gi/pygi-enum-marshal.c b/gi/pygi-enum-marshal.c new file mode 100644 index 0000000..15a489d --- /dev/null +++ b/gi/pygi-enum-marshal.c @@ -0,0 +1,407 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- + * vim: tabstop=4 shiftwidth=4 expandtab + * + * Copyright (C) 2011 John (J5) Palmieri <johnp@redhat.com> + * Copyright (C) 2014 Simon Feltman <sfeltman@gnome.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <Python.h> +#include <glib.h> + +#include "pygi-enum-marshal.h" +#include "pygi-type.h" +#include "pygenum.h" +#include "pygflags.h" + +static gboolean +gi_argument_from_c_long (GIArgument *arg_out, + long c_long_in, + GITypeTag type_tag) +{ + switch (type_tag) { + case GI_TYPE_TAG_INT8: + arg_out->v_int8 = (gint8)c_long_in; + return TRUE; + case GI_TYPE_TAG_UINT8: + arg_out->v_uint8 = (guint8)c_long_in; + return TRUE; + case GI_TYPE_TAG_INT16: + arg_out->v_int16 = (gint16)c_long_in; + return TRUE; + case GI_TYPE_TAG_UINT16: + arg_out->v_uint16 = (guint16)c_long_in; + return TRUE; + case GI_TYPE_TAG_INT32: + arg_out->v_int32 = (gint32)c_long_in; + return TRUE; + case GI_TYPE_TAG_UINT32: + arg_out->v_uint32 = (guint32)c_long_in; + return TRUE; + case GI_TYPE_TAG_INT64: + arg_out->v_int64 = (gint64)c_long_in; + return TRUE; + case GI_TYPE_TAG_UINT64: + arg_out->v_uint64 = (guint64)c_long_in; + return TRUE; + default: + PyErr_Format (PyExc_TypeError, + "Unable to marshal C long %ld to %s", + c_long_in, + g_type_tag_to_string (type_tag)); + return FALSE; + } +} + +static gboolean +gi_argument_to_c_long (GIArgument *arg_in, + long *c_long_out, + GITypeTag type_tag) +{ + switch (type_tag) { + case GI_TYPE_TAG_INT8: + *c_long_out = arg_in->v_int8; + return TRUE; + case GI_TYPE_TAG_UINT8: + *c_long_out = arg_in->v_uint8; + return TRUE; + case GI_TYPE_TAG_INT16: + *c_long_out = arg_in->v_int16; + return TRUE; + case GI_TYPE_TAG_UINT16: + *c_long_out = arg_in->v_uint16; + return TRUE; + case GI_TYPE_TAG_INT32: + *c_long_out = arg_in->v_int32; + return TRUE; + case GI_TYPE_TAG_UINT32: + *c_long_out = arg_in->v_uint32; + return TRUE; + case GI_TYPE_TAG_INT64: + if (arg_in->v_int64 > G_MAXLONG || arg_in->v_int64 < G_MINLONG) { + PyErr_Format (PyExc_TypeError, + "Unable to marshal %s to C long", + g_type_tag_to_string(type_tag)); + return FALSE; + } + *c_long_out = (glong)arg_in->v_int64; + return TRUE; + case GI_TYPE_TAG_UINT64: + if (arg_in->v_uint64 > G_MAXLONG) { + PyErr_Format (PyExc_TypeError, + "Unable to marshal %s to C long", + g_type_tag_to_string(type_tag)); + return FALSE; + } + *c_long_out = (glong)arg_in->v_uint64; + return TRUE; + default: + PyErr_Format (PyExc_TypeError, + "Unable to marshal %s to C long", + g_type_tag_to_string (type_tag)); + return FALSE; + } +} + +static gboolean +_pygi_marshal_from_py_interface_enum (PyGIInvokeState *state, + PyGICallableCache *callable_cache, + PyGIArgCache *arg_cache, + PyObject *py_arg, + GIArgument *arg, + gpointer *cleanup_data) +{ + PyObject *py_long; + long c_long; + gint is_instance; + PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache; + GIBaseInfo *interface = NULL; + + is_instance = PyObject_IsInstance (py_arg, iface_cache->py_type); + + py_long = PyNumber_Long (py_arg); + if (py_long == NULL) { + PyErr_Clear(); + goto err; + } + + c_long = PyLong_AsLong (py_long); + Py_DECREF (py_long); + + /* Write c_long into arg */ + interface = g_type_info_get_interface (arg_cache->type_info); + assert(g_base_info_get_type (interface) == GI_INFO_TYPE_ENUM); + if (!gi_argument_from_c_long(arg, + c_long, + g_enum_info_get_storage_type ((GIEnumInfo *)interface))) { + g_assert_not_reached(); + g_base_info_unref (interface); + return FALSE; + } + + /* If this is not an instance of the Enum type that we want + * we need to check if the value is equivilant to one of the + * Enum's memebers */ + if (!is_instance) { + int i; + gboolean is_found = FALSE; + + for (i = 0; i < g_enum_info_get_n_values (iface_cache->interface_info); i++) { + GIValueInfo *value_info = + g_enum_info_get_value (iface_cache->interface_info, i); + gint64 enum_value = g_value_info_get_value (value_info); + g_base_info_unref ( (GIBaseInfo *)value_info); + if (c_long == enum_value) { + is_found = TRUE; + break; + } + } + + if (!is_found) + goto err; + } + + g_base_info_unref (interface); + return TRUE; + +err: + if (interface) + g_base_info_unref (interface); + PyErr_Format (PyExc_TypeError, "Expected a %s, but got %s", + iface_cache->type_name, Py_TYPE (py_arg)->tp_name); + return FALSE; +} + +static gboolean +_pygi_marshal_from_py_interface_flags (PyGIInvokeState *state, + PyGICallableCache *callable_cache, + PyGIArgCache *arg_cache, + PyObject *py_arg, + GIArgument *arg, + gpointer *cleanup_data) +{ + PyObject *py_long; + unsigned long c_ulong; + gint is_instance; + PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache; + GIBaseInfo *interface; + + is_instance = PyObject_IsInstance (py_arg, iface_cache->py_type); + + py_long = PyNumber_Long (py_arg); + if (py_long == NULL) { + PyErr_Clear (); + goto err; + } + + c_ulong = PyLong_AsUnsignedLongMask (py_long); + Py_DECREF (py_long); + + /* only 0 or argument of type Flag is allowed */ + if (!is_instance && c_ulong != 0) + goto err; + + /* Write c_long into arg */ + interface = g_type_info_get_interface (arg_cache->type_info); + g_assert (g_base_info_get_type (interface) == GI_INFO_TYPE_FLAGS); + if (!gi_argument_from_c_long(arg, c_ulong, + g_enum_info_get_storage_type ((GIEnumInfo *)interface))) { + g_base_info_unref (interface); + return FALSE; + } + + g_base_info_unref (interface); + return TRUE; + +err: + PyErr_Format (PyExc_TypeError, "Expected a %s, but got %s", + iface_cache->type_name, Py_TYPE (py_arg)->tp_name); + return FALSE; + +} + +static PyObject * +_pygi_marshal_to_py_interface_enum (PyGIInvokeState *state, + PyGICallableCache *callable_cache, + PyGIArgCache *arg_cache, + GIArgument *arg, + gpointer *cleanup_data) +{ + PyObject *py_obj = NULL; + PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache; + GIBaseInfo *interface; + long c_long; + + interface = g_type_info_get_interface (arg_cache->type_info); + g_assert (g_base_info_get_type (interface) == GI_INFO_TYPE_ENUM); + + if (!gi_argument_to_c_long(arg, &c_long, + g_enum_info_get_storage_type ((GIEnumInfo *)interface))) { + return NULL; + } + + if (iface_cache->g_type == G_TYPE_NONE) { + py_obj = PyObject_CallFunction (iface_cache->py_type, "l", c_long); + } else { + py_obj = pyg_enum_from_gtype (iface_cache->g_type, (gint)c_long); + } + g_base_info_unref (interface); + return py_obj; +} + +static PyObject * +_pygi_marshal_to_py_interface_flags (PyGIInvokeState *state, + PyGICallableCache *callable_cache, + PyGIArgCache *arg_cache, + GIArgument *arg, + gpointer *cleanup_data) +{ + PyObject *py_obj = NULL; + PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache; + GIBaseInfo *interface; + long c_long; + + interface = g_type_info_get_interface (arg_cache->type_info); + g_assert (g_base_info_get_type (interface) == GI_INFO_TYPE_FLAGS); + + if (!gi_argument_to_c_long(arg, &c_long, + g_enum_info_get_storage_type ((GIEnumInfo *)interface))) { + g_base_info_unref (interface); + return NULL; + } + + g_base_info_unref (interface); + if (iface_cache->g_type == G_TYPE_NONE) { + /* An enum with a GType of None is an enum without GType */ + + PyObject *py_type = pygi_type_import_by_gi_info (iface_cache->interface_info); + PyObject *py_args = NULL; + + if (!py_type) + return NULL; + + py_args = PyTuple_New (1); + if (PyTuple_SetItem (py_args, 0, PyLong_FromLong (c_long)) != 0) { + Py_DECREF (py_args); + Py_DECREF (py_type); + return NULL; + } + + py_obj = PyObject_CallFunction (py_type, "l", c_long); + + Py_DECREF (py_args); + Py_DECREF (py_type); + } else { + py_obj = pyg_flags_from_gtype (iface_cache->g_type, (guint)c_long); + } + + return py_obj; +} + +static gboolean +pygi_arg_enum_setup_from_info (PyGIArgCache *arg_cache, + GITypeInfo *type_info, + GIArgInfo *arg_info, + GITransfer transfer, + PyGIDirection direction) +{ + if (direction & PYGI_DIRECTION_FROM_PYTHON) + arg_cache->from_py_marshaller = _pygi_marshal_from_py_interface_enum; + + if (direction & PYGI_DIRECTION_TO_PYTHON) + arg_cache->to_py_marshaller = _pygi_marshal_to_py_interface_enum; + + return TRUE; +} + + +PyGIArgCache * +pygi_arg_enum_new_from_info (GITypeInfo *type_info, + GIArgInfo *arg_info, + GITransfer transfer, + PyGIDirection direction, + GIInterfaceInfo *iface_info) +{ + gboolean res = FALSE; + PyGIArgCache *cache = NULL; + + cache = pygi_arg_interface_new_from_info (type_info, + arg_info, + transfer, + direction, + iface_info); + if (cache == NULL) + return NULL; + + res = pygi_arg_enum_setup_from_info (cache, + type_info, + arg_info, + transfer, + direction); + if (res) { + return cache; + } else { + pygi_arg_cache_free (cache); + return NULL; + } +} + +static gboolean +pygi_arg_flags_setup_from_info (PyGIArgCache *arg_cache, + GITypeInfo *type_info, + GIArgInfo *arg_info, + GITransfer transfer, + PyGIDirection direction) +{ + if (direction & PYGI_DIRECTION_FROM_PYTHON) + arg_cache->from_py_marshaller = _pygi_marshal_from_py_interface_flags; + + if (direction & PYGI_DIRECTION_TO_PYTHON) + arg_cache->to_py_marshaller = _pygi_marshal_to_py_interface_flags; + + return TRUE; +} + + +PyGIArgCache * +pygi_arg_flags_new_from_info (GITypeInfo *type_info, + GIArgInfo *arg_info, + GITransfer transfer, + PyGIDirection direction, + GIInterfaceInfo *iface_info) +{ + gboolean res = FALSE; + PyGIArgCache *cache = NULL; + + cache = pygi_arg_interface_new_from_info (type_info, + arg_info, + transfer, + direction, + iface_info); + if (cache == NULL) + return NULL; + + res = pygi_arg_flags_setup_from_info (cache, + type_info, + arg_info, + transfer, + direction); + if (res) { + return cache; + } else { + pygi_arg_cache_free (cache); + return NULL; + } +} diff --git a/gi/pygi-enum-marshal.h b/gi/pygi-enum-marshal.h new file mode 100644 index 0000000..2fdcbc4 --- /dev/null +++ b/gi/pygi-enum-marshal.h @@ -0,0 +1,42 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- + * vim: tabstop=4 shiftwidth=4 expandtab + * + * Copyright (C) 2014 Simon Feltman <sfeltman@gnome.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __PYGI_ENUM_MARSHAL_H__ +#define __PYGI_ENUM_MARSHAL_H__ + +#include <girepository.h> +#include "pygi-cache.h" + +G_BEGIN_DECLS + +PyGIArgCache *pygi_arg_enum_new_from_info (GITypeInfo *type_info, + GIArgInfo *arg_info, /* may be null */ + GITransfer transfer, + PyGIDirection direction, + GIInterfaceInfo *iface_info); + +PyGIArgCache *pygi_arg_flags_new_from_info (GITypeInfo *type_info, + GIArgInfo *arg_info, /* may be null */ + GITransfer transfer, + PyGIDirection direction, + GIInterfaceInfo *iface_info); + +G_END_DECLS + +#endif /*__PYGI_ENUM_MARSHAL_H__*/ diff --git a/gi/pygi-error.c b/gi/pygi-error.c new file mode 100644 index 0000000..de6b7c1 --- /dev/null +++ b/gi/pygi-error.c @@ -0,0 +1,374 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- + * vim: tabstop=4 shiftwidth=4 expandtab + * + * Copyright (C) 1998-2003 James Henstridge + * 2004-2008 Johan Dahlin + * Copyright (C) 2011 John (J5) Palmieri <johnp@redhat.com> + * Copyright (C) 2014 Simon Feltman <sfeltman@gnome.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <Python.h> +#include "pygi-error.h" +#include "pygi-type.h" +#include "pygi-util.h" +#include "pygi-basictype.h" + + +PyObject *PyGError = NULL; + +/** + * pygi_error_marshal_to_py: + * @error: a pointer to the GError. + * + * Checks to see if @error has been set. If @error has been set, then a + * GLib.GError Python exception object is returned (but not raised). + * If not error is set returns Py_None. + * + * Returns: a GLib.GError Python exception object, or Py_None, + * or NULL and sets an error if creating the exception object fails. + */ +PyObject * +pygi_error_marshal_to_py (GError **error) +{ + PyGILState_STATE state; + PyObject *exc_type; + PyObject *exc_instance; + const char *domain = NULL; + + g_return_val_if_fail(error != NULL, NULL); + + if (*error == NULL) + Py_RETURN_NONE; + + state = PyGILState_Ensure(); + + exc_type = PyGError; + + if ((*error)->domain) { + domain = g_quark_to_string ((*error)->domain); + } + + exc_instance = PyObject_CallFunction (exc_type, "ssi", + (*error)->message, + domain, + (*error)->code); + + PyGILState_Release(state); + + return exc_instance; +} + +/** + * pygi_error_check: + * @error: a pointer to the GError. + * + * Checks to see if the GError has been set. If the error has been + * set, then the glib.GError Python exception will be raised, and + * the GError cleared. + * + * Returns: True if an error was set. + */ +gboolean +pygi_error_check (GError **error) +{ + PyGILState_STATE state; + PyObject *exc_instance; + + g_return_val_if_fail(error != NULL, FALSE); + if (*error == NULL) + return FALSE; + + state = PyGILState_Ensure(); + + exc_instance = pygi_error_marshal_to_py (error); + if (exc_instance != NULL) { + PyErr_SetObject(PyGError, exc_instance); + Py_DECREF(exc_instance); + } else { + PyErr_Print (); + PyErr_SetString (PyExc_RuntimeError, "Converting the GError failed"); + } + g_clear_error(error); + + PyGILState_Release(state); + + return TRUE; +} + +/** + * pygi_error_marshal_from_py: + * @pyerr: A Python exception instance. + * @error: a standard GLib GError ** output parameter + * + * Converts from a Python implemented GError into a GError. + * + * Returns: TRUE if the conversion was successful, otherwise a Python exception + * is set and FALSE is returned. + */ +gboolean +pygi_error_marshal_from_py (PyObject *pyerr, GError **error) +{ + gint code; + gchar *message = NULL; + gchar *domain = NULL; + gboolean res = FALSE; + PyObject *py_message = NULL, + *py_domain = NULL, + *py_code = NULL; + + if (PyObject_IsInstance (pyerr, PyGError) != 1) { + PyErr_Format (PyExc_TypeError, "Must be GLib.Error, not %s", + Py_TYPE (pyerr)->tp_name); + return FALSE; + } + + py_message = PyObject_GetAttrString (pyerr, "message"); + if (!py_message) { + PyErr_SetString (PyExc_ValueError, + "GLib.Error instances must have a 'message' string attribute"); + goto cleanup; + } + + if (!pygi_utf8_from_py (py_message, &message)) + goto cleanup; + + py_domain = PyObject_GetAttrString (pyerr, "domain"); + if (!py_domain) { + PyErr_SetString (PyExc_ValueError, + "GLib.Error instances must have a 'domain' string attribute"); + goto cleanup; + } + + if (!pygi_utf8_from_py (py_domain, &domain)) + goto cleanup; + + py_code = PyObject_GetAttrString (pyerr, "code"); + if (!py_code) { + PyErr_SetString (PyExc_ValueError, + "GLib.Error instances must have a 'code' int attribute"); + goto cleanup; + } + + if (!pygi_gint_from_py (py_code, &code)) + goto cleanup; + + res = TRUE; + g_set_error_literal (error, + g_quark_from_string (domain), + code, + message); + +cleanup: + g_free (message); + g_free (domain); + Py_XDECREF (py_message); + Py_XDECREF (py_code); + Py_XDECREF (py_domain); + return res; +} + +/** + * pygi_gerror_exception_check: + * @error: a standard GLib GError ** output parameter + * + * Checks to see if a GError exception has been raised, and if so + * translates the python exception to a standard GLib GError. If the + * raised exception is not a GError then PyErr_Print() is called. + * + * Returns: 0 if no exception has been raised, -1 if it is a + * valid glib.GError, -2 otherwise. + */ +gboolean +pygi_gerror_exception_check (GError **error) +{ + int res = -1; + PyObject *type, *value, *traceback; + PyErr_Fetch(&type, &value, &traceback); + if (type == NULL) + return 0; + PyErr_NormalizeException(&type, &value, &traceback); + if (value == NULL) { + PyErr_Restore(type, value, traceback); + PyErr_Print(); + return -2; + } + if (!value || + !PyErr_GivenExceptionMatches(type, + (PyObject *) PyGError)) { + PyErr_Restore(type, value, traceback); + PyErr_Print(); + return -2; + } + Py_DECREF(type); + Py_XDECREF(traceback); + + if (!pygi_error_marshal_from_py (value, error)) { + PyErr_Print(); + res = -2; + } + + Py_DECREF(value); + return res; + +} + +static gboolean +_pygi_marshal_from_py_gerror (PyGIInvokeState *state, + PyGICallableCache *callable_cache, + PyGIArgCache *arg_cache, + PyObject *py_arg, + GIArgument *arg, + gpointer *cleanup_data) +{ + GError *error = NULL; + if (pygi_error_marshal_from_py (py_arg, &error)) { + arg->v_pointer = error; + *cleanup_data = error; + return TRUE; + } else { + return FALSE; + } +} + + +static void +_pygi_marshal_from_py_gerror_cleanup (PyGIInvokeState *state, + PyGIArgCache *arg_cache, + PyObject *py_arg, + gpointer data, + gboolean was_processed) +{ + if (was_processed) { + g_error_free ((GError *)data); + } +} + +static PyObject * +_pygi_marshal_to_py_gerror (PyGIInvokeState *state, + PyGICallableCache *callable_cache, + PyGIArgCache *arg_cache, + GIArgument *arg, + gpointer *cleanup_data) +{ + GError *error = arg->v_pointer; + PyObject *py_obj = NULL; + + py_obj = pygi_error_marshal_to_py (&error); + + if (arg_cache->transfer == GI_TRANSFER_EVERYTHING && error != NULL) { + g_error_free (error); + } + + return py_obj; +} + +static gboolean +pygi_arg_gerror_setup_from_info (PyGIArgCache *arg_cache, + GITypeInfo *type_info, + GIArgInfo *arg_info, + GITransfer transfer, + PyGIDirection direction) +{ + if (!pygi_arg_base_setup (arg_cache, type_info, arg_info, transfer, direction)) { + return FALSE; + } + + if (direction & PYGI_DIRECTION_FROM_PYTHON) { + arg_cache->from_py_marshaller = _pygi_marshal_from_py_gerror; + + /* Assign cleanup function if we manage memory after call completion. */ + if (arg_cache->transfer == GI_TRANSFER_NOTHING) { + arg_cache->from_py_cleanup = _pygi_marshal_from_py_gerror_cleanup; + } + } + + if (direction & PYGI_DIRECTION_TO_PYTHON) { + arg_cache->to_py_marshaller = _pygi_marshal_to_py_gerror; + arg_cache->meta_type = PYGI_META_ARG_TYPE_PARENT; + } + + return TRUE; +} + +PyGIArgCache * +pygi_arg_gerror_new_from_info (GITypeInfo *type_info, + GIArgInfo *arg_info, + GITransfer transfer, + PyGIDirection direction) +{ + gboolean res = FALSE; + PyGIArgCache *arg_cache; + + arg_cache = pygi_arg_cache_alloc (); + + res = pygi_arg_gerror_setup_from_info (arg_cache, + type_info, + arg_info, + transfer, + direction); + if (res) { + return arg_cache; + } else { + pygi_arg_cache_free (arg_cache); + return NULL; + } +} + +static PyObject * +pygerror_from_gvalue (const GValue *value) +{ + GError *gerror = (GError *) g_value_get_boxed (value); + PyObject *pyerr = pygi_error_marshal_to_py (&gerror); + return pyerr; +} + +static int +pygerror_to_gvalue (GValue *value, PyObject *pyerror) +{ + GError *gerror = NULL; + + if (pygi_error_marshal_from_py (pyerror, &gerror)) { + g_value_take_boxed (value, gerror); + return 0; + } + + return -1; +} + +/** + * Returns 0 on success, or -1 and sets an exception. + */ +int +pygi_error_register_types (PyObject *module) +{ + PyObject *error_module = PyImport_ImportModule ("gi._error"); + if (!error_module) { + return -1; + } + + /* Stash a reference to the Python implemented gi._error.GError. */ + PyGError = PyObject_GetAttrString (error_module, "GError"); + Py_DECREF (error_module); + if (PyGError == NULL) + return -1; + + pyg_register_gtype_custom (G_TYPE_ERROR, + pygerror_from_gvalue, + pygerror_to_gvalue); + + return 0; +} + diff --git a/gi/pygi-error.h b/gi/pygi-error.h new file mode 100644 index 0000000..3e6c414 --- /dev/null +++ b/gi/pygi-error.h @@ -0,0 +1,50 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- + * vim: tabstop=4 shiftwidth=4 expandtab + * + * Copyright (C) 1998-2003 James Henstridge + * 2004-2008 Johan Dahlin + * Copyright (C) 2014 Simon Feltman <sfeltman@gnome.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __PYGI_ERROR_H__ +#define __PYGI_ERROR_H__ + +#include <girepository.h> +#include "pygi-cache.h" + +G_BEGIN_DECLS + +extern PyObject *PyGError; + +gboolean pygi_error_check (GError **error); + +PyObject* pygi_error_marshal_to_py (GError **error); + +gboolean pygi_error_marshal_from_py (PyObject *pyerr, + GError **error); + +gboolean pygi_gerror_exception_check (GError **error); + +PyGIArgCache* pygi_arg_gerror_new_from_info (GITypeInfo *type_info, + GIArgInfo *arg_info, /* may be null */ + GITransfer transfer, + PyGIDirection direction); + +int pygi_error_register_types (PyObject *module); + +G_END_DECLS + +#endif /*__PYGI_ERROR_H__*/ diff --git a/gi/pygi-foreign-api.h b/gi/pygi-foreign-api.h new file mode 100644 index 0000000..9367518 --- /dev/null +++ b/gi/pygi-foreign-api.h @@ -0,0 +1,85 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- + * vim: tabstop=4 shiftwidth=4 expandtab + * + * Copyright (C) 2005-2009 Johan Dahlin <johan@gnome.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __PYGI_FOREIGN_API_H__ +#define __PYGI_FOREIGN_API_H__ + +#include <girepository.h> +#include <pygobject.h> + +typedef PyObject * (*PyGIArgOverrideToGIArgumentFunc) (PyObject *value, + GIInterfaceInfo *interface_info, + GITransfer transfer, + GIArgument *arg); +typedef PyObject * (*PyGIArgOverrideFromGIArgumentFunc) (GIInterfaceInfo *interface_info, + GITransfer transfer, + gpointer data); +typedef PyObject * (*PyGIArgOverrideReleaseFunc) (GITypeInfo *type_info, + gpointer struct_); + + +struct PyGI_API { + void (*register_foreign_struct) (const char* namespace_, + const char* name, + PyGIArgOverrideToGIArgumentFunc to_func, + PyGIArgOverrideFromGIArgumentFunc from_func, + PyGIArgOverrideReleaseFunc release_func); +}; + + +#ifndef _INSIDE_PYGOBJECT_ + +static struct PyGI_API *PyGI_API = NULL; + +static int +_pygi_import (void) +{ + if (PyGI_API != NULL) { + return 1; + } + PyGI_API = (struct PyGI_API*) PyCapsule_Import("gi._API", FALSE); + if (PyGI_API == NULL) { + return -1; + } + + return 0; +} + + +static inline PyObject * +pygi_register_foreign_struct (const char* namespace_, + const char* name, + PyGIArgOverrideToGIArgumentFunc to_func, + PyGIArgOverrideFromGIArgumentFunc from_func, + PyGIArgOverrideReleaseFunc release_func) +{ + if (_pygi_import() < 0) { + return NULL; + } + PyGI_API->register_foreign_struct(namespace_, + name, + to_func, + from_func, + release_func); + Py_RETURN_NONE; +} + +#endif /* _INSIDE_PYGOBJECT_ */ + +#endif /* __PYGI_FOREIGN_API_H__ */ diff --git a/gi/pygi-foreign-cairo.c b/gi/pygi-foreign-cairo.c index 3fe6a39..aa01157 100644 --- a/gi/pygi-foreign-cairo.c +++ b/gi/pygi-foreign-cairo.c @@ -21,20 +21,21 @@ * IN THE SOFTWARE. */ -#include <cairo.h> #include <Python.h> +#include <cairo.h> +#include <py3cairo.h> -#if PY_VERSION_HEX < 0x03000000 -#include <pycairo.h> -static Pycairo_CAPI_t *Pycairo_CAPI; -#else -#include <pycairo/py3cairo.h> -#endif - +#include <cairo-gobject.h> -#include "pygi-foreign.h" +/* Limit includes from PyGI to APIs which do not have link dependencies + * (pygobject.h and pygi-foreign-api.h) since _gi_cairo is built as a separate + * shared library that interacts with PyGI through a PyCapsule API at runtime. + */ +#include <pygi-foreign-api.h> -#include <pyglib-python-compat.h> +/* + * cairo_t marshaling + */ static PyObject * cairo_context_to_arg (PyObject *value, @@ -44,27 +45,37 @@ cairo_context_to_arg (PyObject *value, { cairo_t *cr; - g_assert (transfer == GI_TRANSFER_NOTHING); + if (!PyObject_TypeCheck (value, &PycairoContext_Type)) { + PyErr_SetString (PyExc_TypeError, "Expected cairo.Context"); + return NULL; + } cr = PycairoContext_GET (value); if (!cr) { return NULL; } + if (transfer != GI_TRANSFER_NOTHING) + cr = cairo_reference (cr); + arg->v_pointer = cr; Py_RETURN_NONE; } static PyObject * -cairo_context_from_arg (GIInterfaceInfo *interface_info, gpointer data) +cairo_context_from_arg (GIInterfaceInfo *interface_info, + GITransfer transfer, + gpointer data) { cairo_t *context = (cairo_t*) data; - cairo_reference (context); + if (transfer == GI_TRANSFER_NOTHING) + cairo_reference (context); return PycairoContext_FromContext (context, &PycairoContext_Type, NULL); } + static PyObject * cairo_context_release (GIBaseInfo *base_info, gpointer struct_) @@ -73,6 +84,43 @@ cairo_context_release (GIBaseInfo *base_info, Py_RETURN_NONE; } +static int +cairo_context_to_gvalue (GValue *value, PyObject *obj) +{ + cairo_t *cr; + + if (!PyObject_TypeCheck (obj, &PycairoContext_Type)) { + PyErr_SetString (PyExc_TypeError, "Expected cairo.Context"); + return -1; + } + + cr = PycairoContext_GET (obj); + if (!cr) { + return -1; + } + + /* PycairoContext_GET returns a borrowed reference, use set_boxed + * to add new ref to the context which will be managed by the GValue. */ + g_value_set_boxed (value, cr); + return 0; +} + +static PyObject * +cairo_context_from_gvalue (const GValue *value) +{ + /* PycairoContext_FromContext steals a ref, so we dup it out of the GValue. */ + cairo_t *cr = g_value_dup_boxed (value); + if (!cr) { + Py_RETURN_NONE; + } + + return PycairoContext_FromContext (cr, &PycairoContext_Type, NULL); +} + + +/* + * cairo_surface_t marshaling + */ static PyObject * cairo_surface_to_arg (PyObject *value, @@ -82,7 +130,10 @@ cairo_surface_to_arg (PyObject *value, { cairo_surface_t *surface; - g_assert (transfer == GI_TRANSFER_NOTHING); + if (!PyObject_TypeCheck (value, &PycairoSurface_Type)) { + PyErr_SetString (PyExc_TypeError, "Expected cairo.Surface"); + return NULL; + } surface = ( (PycairoSurface*) value)->surface; if (!surface) { @@ -90,16 +141,22 @@ cairo_surface_to_arg (PyObject *value, return NULL; } + if (transfer != GI_TRANSFER_NOTHING) + surface = cairo_surface_reference (surface); + arg->v_pointer = surface; Py_RETURN_NONE; } static PyObject * -cairo_surface_from_arg (GIInterfaceInfo *interface_info, gpointer data) +cairo_surface_from_arg (GIInterfaceInfo *interface_info, + GITransfer transfer, + gpointer data) { cairo_surface_t *surface = (cairo_surface_t*) data; - cairo_surface_reference (surface); + if (transfer == GI_TRANSFER_NOTHING) + cairo_surface_reference (surface); return PycairoSurface_FromSurface (surface, NULL); } @@ -112,6 +169,59 @@ cairo_surface_release (GIBaseInfo *base_info, Py_RETURN_NONE; } +static int +cairo_surface_to_gvalue (GValue *value, PyObject *obj) +{ + cairo_surface_t *surface; + + if (!PyObject_TypeCheck (obj, &PycairoSurface_Type)) { + PyErr_SetString (PyExc_TypeError, "Expected cairo.Surface"); + return -1; + } + + surface = ((PycairoSurface*) obj)->surface; + if (!surface) { + return -1; + } + + /* surface is a borrowed reference, use set_boxed + * to add new ref to the context which will be managed by the GValue. */ + g_value_set_boxed (value, surface); + return 0; +} + +static PyObject * +cairo_surface_from_gvalue (const GValue *value) +{ + /* PycairoSurface_FromSurface steals a ref, so we dup it out of the GValue. */ + cairo_surface_t *surface = g_value_dup_boxed (value); + if (!surface) { + Py_RETURN_NONE; + } + + return PycairoSurface_FromSurface (surface, NULL); +} + + +/* + * cairo_path_t marshaling + */ + +static cairo_path_t * +_cairo_path_copy (cairo_path_t *path) { + cairo_t *cr; + cairo_surface_t *surface; + cairo_path_t *copy; + + surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 0, 0); + cr = cairo_create (surface); + cairo_append_path (cr, path); + copy = cairo_copy_path (cr); + cairo_destroy (cr); + cairo_surface_destroy (surface); + + return copy; +} static PyObject * cairo_path_to_arg (PyObject *value, @@ -121,7 +231,10 @@ cairo_path_to_arg (PyObject *value, { cairo_path_t *path; - g_assert (transfer == GI_TRANSFER_NOTHING); + if (!PyObject_TypeCheck (value, &PycairoPath_Type)) { + PyErr_SetString (PyExc_TypeError, "Expected cairo.Path"); + return NULL; + } path = ( (PycairoPath*) value)->path; if (!path) { @@ -129,15 +242,25 @@ cairo_path_to_arg (PyObject *value, return NULL; } + if (transfer != GI_TRANSFER_NOTHING) + path = _cairo_path_copy (path); + arg->v_pointer = path; Py_RETURN_NONE; } static PyObject * -cairo_path_from_arg (GIInterfaceInfo *interface_info, gpointer data) +cairo_path_from_arg (GIInterfaceInfo *interface_info, + GITransfer transfer, + gpointer data) { cairo_path_t *path = (cairo_path_t*) data; + if (transfer == GI_TRANSFER_NOTHING) { + PyErr_SetString(PyExc_TypeError, "Unsupported annotation (transfer none) for cairo.Path return"); + return NULL; + } + return PycairoPath_FromPath (path); } @@ -149,6 +272,46 @@ cairo_path_release (GIBaseInfo *base_info, Py_RETURN_NONE; } + +/* + * cairo_font_face_t marshaling + */ + +static int +cairo_font_face_to_gvalue (GValue *value, PyObject *obj) +{ + cairo_font_face_t *font_face; + + if (!PyObject_TypeCheck (obj, &PycairoFontFace_Type)) { + PyErr_SetString (PyExc_TypeError, "Expected cairo.FontFace"); + return -1; + } + + font_face = ((PycairoFontFace*) obj)->font_face; + if (!font_face) { + return -1; + } + + g_value_set_boxed (value, font_face); + return 0; +} + +static PyObject * +cairo_font_face_from_gvalue (const GValue *value) +{ + cairo_font_face_t *font_face = g_value_dup_boxed (value); + if (!font_face) { + Py_RETURN_NONE; + } + + return PycairoFontFace_FromFontFace (font_face); +} + + +/* + * cairo_font_options_t marshaling + */ + static PyObject * cairo_font_options_to_arg (PyObject *value, GIInterfaceInfo *interface_info, @@ -157,7 +320,10 @@ cairo_font_options_to_arg (PyObject *value, { cairo_font_options_t *font_options; - g_assert (transfer == GI_TRANSFER_NOTHING); + if (!PyObject_TypeCheck (value, &PycairoFontOptions_Type)) { + PyErr_SetString (PyExc_TypeError, "Expected cairo.FontOptions"); + return NULL; + } font_options = ( (PycairoFontOptions*) value)->font_options; if (!font_options) { @@ -165,16 +331,24 @@ cairo_font_options_to_arg (PyObject *value, return NULL; } + if (transfer != GI_TRANSFER_NOTHING) + font_options = cairo_font_options_copy (font_options); + arg->v_pointer = font_options; Py_RETURN_NONE; } static PyObject * -cairo_font_options_from_arg (GIInterfaceInfo *interface_info, gpointer data) +cairo_font_options_from_arg (GIInterfaceInfo *interface_info, + GITransfer transfer, + gpointer data) { cairo_font_options_t *font_options = (cairo_font_options_t*) data; - return PycairoFontOptions_FromFontOptions (cairo_font_options_copy (font_options)); + if (transfer == GI_TRANSFER_NOTHING) + font_options = cairo_font_options_copy (font_options); + + return PycairoFontOptions_FromFontOptions (font_options); } static PyObject * @@ -185,17 +359,297 @@ cairo_font_options_release (GIBaseInfo *base_info, Py_RETURN_NONE; } -static PyMethodDef _gi_cairo_functions[] = { {0,} }; -PYGLIB_MODULE_START(_gi_cairo, "_gi_cairo") + +/* + * scaled_font_t marshaling + */ + +static int +cairo_scaled_font_to_gvalue (GValue *value, PyObject *obj) +{ + cairo_scaled_font_t *scaled_font; + + if (!PyObject_TypeCheck (obj, &PycairoScaledFont_Type)) { + PyErr_SetString (PyExc_TypeError, "Expected cairo.ScaledFont"); + return -1; + } + + scaled_font = ((PycairoScaledFont*) obj)->scaled_font; + if (!scaled_font) { + return -1; + } + + /* scaled_font is a borrowed reference, use set_boxed + * to add new ref to the context which will be managed by the GValue. */ + g_value_set_boxed (value, scaled_font); + return 0; +} + +static PyObject * +cairo_scaled_font_from_gvalue (const GValue *value) +{ + /* PycairoScaledFont_FromScaledFont steals a ref, so we dup it out of the GValue. */ + cairo_scaled_font_t *scaled_font = g_value_dup_boxed (value); + if (!scaled_font) { + Py_RETURN_NONE; + } + + return PycairoScaledFont_FromScaledFont (scaled_font); +} + + +/* + * cairo_pattern_t marshaling + */ + +static PyObject * +cairo_pattern_to_arg (PyObject *value, + GIInterfaceInfo *interface_info, + GITransfer transfer, + GIArgument *arg) +{ + cairo_pattern_t *pattern; + + if (!PyObject_TypeCheck (value, &PycairoPattern_Type)) { + PyErr_SetString (PyExc_TypeError, "Expected cairo.Pattern"); + return NULL; + } + + pattern = ((PycairoPattern*) value)->pattern; + if (!pattern) { + PyErr_SetString (PyExc_ValueError, "Pattern instance wrapping a NULL pattern"); + return NULL; + } + + if (transfer != GI_TRANSFER_NOTHING) + pattern = cairo_pattern_reference (pattern); + + arg->v_pointer = pattern; + Py_RETURN_NONE; +} + +static PyObject * +cairo_pattern_from_arg (GIInterfaceInfo *interface_info, + GITransfer transfer, + gpointer data) +{ + cairo_pattern_t *pattern = (cairo_pattern_t*) data; + + if (transfer == GI_TRANSFER_NOTHING) + pattern = cairo_pattern_reference (pattern); + + return PycairoPattern_FromPattern (pattern, NULL); +} + +static PyObject * +cairo_pattern_release (GIBaseInfo *base_info, + gpointer struct_) +{ + cairo_pattern_destroy ( (cairo_pattern_t*) struct_); + Py_RETURN_NONE; +} + +static int +cairo_pattern_to_gvalue (GValue *value, PyObject *obj) +{ + cairo_pattern_t *pattern; + + if (!PyObject_TypeCheck (obj, &PycairoPattern_Type)) { + PyErr_SetString (PyExc_TypeError, "Expected cairo.Pattern"); + return -1; + } + + pattern = ((PycairoPattern*) obj)->pattern; + if (!pattern) { + return -1; + } + + /* pattern is a borrowed reference, use set_boxed + * to add new ref to the context which will be managed by the GValue. */ + g_value_set_boxed (value, pattern); + return 0; +} + +static PyObject * +cairo_pattern_from_gvalue (const GValue *value) { -#if PY_VERSION_HEX < 0x03000000 - Pycairo_IMPORT; + /* PycairoPattern_FromPattern steals a ref, so we dup it out of the GValue. */ + cairo_pattern_t *pattern = g_value_dup_boxed (value); + if (!pattern) { + Py_RETURN_NONE; + } + + return PycairoPattern_FromPattern (pattern, NULL); +} + +static PyObject * +cairo_region_to_arg (PyObject *value, + GIInterfaceInfo *interface_info, + GITransfer transfer, + GIArgument *arg) +{ + cairo_region_t *region; + + if (!PyObject_TypeCheck (value, &PycairoRegion_Type)) { + PyErr_SetString (PyExc_TypeError, "Expected cairo.Region"); + return NULL; + } + + region = ( (PycairoRegion*) value)->region; + if (!region) { + PyErr_SetString (PyExc_ValueError, "Region instance wrapping a NULL region"); + return NULL; + } + + if (transfer != GI_TRANSFER_NOTHING) + region = cairo_region_copy (region); + + arg->v_pointer = region; + Py_RETURN_NONE; +} + +static PyObject * +cairo_region_from_arg (GIInterfaceInfo *interface_info, + GITransfer transfer, + gpointer data) +{ + cairo_region_t *region = (cairo_region_t*) data; + + if (transfer == GI_TRANSFER_NOTHING) + cairo_region_reference (region); + + return PycairoRegion_FromRegion (region); +} + +static PyObject * +cairo_region_release (GIBaseInfo *base_info, + gpointer struct_) +{ + cairo_region_destroy ( (cairo_region_t*) struct_); + Py_RETURN_NONE; +} + +static PyObject * +cairo_matrix_from_arg (GIInterfaceInfo *interface_info, + GITransfer transfer, + gpointer data) +{ + cairo_matrix_t *matrix = (cairo_matrix_t*) data; + + if (transfer != GI_TRANSFER_NOTHING) { + PyErr_SetString(PyExc_TypeError, "Unsupported annotation (transfer full) for cairo.Matrix"); + return NULL; + } + + if (matrix == NULL) { + /* NULL in case of caller-allocates */ + cairo_matrix_t temp = {0}; + return PycairoMatrix_FromMatrix (&temp); + } + + return PycairoMatrix_FromMatrix (matrix); +} + +static PyObject * +cairo_matrix_to_arg (PyObject *value, + GIInterfaceInfo *interface_info, + GITransfer transfer, + GIArgument *arg) +{ + cairo_matrix_t *matrix; + + if (!PyObject_TypeCheck (value, &PycairoMatrix_Type)) { + PyErr_SetString (PyExc_TypeError, "Expected cairo.Matrix"); + return NULL; + } + + matrix = &(( (PycairoMatrix*) value)->matrix); + + arg->v_pointer = matrix; + Py_RETURN_NONE; +} + +static PyObject * +cairo_matrix_release (GIBaseInfo *base_info, + gpointer struct_) +{ + Py_RETURN_NONE; +} + +static int +cairo_matrix_to_gvalue (GValue *value, PyObject *obj) +{ + cairo_matrix_t *matrix; + + if (!PyObject_TypeCheck (obj, &PycairoMatrix_Type)) { + PyErr_SetString (PyExc_TypeError, "Expected cairo.Matrix"); + return -1; + } + + matrix = &(( (PycairoMatrix*) obj)->matrix); + if (!matrix) { + return -1; + } + + g_value_set_boxed (value, matrix); + return 0; +} + +static PyObject * +cairo_matrix_from_gvalue (const GValue *value) +{ + cairo_matrix_t *matrix = g_value_get_boxed(value); + if (!matrix) { + Py_RETURN_NONE; + } + + return PycairoMatrix_FromMatrix (matrix); +} + +#ifdef __GNUC__ +#define PYGI_MODINIT_FUNC __attribute__((visibility("default"))) PyMODINIT_FUNC #else - import_cairo(); +#define PYGI_MODINIT_FUNC PyMODINIT_FUNC #endif +static PyMethodDef _gi_cairo_functions[] = { {0,} }; + +static struct PyModuleDef __gi_cairomodule = { + PyModuleDef_HEAD_INIT, + "_gi_cairo", + NULL, + -1, + _gi_cairo_functions, + NULL, + NULL, + NULL, + NULL +}; + +PYGI_MODINIT_FUNC PyInit__gi_cairo (void); + +PYGI_MODINIT_FUNC PyInit__gi_cairo (void) +{ + PyObject *module; + module = PyModule_Create (&__gi_cairomodule); + + PyObject *gobject_mod; + + import_cairo(); + if (Pycairo_CAPI == NULL) - return PYGLIB_MODULE_ERROR_RETURN; + return NULL; + + gobject_mod = pygobject_init (3, 13, 2); + if (gobject_mod == NULL) + return NULL; + Py_DECREF (gobject_mod); + + pygi_register_foreign_struct ("cairo", + "Matrix", + cairo_matrix_to_arg, + cairo_matrix_from_arg, + cairo_matrix_release); pygi_register_foreign_struct ("cairo", "Context", @@ -220,5 +674,42 @@ PYGLIB_MODULE_START(_gi_cairo, "_gi_cairo") cairo_font_options_to_arg, cairo_font_options_from_arg, cairo_font_options_release); -} -PYGLIB_MODULE_END; + + pygi_register_foreign_struct ("cairo", + "Pattern", + cairo_pattern_to_arg, + cairo_pattern_from_arg, + cairo_pattern_release); + + pygi_register_foreign_struct ("cairo", + "Region", + cairo_region_to_arg, + cairo_region_from_arg, + cairo_region_release); + + pyg_register_gtype_custom (CAIRO_GOBJECT_TYPE_MATRIX, + cairo_matrix_from_gvalue, + cairo_matrix_to_gvalue); + + pyg_register_gtype_custom (CAIRO_GOBJECT_TYPE_CONTEXT, + cairo_context_from_gvalue, + cairo_context_to_gvalue); + + pyg_register_gtype_custom (CAIRO_GOBJECT_TYPE_SURFACE, + cairo_surface_from_gvalue, + cairo_surface_to_gvalue); + + pyg_register_gtype_custom (CAIRO_GOBJECT_TYPE_FONT_FACE, + cairo_font_face_from_gvalue, + cairo_font_face_to_gvalue); + + pyg_register_gtype_custom (CAIRO_GOBJECT_TYPE_SCALED_FONT, + cairo_scaled_font_from_gvalue, + cairo_scaled_font_to_gvalue); + + pyg_register_gtype_custom (CAIRO_GOBJECT_TYPE_PATTERN, + cairo_pattern_from_gvalue, + cairo_pattern_to_gvalue); + + return module; +}
\ No newline at end of file diff --git a/gi/pygi-foreign.c b/gi/pygi-foreign.c index 7537399..80a19f7 100644 --- a/gi/pygi-foreign.c +++ b/gi/pygi-foreign.c @@ -22,11 +22,9 @@ * IN THE SOFTWARE. */ -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif +#include <config.h> -#include "pygobject.h" +#include "pygobject-internal.h" #include "pygi-foreign.h" #include <girepository.h> @@ -50,7 +48,7 @@ init_foreign_structs (void) static PyGIForeignStruct * do_lookup (const gchar *namespace, const gchar *name) { - gint i; + guint i; for (i = 0; i < foreign_structs->len; i++) { PyGIForeignStruct *foreign_struct = \ g_ptr_array_index (foreign_structs, i); @@ -63,24 +61,24 @@ do_lookup (const gchar *namespace, const gchar *name) return NULL; } +static PyObject * +pygi_struct_foreign_load_module (const char *namespace) +{ + gchar *module_name = g_strconcat ("gi._gi_", namespace, NULL); + PyObject *module = PyImport_ImportModule (module_name); + g_free (module_name); + return module; +} + static PyGIForeignStruct * -pygi_struct_foreign_lookup (GIBaseInfo *base_info) +pygi_struct_foreign_lookup_by_name (const char *namespace, const char *name) { PyGIForeignStruct *result; - const gchar *namespace = g_base_info_get_namespace (base_info); - const gchar *name = g_base_info_get_name (base_info); - - if (foreign_structs == NULL) { - init_foreign_structs (); - } result = do_lookup (namespace, name); if (result == NULL) { - gchar *module_name = g_strconcat ("gi._gi_", namespace, NULL); - PyObject *module = PyImport_ImportModule (module_name); - - g_free (module_name); + PyObject *module = pygi_struct_foreign_load_module (namespace); if (module == NULL) PyErr_Clear (); @@ -92,7 +90,7 @@ pygi_struct_foreign_lookup (GIBaseInfo *base_info) if (result == NULL) { PyErr_Format (PyExc_TypeError, - "Couldn't find conversion for foreign struct '%s.%s'", + "Couldn't find foreign struct converter for '%s.%s'", namespace, name); } @@ -100,6 +98,15 @@ pygi_struct_foreign_lookup (GIBaseInfo *base_info) return result; } +static PyGIForeignStruct * +pygi_struct_foreign_lookup (GIBaseInfo *base_info) +{ + const gchar *namespace = g_base_info_get_namespace (base_info); + const gchar *name = g_base_info_get_name (base_info); + + return pygi_struct_foreign_lookup_by_name (namespace, name); +} + PyObject * pygi_struct_foreign_convert_to_g_argument (PyObject *value, GIInterfaceInfo *interface_info, @@ -123,6 +130,7 @@ pygi_struct_foreign_convert_to_g_argument (PyObject *value, PyObject * pygi_struct_foreign_convert_from_g_argument (GIInterfaceInfo *interface_info, + GITransfer transfer, GIArgument *arg) { GIBaseInfo *base_info = (GIBaseInfo *) interface_info; @@ -131,7 +139,7 @@ pygi_struct_foreign_convert_from_g_argument (GIInterfaceInfo *interface_info, if (foreign_struct == NULL) return NULL; - return foreign_struct->from_func (interface_info, arg); + return foreign_struct->from_func (interface_info, transfer, arg); } PyObject * @@ -150,11 +158,11 @@ pygi_struct_foreign_release (GIBaseInfo *base_info, } void -pygi_register_foreign_struct_real (const char* namespace_, - const char* name, - PyGIArgOverrideToGIArgumentFunc to_func, - PyGIArgOverrideFromGIArgumentFunc from_func, - PyGIArgOverrideReleaseFunc release_func) +pygi_register_foreign_struct (const char* namespace_, + const char* name, + PyGIArgOverrideToGIArgumentFunc to_func, + PyGIArgOverrideFromGIArgumentFunc from_func, + PyGIArgOverrideReleaseFunc release_func) { PyGIForeignStruct *new_struct = g_slice_new (PyGIForeignStruct); new_struct->namespace = namespace_; @@ -165,3 +173,63 @@ pygi_register_foreign_struct_real (const char* namespace_, g_ptr_array_add (foreign_structs, new_struct); } + +PyObject * +pygi_require_foreign (PyObject *self, PyObject *args, PyObject *kwargs) +{ + static char *kwlist[] = { "namespace", "symbol", NULL }; + const char *namespace = NULL; + const char *symbol = NULL; + + if (!PyArg_ParseTupleAndKeywords (args, kwargs, + "s|z:require_foreign", + kwlist, &namespace, &symbol)) { + return NULL; + } + + if (symbol) { + PyGIForeignStruct *foreign; + foreign = pygi_struct_foreign_lookup_by_name (namespace, symbol); + if (foreign == NULL) { + return NULL; + } + } else { + PyObject *module = pygi_struct_foreign_load_module (namespace); + if (module) { + Py_DECREF (module); + } else { + return NULL; + } + } + + Py_RETURN_NONE; +} + +/** + * Returns 0 on success, or -1 and sets an exception. + */ +int +pygi_foreign_init (void) +{ + if (foreign_structs == NULL) { + init_foreign_structs (); + } + + return 0; +} + + +PyObject *pygi_register_foreign (PyObject *self, PyObject *args) +{ + /* We need to try loading the foreign modules upfront so the GType + * converters are registered: + * https://gitlab.gnome.org/GNOME/pygobject/issues/260 + */ + PyObject *mod = pygi_struct_foreign_load_module ("cairo"); + if (mod == NULL) + PyErr_Clear (); + else + Py_DECREF (mod); + + Py_RETURN_NONE; +} diff --git a/gi/pygi-foreign.h b/gi/pygi-foreign.h index dd5f896..d4c50dd 100644 --- a/gi/pygi-foreign.h +++ b/gi/pygi-foreign.h @@ -26,23 +26,30 @@ #define __PYGI_FOREIGN_H__ #include <Python.h> -#include <girepository.h> - -#include "pygi.h" +#include "pygi-foreign-api.h" PyObject *pygi_struct_foreign_convert_to_g_argument (PyObject *value, GIInterfaceInfo *interface_info, GITransfer transfer, GIArgument *arg); PyObject *pygi_struct_foreign_convert_from_g_argument (GIInterfaceInfo *interface_info, + GITransfer transfer, GIArgument *arg); PyObject *pygi_struct_foreign_release (GITypeInfo *type_info, gpointer struct_); -void pygi_register_foreign_struct_real (const char* namespace_, - const char* name, - PyGIArgOverrideToGIArgumentFunc to_func, - PyGIArgOverrideFromGIArgumentFunc from_func, - PyGIArgOverrideReleaseFunc release_func); +void pygi_register_foreign_struct (const char* namespace_, + const char* name, + PyGIArgOverrideToGIArgumentFunc to_func, + PyGIArgOverrideFromGIArgumentFunc from_func, + PyGIArgOverrideReleaseFunc release_func); + +PyObject *pygi_require_foreign (PyObject *self, + PyObject *args, + PyObject *kwargs); + +int pygi_foreign_init (void); + +PyObject *pygi_register_foreign (PyObject *self, PyObject *args); #endif /* __PYGI_FOREIGN_H__ */ diff --git a/gi/pygi-hashtable.c b/gi/pygi-hashtable.c new file mode 100644 index 0000000..26d5f61 --- /dev/null +++ b/gi/pygi-hashtable.c @@ -0,0 +1,420 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- + * vim: tabstop=4 shiftwidth=4 expandtab + * + * Copyright (C) 2011 John (J5) Palmieri <johnp@redhat.com> + * Copyright (C) 2014 Simon Feltman <sfeltman@gnome.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <Python.h> +#include "pygi-hashtable.h" +#include "pygi-argument.h" +#include "pygi-util.h" + +typedef struct _PyGIHashCache +{ + PyGIArgCache arg_cache; + PyGIArgCache *key_cache; + PyGIArgCache *value_cache; +} PyGIHashCache; + + +static void +_hash_cache_free_func (PyGIHashCache *cache) +{ + if (cache != NULL) { + pygi_arg_cache_free (cache->key_cache); + pygi_arg_cache_free (cache->value_cache); + g_slice_free (PyGIHashCache, cache); + } +} + +static gboolean +_pygi_marshal_from_py_ghash (PyGIInvokeState *state, + PyGICallableCache *callable_cache, + PyGIArgCache *arg_cache, + PyObject *py_arg, + GIArgument *arg, + gpointer *cleanup_data) +{ + PyGIMarshalFromPyFunc key_from_py_marshaller; + PyGIMarshalFromPyFunc value_from_py_marshaller; + + int i; + Py_ssize_t length; + PyObject *py_keys, *py_values; + + GHashFunc hash_func; + GEqualFunc equal_func; + + GHashTable *hash_ = NULL; + PyGIHashCache *hash_cache = (PyGIHashCache *)arg_cache; + + if (py_arg == Py_None) { + arg->v_pointer = NULL; + return TRUE; + } + + py_keys = PyMapping_Keys (py_arg); + if (py_keys == NULL) { + PyErr_Format (PyExc_TypeError, "Must be mapping, not %s", + Py_TYPE (py_arg)->tp_name); + return FALSE; + } + + length = PyMapping_Length (py_arg); + if (length < 0) { + Py_DECREF (py_keys); + return FALSE; + } + + py_values = PyMapping_Values (py_arg); + if (py_values == NULL) { + Py_DECREF (py_keys); + return FALSE; + } + + key_from_py_marshaller = hash_cache->key_cache->from_py_marshaller; + value_from_py_marshaller = hash_cache->value_cache->from_py_marshaller; + + switch (hash_cache->key_cache->type_tag) { + case GI_TYPE_TAG_UTF8: + case GI_TYPE_TAG_FILENAME: + hash_func = g_str_hash; + equal_func = g_str_equal; + break; + default: + hash_func = NULL; + equal_func = NULL; + } + + hash_ = g_hash_table_new (hash_func, equal_func); + if (hash_ == NULL) { + PyErr_NoMemory (); + Py_DECREF (py_keys); + Py_DECREF (py_values); + return FALSE; + } + + for (i = 0; i < length; i++) { + GIArgument key, value; + gpointer key_cleanup_data = NULL; + gpointer value_cleanup_data = NULL; + PyObject *py_key = PyList_GET_ITEM (py_keys, i); + PyObject *py_value = PyList_GET_ITEM (py_values, i); + if (py_key == NULL || py_value == NULL) + goto err; + + if (!key_from_py_marshaller ( state, + callable_cache, + hash_cache->key_cache, + py_key, + &key, + &key_cleanup_data)) + goto err; + + if (!value_from_py_marshaller ( state, + callable_cache, + hash_cache->value_cache, + py_value, + &value, + &value_cleanup_data)) + goto err; + + g_hash_table_insert (hash_, + _pygi_arg_to_hash_pointer (&key, hash_cache->key_cache->type_info), + _pygi_arg_to_hash_pointer (&value, hash_cache->value_cache->type_info)); + continue; +err: + /* FIXME: cleanup hash keys and values */ + Py_DECREF (py_keys); + Py_DECREF (py_values); + g_hash_table_unref (hash_); + _PyGI_ERROR_PREFIX ("Item %i: ", i); + return FALSE; + } + + arg->v_pointer = hash_; + + if (arg_cache->transfer == GI_TRANSFER_NOTHING) { + /* Free everything in cleanup. */ + *cleanup_data = arg->v_pointer; + } else if (arg_cache->transfer == GI_TRANSFER_CONTAINER) { + /* Make a shallow copy so we can free the elements later in cleanup + * because it is possible invoke will free the list before our cleanup. */ + *cleanup_data = g_hash_table_ref (arg->v_pointer); + } else { /* GI_TRANSFER_EVERYTHING */ + /* No cleanup, everything is given to the callee. + * Note that the keys and values will leak for transfer everything because + * we do not use g_hash_table_new_full and set key/value_destroy_func. */ + *cleanup_data = NULL; + } + + return TRUE; +} + +static void +_pygi_marshal_cleanup_from_py_ghash (PyGIInvokeState *state, + PyGIArgCache *arg_cache, + PyObject *py_arg, + gpointer data, + gboolean was_processed) +{ + if (data == NULL) + return; + + if (was_processed) { + GHashTable *hash_; + PyGIHashCache *hash_cache = (PyGIHashCache *)arg_cache; + + hash_ = (GHashTable *)data; + + /* clean up keys and values first */ + if (hash_cache->key_cache->from_py_cleanup != NULL || + hash_cache->value_cache->from_py_cleanup != NULL) { + GHashTableIter hiter; + gpointer key; + gpointer value; + + PyGIMarshalCleanupFunc key_cleanup_func = + hash_cache->key_cache->from_py_cleanup; + PyGIMarshalCleanupFunc value_cleanup_func = + hash_cache->value_cache->from_py_cleanup; + + g_hash_table_iter_init (&hiter, hash_); + while (g_hash_table_iter_next (&hiter, &key, &value)) { + if (key != NULL && key_cleanup_func != NULL) + key_cleanup_func (state, + hash_cache->key_cache, + NULL, + key, + TRUE); + if (value != NULL && value_cleanup_func != NULL) + value_cleanup_func (state, + hash_cache->value_cache, + NULL, + value, + TRUE); + } + } + + g_hash_table_unref (hash_); + } +} + +static PyObject * +_pygi_marshal_to_py_ghash (PyGIInvokeState *state, + PyGICallableCache *callable_cache, + PyGIArgCache *arg_cache, + GIArgument *arg, + gpointer *cleanup_data) +{ + GHashTable *hash_; + GHashTableIter hash_table_iter; + + PyGIMarshalToPyFunc key_to_py_marshaller; + PyGIMarshalToPyFunc value_to_py_marshaller; + + PyGIArgCache *key_arg_cache; + PyGIArgCache *value_arg_cache; + PyGIHashCache *hash_cache = (PyGIHashCache *)arg_cache; + + GIArgument key_arg; + GIArgument value_arg; + + PyObject *py_obj = NULL; + + hash_ = arg->v_pointer; + + if (hash_ == NULL) { + py_obj = Py_None; + Py_INCREF (py_obj); + return py_obj; + } + + py_obj = PyDict_New (); + if (py_obj == NULL) + return NULL; + + key_arg_cache = hash_cache->key_cache; + key_to_py_marshaller = key_arg_cache->to_py_marshaller; + + value_arg_cache = hash_cache->value_cache; + value_to_py_marshaller = value_arg_cache->to_py_marshaller; + + g_hash_table_iter_init (&hash_table_iter, hash_); + while (g_hash_table_iter_next (&hash_table_iter, + &key_arg.v_pointer, + &value_arg.v_pointer)) { + gpointer key_cleanup_data = NULL; + gpointer value_cleanup_data = NULL; + PyObject *py_key; + PyObject *py_value; + int retval; + + + _pygi_hash_pointer_to_arg (&key_arg, hash_cache->key_cache->type_info); + py_key = key_to_py_marshaller ( state, + callable_cache, + key_arg_cache, + &key_arg, + &key_cleanup_data); + + if (py_key == NULL) { + Py_CLEAR (py_obj); + return NULL; + } + + _pygi_hash_pointer_to_arg (&value_arg, hash_cache->value_cache->type_info); + py_value = value_to_py_marshaller ( state, + callable_cache, + value_arg_cache, + &value_arg, + &value_cleanup_data); + + if (py_value == NULL) { + Py_CLEAR (py_obj); + Py_DECREF(py_key); + return NULL; + } + + retval = PyDict_SetItem (py_obj, py_key, py_value); + + Py_DECREF (py_key); + Py_DECREF (py_value); + + if (retval < 0) { + Py_CLEAR (py_obj); + return NULL; + } + } + + return py_obj; +} + +static void +_pygi_marshal_cleanup_to_py_ghash (PyGIInvokeState *state, + PyGIArgCache *arg_cache, + gpointer cleanup_data, + gpointer data, + gboolean was_processed) +{ + if (data == NULL) + return; + + /* assume hashtable has boxed key and value */ + if (arg_cache->transfer == GI_TRANSFER_EVERYTHING || arg_cache->transfer == GI_TRANSFER_CONTAINER) + g_hash_table_unref ( (GHashTable *)data); +} + +static void +_arg_cache_from_py_ghash_setup (PyGIArgCache *arg_cache) +{ + arg_cache->from_py_marshaller = _pygi_marshal_from_py_ghash; + arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_ghash; +} + +static void +_arg_cache_to_py_ghash_setup (PyGIArgCache *arg_cache) +{ + arg_cache->to_py_marshaller = _pygi_marshal_to_py_ghash; + arg_cache->to_py_cleanup = _pygi_marshal_cleanup_to_py_ghash; +} + +static gboolean +pygi_arg_hash_table_setup_from_info (PyGIHashCache *hc, + GITypeInfo *type_info, + GIArgInfo *arg_info, + GITransfer transfer, + PyGIDirection direction, + PyGICallableCache *callable_cache) +{ + GITypeInfo *key_type_info; + GITypeInfo *value_type_info; + GITransfer item_transfer; + + if (!pygi_arg_base_setup ((PyGIArgCache *)hc, type_info, arg_info, transfer, direction)) + return FALSE; + + ( (PyGIArgCache *)hc)->destroy_notify = (GDestroyNotify)_hash_cache_free_func; + key_type_info = g_type_info_get_param_type (type_info, 0); + value_type_info = g_type_info_get_param_type (type_info, 1); + + item_transfer = + transfer == GI_TRANSFER_CONTAINER ? GI_TRANSFER_NOTHING : transfer; + + hc->key_cache = pygi_arg_cache_new (key_type_info, + NULL, + item_transfer, + direction, + callable_cache, + 0, 0); + + if (hc->key_cache == NULL) { + return FALSE; + } + + hc->value_cache = pygi_arg_cache_new (value_type_info, + NULL, + item_transfer, + direction, + callable_cache, + 0, 0); + + if (hc->value_cache == NULL) { + return FALSE; + } + + g_base_info_unref( (GIBaseInfo *)key_type_info); + g_base_info_unref( (GIBaseInfo *)value_type_info); + + if (direction & PYGI_DIRECTION_FROM_PYTHON) { + _arg_cache_from_py_ghash_setup ((PyGIArgCache *)hc); + } + + if (direction & PYGI_DIRECTION_TO_PYTHON) { + _arg_cache_to_py_ghash_setup ((PyGIArgCache *)hc); + } + + return TRUE; +} + +PyGIArgCache * +pygi_arg_hash_table_new_from_info (GITypeInfo *type_info, + GIArgInfo *arg_info, + GITransfer transfer, + PyGIDirection direction, + PyGICallableCache *callable_cache) +{ + gboolean res = FALSE; + PyGIHashCache *hc = NULL; + + hc = g_slice_new0 (PyGIHashCache); + if (hc == NULL) + return NULL; + + res = pygi_arg_hash_table_setup_from_info (hc, + type_info, + arg_info, + transfer, + direction, + callable_cache); + if (res) { + return (PyGIArgCache *)hc; + } else { + pygi_arg_cache_free ((PyGIArgCache *)hc); + return NULL; + } +} diff --git a/gi/pygi-hashtable.h b/gi/pygi-hashtable.h new file mode 100644 index 0000000..74cd04f --- /dev/null +++ b/gi/pygi-hashtable.h @@ -0,0 +1,36 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- + * vim: tabstop=4 shiftwidth=4 expandtab + * + * Copyright (C) 2013 Simon Feltman <sfeltman@gnome.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __PYGI_HASHTABLE_H__ +#define __PYGI_HASHTABLE_H__ + +#include "pygi-cache.h" +#include <girepository.h> + +G_BEGIN_DECLS + +PyGIArgCache *pygi_arg_hash_table_new_from_info (GITypeInfo *type_info, + GIArgInfo *arg_info, /* may be null */ + GITransfer transfer, + PyGIDirection direction, + PyGICallableCache *callable_cache); + +G_END_DECLS + +#endif /*__PYGI_HASHTABLE_H__*/ diff --git a/gi/pygi-info.c b/gi/pygi-info.c index 7164ff9..08c76db 100644 --- a/gi/pygi-info.c +++ b/gi/pygi-info.c @@ -2,6 +2,7 @@ * vim: tabstop=4 shiftwidth=4 expandtab * * Copyright (C) 2005-2009 Johan Dahlin <johan@gnome.org> + * Copyright (C) 2013 Simon Feltman <sfeltman@gnome.org> * * pygi-info.c: GI.*Info wrappers. * @@ -16,17 +17,17 @@ * 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 + * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ -#include "pygi-private.h" +#include "pygi-info.h" #include "pygi-cache.h" - -#include <pygobject.h> -#include <pyglib-python-compat.h> - +#include "pygi-invoke.h" +#include "pygi-type.h" +#include "pygi-argument.h" +#include "pygi-util.h" +#include "pygi-basictype.h" +#include "pygi-type.h" /* _generate_doc_string * @@ -53,9 +54,119 @@ _generate_doc_string(PyGIBaseInfo *self) return PyObject_CallFunctionObjArgs (_py_generate_doc_string, self, NULL); } +static PyObject * +_get_info_string (PyGIBaseInfo *self, + const gchar* (*get_info_string)(GIBaseInfo*)) +{ + const gchar *value = get_info_string ((GIBaseInfo*)self->info); + if (value == NULL) { + Py_RETURN_NONE; + } + return pygi_utf8_to_py (value); +} + +static PyObject * +_get_child_info (PyGIBaseInfo *self, + GIBaseInfo* (*get_child_info)(GIBaseInfo*)) +{ + GIBaseInfo *info; + PyObject *py_info; + + info = get_child_info ((GIBaseInfo*)self->info); + if (info == NULL) { + Py_RETURN_NONE; + } + + py_info = _pygi_info_new (info); + g_base_info_unref (info); + return py_info; +} + + +static PyObject * +_get_child_info_by_name (PyGIBaseInfo *self, PyObject *py_name, + GIBaseInfo* (*get_child_info_by_name)(GIBaseInfo*, const gchar*)) +{ + GIBaseInfo *info; + PyObject *py_info; + char *name; + + if (!pygi_utf8_from_py (py_name, &name)) + return NULL; + + info = get_child_info_by_name ((GIObjectInfo*)self->info, name); + g_free (name); + if (info == NULL) { + Py_RETURN_NONE; + } + + py_info = _pygi_info_new (info); + g_base_info_unref (info); + return py_info; +} + + +/* _make_infos_tuple + * + * Build a tuple from the common API pattern in GI of having a + * function which returns a count and an indexed GIBaseInfo + * in the range of 0 to count; + */ +static PyObject * +_make_infos_tuple (PyGIBaseInfo *self, + gint (*get_n_infos)(GIBaseInfo*), + GIBaseInfo* (*get_info)(GIBaseInfo*, gint)) +{ + gint n_infos; + PyObject *infos; + gint i; + + n_infos = get_n_infos ( (GIBaseInfo *) self->info); + + infos = PyTuple_New (n_infos); + if (infos == NULL) { + return NULL; + } + + for (i = 0; i < n_infos; i++) { + GIBaseInfo *info; + PyObject *py_info; + + info = (GIBaseInfo *) get_info (self->info, i); + g_assert (info != NULL); + + py_info = _pygi_info_new (info); + + g_base_info_unref (info); + + if (py_info == NULL) { + Py_CLEAR (infos); + break; + } + + PyTuple_SET_ITEM (infos, i, py_info); + } + + return infos; +} + /* BaseInfo */ +/* We need to be careful about calling g_base_info_get_name because + * calling it with a GI_INFO_TYPE_TYPE will crash. + * See: https://bugzilla.gnome.org/show_bug.cgi?id=709456 + */ +static const char * +_safe_base_info_get_name (GIBaseInfo *info) +{ + if (g_base_info_get_type (info) == GI_INFO_TYPE_TYPE) { + return "type_type_instance"; + } else { + return g_base_info_get_name (info); + } +} + static void _base_info_dealloc (PyGIBaseInfo *self) { @@ -64,40 +175,56 @@ _base_info_dealloc (PyGIBaseInfo *self) g_base_info_unref (self->info); - _pygi_callable_cache_free(self->cache); + if (self->cache != NULL) + pygi_callable_cache_free ( (PyGICallableCache *) self->cache); - Py_TYPE( (PyObject *) self)->tp_free ( (PyObject *) self); + Py_TYPE (self)->tp_free ((PyObject *)self); } static PyObject * _base_info_repr (PyGIBaseInfo *self) { - return PYGLIB_PyUnicode_FromFormat ("<%s object (%s) at 0x%p>", - Py_TYPE( (PyObject *) self)->tp_name, - g_base_info_get_name (self->info), - (void *) self); + + return PyUnicode_FromFormat ("%s(%s)", + Py_TYPE( (PyObject *) self)->tp_name, + _safe_base_info_get_name (self->info)); } static PyObject * -_base_info_richcompare (PyGIBaseInfo *self, PyObject *other, int op) +_wrap_g_base_info_equal (PyGIBaseInfo *self, PyObject *other) { - PyObject *res; GIBaseInfo *other_info; - if (!PyObject_TypeCheck(other, &PyGIBaseInfo_Type)) { - Py_INCREF(Py_NotImplemented); + if (!PyObject_TypeCheck (other, &PyGIBaseInfo_Type)) { + Py_INCREF (Py_NotImplemented); return Py_NotImplemented; } other_info = ((PyGIBaseInfo *)other)->info; + if (g_base_info_equal (self->info, other_info)) { + Py_RETURN_TRUE; + } else { + Py_RETURN_FALSE; + } +} + +static PyObject * +_base_info_richcompare (PyGIBaseInfo *self, PyObject *other, int op) +{ + PyObject *res; switch (op) { case Py_EQ: - res = g_base_info_equal (self->info, other_info) ? Py_True : Py_False; - break; + return _wrap_g_base_info_equal (self, other); case Py_NE: - res = g_base_info_equal (self->info, other_info) ? Py_False : Py_True; - break; + res = _wrap_g_base_info_equal (self, other); + if (res == Py_True) { + Py_DECREF (res); + Py_RETURN_FALSE; + } else { + Py_DECREF (res); + Py_RETURN_TRUE; + } default: res = Py_NotImplemented; break; @@ -106,21 +233,14 @@ _base_info_richcompare (PyGIBaseInfo *self, PyObject *other, int op) return res; } -PYGLIB_DEFINE_TYPE("gi.BaseInfo", PyGIBaseInfo_Type, PyGIBaseInfo); +PYGI_DEFINE_TYPE("gi.BaseInfo", PyGIBaseInfo_Type, PyGIBaseInfo); gboolean _pygi_is_python_keyword (const gchar *name) { /* It may be better to use keyword.iskeyword(); keep in sync with * python -c 'import keyword; print(keyword.kwlist)' */ -#if PY_VERSION_HEX < 0x03000000 - /* Python 2.x */ - static const gchar* keywords[] = {"and", "as", "assert", "break", "class", - "continue", "def", "del", "elif", "else", "except", "exec", "finally", - "for", "from", "global", "if", "import", "in", "is", "lambda", "not", - "or", "pass", "print", "raise", "return", "try", "while", "with", - "yield", NULL}; -#elif PY_VERSION_HEX < 0x04000000 +#if PY_VERSION_HEX < 0x04000000 /* Python 3.x; note that we explicitly keep "print"; it is not a keyword * any more, but we do not want to break API between Python versions */ static const gchar* keywords[] = {"False", "None", "True", "and", "as", @@ -145,38 +265,73 @@ _pygi_is_python_keyword (const gchar *name) } static PyObject * +_wrap_g_base_info_get_type (PyGIBaseInfo *self) +{ + return pygi_guint_to_py (g_base_info_get_type (self->info)); +} + +static PyObject * _wrap_g_base_info_get_name (PyGIBaseInfo *self) { const gchar *name; - name = g_base_info_get_name (self->info); + name = _safe_base_info_get_name (self->info); /* escape keywords */ if (_pygi_is_python_keyword (name)) { gchar *escaped = g_strconcat (name, "_", NULL); - PyObject *obj = PYGLIB_PyUnicode_FromString (escaped); + PyObject *obj = pygi_utf8_to_py (escaped); g_free (escaped); return obj; } - return PYGLIB_PyUnicode_FromString (name); + return pygi_utf8_to_py (name); } static PyObject * _wrap_g_base_info_get_name_unescaped (PyGIBaseInfo *self) { - return PYGLIB_PyUnicode_FromString (g_base_info_get_name (self->info)); + return _get_info_string (self, _safe_base_info_get_name); } static PyObject * _wrap_g_base_info_get_namespace (PyGIBaseInfo *self) { - return PYGLIB_PyUnicode_FromString (g_base_info_get_namespace (self->info)); + return _get_info_string (self, g_base_info_get_namespace); +} + +static PyObject * +_wrap_g_base_info_is_deprecated (PyGIBaseInfo *self) +{ + if (g_base_info_is_deprecated (self->info)) + Py_RETURN_TRUE; + else + Py_RETURN_FALSE; +} + +static PyObject * +_wrap_g_base_info_get_attribute (PyGIBaseInfo *self, PyObject *arg) +{ + char *name; + const char *value; + + if (!pygi_utf8_from_py (arg, &name)) + return NULL; + + value = g_base_info_get_attribute (self->info, name); + g_free (name); + if (value == NULL) { + Py_RETURN_NONE; + } + return pygi_utf8_to_py (value); } static PyObject * _wrap_g_base_info_get_container (PyGIBaseInfo *self) { + /* Note: don't use _get_child_info because g_base_info_get_container + * is marked as [transfer none] and therefore returns a borrowed ref. + */ GIBaseInfo *info; info = g_base_info_get_container (self->info); @@ -190,10 +345,14 @@ _wrap_g_base_info_get_container (PyGIBaseInfo *self) static PyMethodDef _PyGIBaseInfo_methods[] = { + { "get_type", (PyCFunction) _wrap_g_base_info_get_type, METH_NOARGS }, { "get_name", (PyCFunction) _wrap_g_base_info_get_name, METH_NOARGS }, { "get_name_unescaped", (PyCFunction) _wrap_g_base_info_get_name_unescaped, METH_NOARGS }, { "get_namespace", (PyCFunction) _wrap_g_base_info_get_namespace, METH_NOARGS }, + { "is_deprecated", (PyCFunction) _wrap_g_base_info_is_deprecated, METH_NOARGS }, + { "get_attribute", (PyCFunction) _wrap_g_base_info_get_attribute, METH_O }, { "get_container", (PyCFunction) _wrap_g_base_info_get_container, METH_NOARGS }, + { "equal", (PyCFunction) _wrap_g_base_info_equal, METH_O }, { NULL, NULL, 0 } }; @@ -209,13 +368,13 @@ _base_info_getattro(PyGIBaseInfo *self, PyObject *name) static PyObject *docstr; if (docstr == NULL) { - docstr= PYGLIB_PyUnicode_InternFromString("__doc__"); + docstr= PyUnicode_InternFromString ("__doc__"); if (docstr == NULL) return NULL; } Py_INCREF (name); - PYGLIB_PyUnicode_InternInPlace (&name); + PyUnicode_InternInPlace (&name); if (name == docstr) { result = _generate_doc_string (self); @@ -236,8 +395,8 @@ _base_info_attr_name(PyGIBaseInfo *self, void *closure) static PyObject * _base_info_attr_module(PyGIBaseInfo *self, void *closure) { - return PYGLIB_PyUnicode_FromFormat ("gi.repository.%s", - g_base_info_get_namespace (self->info)); + return PyUnicode_FromFormat ("gi.repository.%s", + g_base_info_get_namespace (self->info)); } static PyGetSetDef _base_info_getsets[] = { @@ -267,10 +426,8 @@ _pygi_info_new (GIBaseInfo *info) type = &PyGICallbackInfo_Type; break; case GI_INFO_TYPE_STRUCT: - type = &PyGIStructInfo_Type; - break; case GI_INFO_TYPE_BOXED: - type = &PyGIBoxedInfo_Type; + type = &PyGIStructInfo_Type; break; case GI_INFO_TYPE_ENUM: case GI_INFO_TYPE_FLAGS: @@ -342,7 +499,7 @@ _pygi_object_get_gi_info (PyObject *object, } if (!PyObject_TypeCheck (py_info, type)) { PyErr_Format (PyExc_TypeError, "attribute '__info__' must be %s, not %s", - type->tp_name, Py_TYPE(&py_info)->tp_name); + type->tp_name, Py_TYPE(py_info)->tp_name); goto out; } @@ -357,44 +514,7 @@ out: /* CallableInfo */ -PYGLIB_DEFINE_TYPE ("gi.CallableInfo", PyGICallableInfo_Type, PyGICallableInfo); - -static PyObject * -_wrap_g_callable_info_get_arguments (PyGIBaseInfo *self) -{ - gssize n_infos; - PyObject *infos; - gssize i; - - n_infos = g_callable_info_get_n_args ( (GICallableInfo *) self->info); - - infos = PyTuple_New (n_infos); - if (infos == NULL) { - return NULL; - } - - for (i = 0; i < n_infos; i++) { - GIBaseInfo *info; - PyObject *py_info; - - info = (GIBaseInfo *) g_callable_info_get_arg ( (GICallableInfo *) self->info, i); - g_assert (info != NULL); - - py_info = _pygi_info_new (info); - - g_base_info_unref (info); - - if (py_info == NULL) { - Py_CLEAR (infos); - break; - } - - PyTuple_SET_ITEM (infos, i, py_info); - } - - return infos; -} - +PYGI_DEFINE_TYPE ("gi.CallableInfo", PyGICallableInfo_Type, PyGICallableInfo); /* _callable_info_call: * @@ -440,6 +560,33 @@ _callable_info_call (PyGICallableInfo *self, PyObject *args, PyObject *kwargs) } } +static PyObject * +_callable_info_repr (PyGICallableInfo *self) +{ + PyObject *bound_repr_o = NULL; + const char *bound_repr = "None"; + PyObject *res = NULL; + + if (self->py_bound_arg) { + bound_repr_o = PyObject_Repr(self->py_bound_arg); + if (bound_repr_o == NULL) + goto out; + + bound_repr = PyUnicode_AsUTF8(bound_repr_o); + if (bound_repr == NULL) + goto out; + } + + res = PyUnicode_FromFormat ("%s(%s, bound=%s)", + Py_TYPE( (PyObject *) self)->tp_name, + _safe_base_info_get_name (self->base.info), + bound_repr); + +out: + Py_XDECREF(bound_repr_o); + + return res; +} /* _function_info_call: * @@ -472,17 +619,12 @@ _function_info_call (PyGICallableInfo *self, PyObject *args, PyObject *kwargs) py_str_name = tmp; } -#if PY_VERSION_HEX < 0x03000000 - str_name = PyString_AsString (py_str_name); -#else str_name = PyBytes_AsString (py_str_name); -#endif - - if (strcmp (str_name, g_base_info_get_name (container_info))) { + if (strcmp (str_name, _safe_base_info_get_name (container_info))) { PyErr_Format (PyExc_TypeError, "%s constructor cannot be used to create instances of " "a subclass %s", - g_base_info_get_name (container_info), + _safe_base_info_get_name (container_info), str_name); Py_DECREF (py_str_name); return NULL; @@ -572,132 +714,224 @@ _callable_info_dealloc (PyGICallableInfo *self) PyGIBaseInfo_Type.tp_dealloc ((PyObject *) self); } +static PyObject * +_wrap_g_callable_info_get_arguments (PyGIBaseInfo *self) +{ + return _make_infos_tuple (self, g_callable_info_get_n_args, g_callable_info_get_arg); +} + +static PyObject * +_wrap_g_callable_info_get_return_type (PyGIBaseInfo *self) +{ + return _get_child_info (self, g_callable_info_get_return_type); +} + +static PyObject * +_wrap_g_callable_info_get_caller_owns (PyGIBaseInfo *self) +{ + return pygi_guint_to_py ( + g_callable_info_get_caller_owns (self->info) ); +} + +static PyObject * +_wrap_g_callable_info_may_return_null (PyGIBaseInfo *self) +{ + return pygi_gboolean_to_py ( + g_callable_info_may_return_null (self->info) ); +} + +static PyObject * +_wrap_g_callable_info_skip_return (PyGIBaseInfo *self) +{ + return pygi_gboolean_to_py (g_callable_info_skip_return (self->info)); +} + +static PyObject * +_wrap_g_callable_info_get_return_attribute (PyGIBaseInfo *self, PyObject *py_name) +{ + gchar *name; + const gchar *attr; + + if (!pygi_utf8_from_py (py_name, &name)) + return NULL; + + attr = g_callable_info_get_return_attribute (self->info, name); + if (attr) { + g_free (name); + return pygi_utf8_to_py (attr); + } else { + PyErr_Format(PyExc_AttributeError, "return attribute %s not found", name); + g_free (name); + return NULL; + } +} + +static PyObject * +_wrap_g_callable_info_can_throw_gerror (PyGIBaseInfo *self) +{ + if (g_callable_info_can_throw_gerror (self->info)) + Py_RETURN_TRUE; + else + Py_RETURN_FALSE; +} + static PyMethodDef _PyGICallableInfo_methods[] = { { "invoke", (PyCFunction) _wrap_g_callable_info_invoke, METH_VARARGS | METH_KEYWORDS }, { "get_arguments", (PyCFunction) _wrap_g_callable_info_get_arguments, METH_NOARGS }, + { "get_return_type", (PyCFunction) _wrap_g_callable_info_get_return_type, METH_NOARGS }, + { "get_caller_owns", (PyCFunction) _wrap_g_callable_info_get_caller_owns, METH_NOARGS }, + { "may_return_null", (PyCFunction) _wrap_g_callable_info_may_return_null, METH_NOARGS }, + { "skip_return", (PyCFunction) _wrap_g_callable_info_skip_return, METH_NOARGS }, + { "get_return_attribute", (PyCFunction) _wrap_g_callable_info_get_return_attribute, METH_O }, + { "can_throw_gerror", (PyCFunction) _wrap_g_callable_info_can_throw_gerror, METH_NOARGS }, { NULL, NULL, 0 } }; /* CallbackInfo */ -PYGLIB_DEFINE_TYPE ("gi.CallbackInfo", PyGICallbackInfo_Type, PyGIBaseInfo); +PYGI_DEFINE_TYPE ("gi.CallbackInfo", PyGICallbackInfo_Type, PyGICallableInfo); static PyMethodDef _PyGICallbackInfo_methods[] = { { NULL, NULL, 0 } }; -/* BoxedInfo */ -PYGLIB_DEFINE_TYPE ("gi.BoxedInfo", PyGIBoxedInfo_Type, PyGIBaseInfo); - -static PyMethodDef _PyGIBoxedInfo_methods[] = { - { NULL, NULL, 0 } -}; - /* ErrorDomainInfo */ -PYGLIB_DEFINE_TYPE ("gi.ErrorDomainInfo", PyGIErrorDomainInfo_Type, PyGIBaseInfo); +PYGI_DEFINE_TYPE ("gi.ErrorDomainInfo", PyGIErrorDomainInfo_Type, PyGIBaseInfo); static PyMethodDef _PyGIErrorDomainInfo_methods[] = { { NULL, NULL, 0 } }; /* SignalInfo */ -PYGLIB_DEFINE_TYPE ("gi.SignalInfo", PyGISignalInfo_Type, PyGIBaseInfo); +PYGI_DEFINE_TYPE ("gi.SignalInfo", PyGISignalInfo_Type, PyGICallableInfo); + +static PyObject * +_wrap_g_signal_info_get_flags (PyGIBaseInfo *self) +{ + return pygi_guint_to_py ( + g_signal_info_get_flags ((GISignalInfo *)self->info) ); +} + +static PyObject * +_wrap_g_signal_info_get_class_closure (PyGIBaseInfo *self) +{ + return _get_child_info (self, g_signal_info_get_class_closure); +} + +static PyObject * +_wrap_g_signal_info_true_stops_emit (PyGIBaseInfo *self) +{ + return pygi_gboolean_to_py ( + g_signal_info_true_stops_emit ((GISignalInfo *)self->info) ); +} static PyMethodDef _PyGISignalInfo_methods[] = { + { "get_flags", (PyCFunction) _wrap_g_signal_info_get_flags, METH_NOARGS }, + { "get_class_closure", (PyCFunction) _wrap_g_signal_info_get_class_closure, METH_NOARGS }, + { "true_stops_emit", (PyCFunction) _wrap_g_signal_info_true_stops_emit, METH_NOARGS }, { NULL, NULL, 0 } }; /* PropertyInfo */ -PYGLIB_DEFINE_TYPE ("gi.PropertyInfo", PyGIPropertyInfo_Type, PyGIBaseInfo); +PYGI_DEFINE_TYPE ("gi.PropertyInfo", PyGIPropertyInfo_Type, PyGIBaseInfo); + +static PyObject * +_wrap_g_property_info_get_flags (PyGIBaseInfo *self) +{ + return pygi_guint_to_py ( + g_property_info_get_flags ((GIPropertyInfo *)self->info) ); +} + +static PyObject * +_wrap_g_property_info_get_type (PyGIBaseInfo *self) +{ + return _get_child_info (self, g_property_info_get_type); +} + +static PyObject * +_wrap_g_property_info_get_ownership_transfer (PyGIBaseInfo *self) +{ + return pygi_guint_to_py ( + g_property_info_get_ownership_transfer ((GIPropertyInfo *)self->info) ); +} static PyMethodDef _PyGIPropertyInfo_methods[] = { + { "get_flags", (PyCFunction) _wrap_g_property_info_get_flags, METH_NOARGS }, + { "get_type", (PyCFunction) _wrap_g_property_info_get_type, METH_NOARGS }, + { "get_ownership_transfer", (PyCFunction) _wrap_g_property_info_get_ownership_transfer, METH_NOARGS }, { NULL, NULL, 0 } }; /* ArgInfo */ -PYGLIB_DEFINE_TYPE ("gi.ArgInfo", PyGIArgInfo_Type, PyGIBaseInfo); +PYGI_DEFINE_TYPE ("gi.ArgInfo", PyGIArgInfo_Type, PyGIBaseInfo); static PyObject * _wrap_g_arg_info_get_direction (PyGIBaseInfo *self) { - return PyLong_FromLong ( + return pygi_guint_to_py ( g_arg_info_get_direction ((GIArgInfo*)self->info) ); } static PyObject * _wrap_g_arg_info_is_caller_allocates (PyGIBaseInfo *self) { - return PyBool_FromLong ( + return pygi_gboolean_to_py ( g_arg_info_is_caller_allocates ((GIArgInfo*)self->info) ); } static PyObject * _wrap_g_arg_info_is_return_value (PyGIBaseInfo *self) { - return PyBool_FromLong ( + return pygi_gboolean_to_py ( g_arg_info_is_return_value ((GIArgInfo*)self->info) ); } static PyObject * _wrap_g_arg_info_is_optional (PyGIBaseInfo *self) { - return PyBool_FromLong ( + return pygi_gboolean_to_py ( g_arg_info_is_optional ((GIArgInfo*)self->info) ); } static PyObject * _wrap_g_arg_info_may_be_null (PyGIBaseInfo *self) { - return PyBool_FromLong ( + return pygi_gboolean_to_py ( g_arg_info_may_be_null ((GIArgInfo*)self->info) ); } -/* _g_arg_get_pytype_hint - * - * Returns new value reference to a string hinting at the python type - * which can be used for the given gi argument info. - */ static PyObject * -_g_arg_get_pytype_hint (PyGIBaseInfo *self) +_wrap_g_arg_info_get_ownership_transfer (PyGIBaseInfo *self) { - GIArgInfo *arg_info = (GIArgInfo*)self->info; - GITypeInfo type_info; - GITypeTag type_tag; - PyObject *py_type; + return pygi_guint_to_py ( + g_arg_info_get_ownership_transfer ((GIArgInfo *)self->info) ); +} - g_arg_info_load_type(arg_info, &type_info); - type_tag = g_type_info_get_tag(&type_info); +static PyObject * +_wrap_g_arg_info_get_scope (PyGIBaseInfo *self) +{ + return pygi_guint_to_py ( + g_arg_info_get_scope ((GIArgInfo *)self->info) ); +} - /* First attempt getting a python type object. */ - py_type = _pygi_get_py_type_hint(type_tag); - if (py_type != Py_None && PyObject_HasAttrString(py_type, "__name__")) { - PyObject *name = PyObject_GetAttrString(py_type, "__name__"); - Py_DecRef(py_type); - return name; - } else { - Py_DecRef(py_type); - if (type_tag == GI_TYPE_TAG_INTERFACE) { - const char *info_name; - PyObject *py_string; - GIBaseInfo *iface = g_type_info_get_interface(&type_info); - gchar *name; - - info_name = g_base_info_get_name (iface); - if (info_name == NULL) { - g_base_info_unref (iface); - return PYGLIB_PyUnicode_FromString(g_type_tag_to_string(type_tag)); - } - - name = g_strdup_printf("%s.%s", - g_base_info_get_namespace(iface), - info_name); - g_base_info_unref(iface); - py_string = PYGLIB_PyUnicode_FromString(name); - g_free(name); - return py_string; - } - return PYGLIB_PyUnicode_FromString(g_type_tag_to_string(type_tag)); - } +static PyObject * +_wrap_g_arg_info_get_closure (PyGIBaseInfo *self) +{ + return pygi_gint_to_py ( + g_arg_info_get_closure ((GIArgInfo *)self->info) ); +} + +static PyObject * +_wrap_g_arg_info_get_destroy (PyGIBaseInfo *self) +{ + return pygi_gint_to_py ( + g_arg_info_get_destroy ((GIArgInfo *)self->info) ); +} + +static PyObject * +_wrap_g_arg_info_get_type (PyGIBaseInfo *self) +{ + return _get_child_info (self, g_arg_info_get_type); } static PyMethodDef _PyGIArgInfo_methods[] = { @@ -706,21 +940,103 @@ static PyMethodDef _PyGIArgInfo_methods[] = { { "is_return_value", (PyCFunction) _wrap_g_arg_info_is_return_value, METH_NOARGS }, { "is_optional", (PyCFunction) _wrap_g_arg_info_is_optional, METH_NOARGS }, { "may_be_null", (PyCFunction) _wrap_g_arg_info_may_be_null, METH_NOARGS }, - { "get_pytype_hint", (PyCFunction) _g_arg_get_pytype_hint, METH_NOARGS }, + { "get_ownership_transfer", (PyCFunction) _wrap_g_arg_info_get_ownership_transfer, METH_NOARGS }, + { "get_scope", (PyCFunction) _wrap_g_arg_info_get_scope, METH_NOARGS }, + { "get_closure", (PyCFunction) _wrap_g_arg_info_get_closure, METH_NOARGS }, + { "get_destroy", (PyCFunction) _wrap_g_arg_info_get_destroy, METH_NOARGS }, + { "get_type", (PyCFunction) _wrap_g_arg_info_get_type, METH_NOARGS }, { NULL, NULL, 0 } }; /* TypeInfo */ -PYGLIB_DEFINE_TYPE ("gi.TypeInfo", PyGITypeInfo_Type, PyGIBaseInfo); +PYGI_DEFINE_TYPE ("gi.TypeInfo", PyGITypeInfo_Type, PyGIBaseInfo); + +static PyObject * +_wrap_g_type_info_is_pointer (PyGIBaseInfo *self) +{ + return pygi_gboolean_to_py (g_type_info_is_pointer (self->info)); +} + +static PyObject * +_wrap_g_type_info_get_tag (PyGIBaseInfo *self) +{ + return pygi_guint_to_py (g_type_info_get_tag (self->info)); +} + +static PyObject * +_wrap_g_type_info_get_tag_as_string (PyGIBaseInfo *self) +{ + GITypeTag tag = g_type_info_get_tag (self->info); + return pygi_utf8_to_py (g_type_tag_to_string(tag)); +} + +static PyObject * +_wrap_g_type_info_get_param_type (PyGIBaseInfo *self, PyObject *py_n) +{ + GIBaseInfo *info; + PyObject *py_info; + gint n; + + if (!pygi_gint_from_py (py_n, &n)) + return NULL; + + info = (GIBaseInfo *) g_type_info_get_param_type ( (GITypeInfo *) self->info, n); + if (info == NULL) { + Py_RETURN_NONE; + } + + py_info = _pygi_info_new (info); + g_base_info_unref (info); + return py_info; +} + +static PyObject * +_wrap_g_type_info_get_interface (PyGIBaseInfo *self) +{ + return _get_child_info (self, g_type_info_get_interface); +} + +static PyObject * +_wrap_g_type_info_get_array_length (PyGIBaseInfo *self) +{ + return pygi_gint_to_py (g_type_info_get_array_length (self->info)); +} + +static PyObject * +_wrap_g_type_info_get_array_fixed_size (PyGIBaseInfo *self) +{ + return pygi_gint_to_py (g_type_info_get_array_fixed_size (self->info)); +} + +static PyObject * +_wrap_g_type_info_is_zero_terminated (PyGIBaseInfo *self) +{ + return pygi_gboolean_to_py (g_type_info_is_zero_terminated (self->info)); +} + +static PyObject * +_wrap_g_type_info_get_array_type (PyGIBaseInfo *self) +{ + return pygi_guint_to_py (g_type_info_get_array_type (self->info)); +} static PyMethodDef _PyGITypeInfo_methods[] = { + { "is_pointer", (PyCFunction) _wrap_g_type_info_is_pointer, METH_NOARGS }, + { "get_tag", (PyCFunction) _wrap_g_type_info_get_tag, METH_NOARGS }, + { "get_tag_as_string", (PyCFunction) _wrap_g_type_info_get_tag_as_string, METH_NOARGS }, + { "get_param_type", (PyCFunction) _wrap_g_type_info_get_param_type, METH_O }, + { "get_interface", (PyCFunction) _wrap_g_type_info_get_interface, METH_NOARGS }, + { "get_array_length", (PyCFunction) _wrap_g_type_info_get_array_length, METH_NOARGS }, + { "get_array_fixed_size", (PyCFunction) _wrap_g_type_info_get_array_fixed_size, METH_NOARGS }, + { "is_zero_terminated", (PyCFunction) _wrap_g_type_info_is_zero_terminated, METH_NOARGS }, + { "get_array_type", (PyCFunction) _wrap_g_type_info_get_array_type, METH_NOARGS }, { NULL, NULL, 0 } }; /* FunctionInfo */ -PYGLIB_DEFINE_TYPE ("gi.FunctionInfo", PyGIFunctionInfo_Type, PyGICallableInfo); +PYGI_DEFINE_TYPE ("gi.FunctionInfo", PyGIFunctionInfo_Type, PyGICallableInfo); static PyObject * _wrap_g_function_info_is_constructor (PyGIBaseInfo *self) @@ -731,7 +1047,7 @@ _wrap_g_function_info_is_constructor (PyGIBaseInfo *self) flags = g_function_info_get_flags ( (GIFunctionInfo*) self->info); is_constructor = flags & GI_FUNCTION_IS_CONSTRUCTOR; - return PyBool_FromLong (is_constructor); + return pygi_gboolean_to_py (is_constructor); } static PyObject * @@ -743,7 +1059,7 @@ _wrap_g_function_info_is_method (PyGIBaseInfo *self) flags = g_function_info_get_flags ( (GIFunctionInfo*) self->info); is_method = flags & GI_FUNCTION_IS_METHOD; - return PyBool_FromLong (is_method); + return pygi_gboolean_to_py (is_method); } gsize @@ -796,6 +1112,8 @@ _pygi_g_type_tag_size (GITypeTag type_tag) "Unable to know the size (assuming %s is not a pointer)", g_type_tag_to_string (type_tag)); break; + default: + break; } return size; @@ -854,10 +1172,10 @@ _pygi_g_type_info_size (GITypeInfo *type_info) if (g_type_info_is_pointer (type_info)) { size = sizeof (gpointer); } else { - GITypeTag type_tag; + GITypeTag enum_type_tag; - type_tag = g_enum_info_get_storage_type ( (GIEnumInfo *) info); - size = _pygi_g_type_tag_size (type_tag); + enum_type_tag = g_enum_info_get_storage_type ( (GIEnumInfo *) info); + size = _pygi_g_type_tag_size (enum_type_tag); } break; case GI_INFO_TYPE_BOXED: @@ -895,19 +1213,61 @@ _pygi_g_type_info_size (GITypeInfo *type_info) case GI_TYPE_TAG_ERROR: size = sizeof (gpointer); break; + default: + break; } return size; } +static PyObject * +_wrap_g_function_info_get_symbol (PyGIBaseInfo *self) +{ + return _get_info_string (self, g_function_info_get_symbol); +} + +static PyObject * +_wrap_g_function_info_get_flags (PyGIBaseInfo *self) +{ + return pygi_guint_to_py (g_function_info_get_flags (self->info)); +} + +static PyObject * +_wrap_g_function_info_get_property (PyGIBaseInfo *self) +{ + return _get_child_info (self, g_function_info_get_property); +} + +static PyObject * +_wrap_g_function_info_get_vfunc (PyGIBaseInfo *self) +{ + return _get_child_info (self, g_function_info_get_vfunc); +} + static PyMethodDef _PyGIFunctionInfo_methods[] = { { "is_constructor", (PyCFunction) _wrap_g_function_info_is_constructor, METH_NOARGS }, { "is_method", (PyCFunction) _wrap_g_function_info_is_method, METH_NOARGS }, + { "get_symbol", (PyCFunction) _wrap_g_function_info_get_symbol, METH_NOARGS }, + { "get_flags", (PyCFunction) _wrap_g_function_info_get_flags, METH_NOARGS }, + { "get_property", (PyCFunction) _wrap_g_function_info_get_property, METH_NOARGS }, + { "get_vfunc", (PyCFunction) _wrap_g_function_info_get_vfunc, METH_NOARGS }, { NULL, NULL, 0 } }; /* RegisteredTypeInfo */ -PYGLIB_DEFINE_TYPE ("gi.RegisteredTypeInfo", PyGIRegisteredTypeInfo_Type, PyGIBaseInfo); +PYGI_DEFINE_TYPE ("gi.RegisteredTypeInfo", PyGIRegisteredTypeInfo_Type, PyGIBaseInfo); + +static PyObject * +_wrap_g_registered_type_info_get_type_name (PyGIBaseInfo *self) +{ + return _get_info_string (self, g_registered_type_info_get_type_name); +} + +static PyObject * +_wrap_g_registered_type_info_get_type_init (PyGIBaseInfo *self) +{ + return _get_info_string (self, g_registered_type_info_get_type_init); +} static PyObject * _wrap_g_registered_type_info_get_g_type (PyGIBaseInfo *self) @@ -920,245 +1280,73 @@ _wrap_g_registered_type_info_get_g_type (PyGIBaseInfo *self) } static PyMethodDef _PyGIRegisteredTypeInfo_methods[] = { + { "get_type_name", (PyCFunction) _wrap_g_registered_type_info_get_type_name, METH_NOARGS }, + { "get_type_init", (PyCFunction) _wrap_g_registered_type_info_get_type_init, METH_NOARGS }, { "get_g_type", (PyCFunction) _wrap_g_registered_type_info_get_g_type, METH_NOARGS }, { NULL, NULL, 0 } }; /* GIStructInfo */ -PYGLIB_DEFINE_TYPE ("StructInfo", PyGIStructInfo_Type, PyGIBaseInfo); +PYGI_DEFINE_TYPE ("StructInfo", PyGIStructInfo_Type, PyGIBaseInfo); static PyObject * -_get_fields (PyGIBaseInfo *self, GIInfoType info_type) +_wrap_g_struct_info_get_fields (PyGIBaseInfo *self) { - gssize n_infos; - PyObject *infos; - gssize i; - - switch (info_type) { - case GI_INFO_TYPE_STRUCT: - n_infos = g_struct_info_get_n_fields ( (GIStructInfo *) self->info); - break; - case GI_INFO_TYPE_OBJECT: - n_infos = g_object_info_get_n_fields ( (GIObjectInfo *) self->info); - break; - default: - g_assert_not_reached(); - } - - infos = PyTuple_New (n_infos); - if (infos == NULL) { - return NULL; - } - - for (i = 0; i < n_infos; i++) { - GIBaseInfo *info; - PyObject *py_info; - - switch (info_type) { - case GI_INFO_TYPE_STRUCT: - info = (GIBaseInfo *) g_struct_info_get_field ( (GIStructInfo *) self->info, i); - break; - case GI_INFO_TYPE_OBJECT: - info = (GIBaseInfo *) g_object_info_get_field ( (GIObjectInfo *) self->info, i); - break; - default: - g_assert_not_reached(); - } - g_assert (info != NULL); - - py_info = _pygi_info_new (info); - - g_base_info_unref (info); - - if (py_info == NULL) { - Py_CLEAR (infos); - break; - } - - PyTuple_SET_ITEM (infos, i, py_info); - } - - return infos; + return _make_infos_tuple (self, g_struct_info_get_n_fields, g_struct_info_get_field); } static PyObject * -_get_methods (PyGIBaseInfo *self, GIInfoType info_type) +_wrap_g_struct_info_get_methods (PyGIBaseInfo *self) { - gssize n_infos; - PyObject *infos; - gssize i; - - switch (info_type) { - case GI_INFO_TYPE_STRUCT: - n_infos = g_struct_info_get_n_methods ( (GIStructInfo *) self->info); - break; - case GI_INFO_TYPE_OBJECT: - n_infos = g_object_info_get_n_methods ( (GIObjectInfo *) self->info); - break; - default: - g_assert_not_reached(); - } - - infos = PyTuple_New (n_infos); - if (infos == NULL) { - return NULL; - } - - for (i = 0; i < n_infos; i++) { - GIBaseInfo *info; - PyObject *py_info; - - switch (info_type) { - case GI_INFO_TYPE_STRUCT: - info = (GIBaseInfo *) g_struct_info_get_method ( (GIStructInfo *) self->info, i); - break; - case GI_INFO_TYPE_OBJECT: - info = (GIBaseInfo *) g_object_info_get_method ( (GIObjectInfo *) self->info, i); - break; - default: - g_assert_not_reached(); - } - g_assert (info != NULL); - - py_info = _pygi_info_new (info); - - g_base_info_unref (info); - - if (py_info == NULL) { - Py_CLEAR (infos); - break; - } - - PyTuple_SET_ITEM (infos, i, py_info); - } - - return infos; + return _make_infos_tuple (self, g_struct_info_get_n_methods, g_struct_info_get_method); } static PyObject * -_get_constants (PyGIBaseInfo *self, GIInfoType info_type) +_wrap_g_struct_info_get_size (PyGIBaseInfo *self) { - gssize n_infos; - PyObject *infos; - gssize i; - - switch (info_type) { - case GI_INFO_TYPE_INTERFACE: - n_infos = g_interface_info_get_n_constants ( (GIInterfaceInfo *) self->info); - break; - case GI_INFO_TYPE_OBJECT: - n_infos = g_object_info_get_n_constants ( (GIObjectInfo *) self->info); - break; - default: - g_assert_not_reached(); - } - - infos = PyTuple_New (n_infos); - if (infos == NULL) { - return NULL; - } - - for (i = 0; i < n_infos; i++) { - GIBaseInfo *info; - PyObject *py_info; - - switch (info_type) { - case GI_INFO_TYPE_INTERFACE: - info = (GIBaseInfo *) g_interface_info_get_constant ( (GIInterfaceInfo *) self->info, i); - break; - case GI_INFO_TYPE_OBJECT: - info = (GIBaseInfo *) g_object_info_get_constant ( (GIObjectInfo *) self->info, i); - break; - default: - g_assert_not_reached(); - } - g_assert (info != NULL); - - py_info = _pygi_info_new (info); - - g_base_info_unref (info); - - if (py_info == NULL) { - Py_CLEAR (infos); - break; - } - - PyTuple_SET_ITEM (infos, i, py_info); - } - - return infos; + return pygi_gsize_to_py (g_struct_info_get_size (self->info)); } static PyObject * -_get_vfuncs (PyGIBaseInfo *self, GIInfoType info_type) +_wrap_g_struct_info_get_alignment (PyGIBaseInfo *self) { - gssize n_infos; - PyObject *infos; - gssize i; - - switch (info_type) { - case GI_INFO_TYPE_INTERFACE: - n_infos = g_interface_info_get_n_vfuncs ( (GIInterfaceInfo *) self->info); - break; - case GI_INFO_TYPE_OBJECT: - n_infos = g_object_info_get_n_vfuncs ( (GIObjectInfo *) self->info); - break; - default: - g_assert_not_reached(); - } - - infos = PyTuple_New (n_infos); - if (infos == NULL) { - return NULL; - } - - for (i = 0; i < n_infos; i++) { - GIBaseInfo *info; - PyObject *py_info; - - switch (info_type) { - case GI_INFO_TYPE_INTERFACE: - info = (GIBaseInfo *) g_interface_info_get_vfunc ( (GIInterfaceInfo *) self->info, i); - break; - case GI_INFO_TYPE_OBJECT: - info = (GIBaseInfo *) g_object_info_get_vfunc ( (GIObjectInfo *) self->info, i); - break; - default: - g_assert_not_reached(); - } - g_assert (info != NULL); - - py_info = _pygi_info_new (info); - - g_base_info_unref (info); - - if (py_info == NULL) { - Py_CLEAR (infos); - break; - } + return pygi_gsize_to_py (g_struct_info_get_alignment (self->info)); +} - PyTuple_SET_ITEM (infos, i, py_info); - } +static PyObject * +_wrap_g_struct_info_is_gtype_struct (PyGIBaseInfo *self) +{ + return pygi_gboolean_to_py (g_struct_info_is_gtype_struct (self->info)); +} - return infos; +static PyObject * +_wrap_g_struct_info_is_foreign (PyGIBaseInfo *self) +{ + return pygi_gboolean_to_py (g_struct_info_is_foreign (self->info)); } static PyObject * -_wrap_g_struct_info_get_fields (PyGIBaseInfo *self) +_wrap_g_struct_info_find_method (PyGIBaseInfo *self, PyObject *py_name) { - return _get_fields (self, GI_INFO_TYPE_STRUCT); + return _get_child_info_by_name (self, py_name, g_struct_info_find_method); } static PyObject * -_wrap_g_struct_info_get_methods (PyGIBaseInfo *self) +_wrap_g_struct_info_find_field (PyGIBaseInfo *self, PyObject *py_name) { - return _get_methods (self, GI_INFO_TYPE_STRUCT); + return _get_child_info_by_name (self, py_name, g_struct_info_find_field); } static PyMethodDef _PyGIStructInfo_methods[] = { { "get_fields", (PyCFunction) _wrap_g_struct_info_get_fields, METH_NOARGS }, + { "find_field", (PyCFunction) _wrap_g_struct_info_find_field, METH_O }, { "get_methods", (PyCFunction) _wrap_g_struct_info_get_methods, METH_NOARGS }, + { "find_method", (PyCFunction) _wrap_g_struct_info_find_method, METH_O }, + { "get_size", (PyCFunction) _wrap_g_struct_info_get_size, METH_NOARGS }, + { "get_alignment", (PyCFunction) _wrap_g_struct_info_get_alignment, METH_NOARGS }, + { "is_gtype_struct", (PyCFunction) _wrap_g_struct_info_is_gtype_struct, METH_NOARGS }, + { "is_foreign", (PyCFunction) _wrap_g_struct_info_is_foreign, METH_NOARGS }, { NULL, NULL, 0 } }; @@ -1166,8 +1354,8 @@ gboolean pygi_g_struct_info_is_simple (GIStructInfo *struct_info) { gboolean is_simple; - gsize n_field_infos; - gsize i; + gint n_field_infos; + gint i; is_simple = TRUE; @@ -1263,6 +1451,9 @@ pygi_g_struct_info_is_simple (GIStructInfo *struct_info) g_base_info_unref (info); break; } + default: + g_assert_not_reached(); + break; } g_base_info_unref ( (GIBaseInfo *) field_type_info); @@ -1274,42 +1465,12 @@ pygi_g_struct_info_is_simple (GIStructInfo *struct_info) /* EnumInfo */ -PYGLIB_DEFINE_TYPE ("gi.EnumInfo", PyGIEnumInfo_Type, PyGIBaseInfo); +PYGI_DEFINE_TYPE ("gi.EnumInfo", PyGIEnumInfo_Type, PyGIBaseInfo); static PyObject * _wrap_g_enum_info_get_values (PyGIBaseInfo *self) { - gssize n_infos; - PyObject *infos; - gssize i; - - n_infos = g_enum_info_get_n_values ( (GIEnumInfo *) self->info); - - infos = PyTuple_New (n_infos); - if (infos == NULL) { - return NULL; - } - - for (i = 0; i < n_infos; i++) { - GIBaseInfo *info; - PyObject *py_info; - - info = (GIBaseInfo *) g_enum_info_get_value ( (GIEnumInfo *) self->info, i); - g_assert (info != NULL); - - py_info = _pygi_info_new (info); - - g_base_info_unref (info); - - if (py_info == NULL) { - Py_CLEAR (infos); - break; - } - - PyTuple_SET_ITEM (infos, i, py_info); - } - - return infos; + return _make_infos_tuple (self, g_enum_info_get_n_values, g_enum_info_get_value); } static PyObject * @@ -1326,195 +1487,254 @@ _wrap_g_enum_info_is_flags (PyGIBaseInfo *self) } } +static PyObject * +_wrap_g_enum_info_get_methods (PyGIBaseInfo *self) +{ + return _make_infos_tuple (self, g_enum_info_get_n_methods, g_enum_info_get_method); +} + +static PyObject * +_wrap_g_enum_info_get_storage_type (PyGIBaseInfo *self) +{ + return pygi_guint_to_py (g_enum_info_get_storage_type ((GIBaseInfo *) self->info)); +} + static PyMethodDef _PyGIEnumInfo_methods[] = { { "get_values", (PyCFunction) _wrap_g_enum_info_get_values, METH_NOARGS }, { "is_flags", (PyCFunction) _wrap_g_enum_info_is_flags, METH_NOARGS }, + { "get_methods", (PyCFunction) _wrap_g_enum_info_get_methods, METH_NOARGS }, + { "get_storage_type", (PyCFunction) _wrap_g_enum_info_get_storage_type, METH_NOARGS }, { NULL, NULL, 0 } }; /* ObjectInfo */ -PYGLIB_DEFINE_TYPE ("ObjectInfo", PyGIObjectInfo_Type, PyGIBaseInfo); +PYGI_DEFINE_TYPE ("ObjectInfo", PyGIObjectInfo_Type, PyGIBaseInfo); static PyObject * _wrap_g_object_info_get_parent (PyGIBaseInfo *self) { - GIBaseInfo *info; - PyObject *py_info; - - info = (GIBaseInfo *) g_object_info_get_parent ( (GIObjectInfo*) self->info); - - if (info == NULL) { - Py_RETURN_NONE; - } - - py_info = _pygi_info_new (info); - - g_base_info_unref (info); - - return py_info; + return _get_child_info (self, g_object_info_get_parent); } static PyObject * _wrap_g_object_info_get_methods (PyGIBaseInfo *self) { - return _get_methods (self, GI_INFO_TYPE_OBJECT); + return _make_infos_tuple (self, g_object_info_get_n_methods, g_object_info_get_method); } static PyObject * -_wrap_g_object_info_get_fields (PyGIBaseInfo *self) +_wrap_g_object_info_find_method (PyGIBaseInfo *self, PyObject *py_name) { - return _get_fields (self, GI_INFO_TYPE_OBJECT); + return _get_child_info_by_name (self, py_name, g_object_info_find_method); } static PyObject * -_wrap_g_object_info_get_interfaces (PyGIBaseInfo *self) +_wrap_g_object_info_get_fields (PyGIBaseInfo *self) { - gssize n_infos; - PyObject *infos; - gssize i; - - n_infos = g_object_info_get_n_interfaces ( (GIObjectInfo *) self->info); - - infos = PyTuple_New (n_infos); - if (infos == NULL) { - return NULL; - } - - for (i = 0; i < n_infos; i++) { - GIBaseInfo *info; - PyObject *py_info; - - info = (GIBaseInfo *) g_object_info_get_interface ( (GIObjectInfo *) self->info, i); - g_assert (info != NULL); - - py_info = _pygi_info_new (info); - - g_base_info_unref (info); + return _make_infos_tuple (self, g_object_info_get_n_fields, g_object_info_get_field); +} - if (py_info == NULL) { - Py_CLEAR (infos); - break; - } +static PyObject * +_wrap_g_object_info_get_properties (PyGIBaseInfo *self) +{ + return _make_infos_tuple (self, g_object_info_get_n_properties, g_object_info_get_property); +} - PyTuple_SET_ITEM (infos, i, py_info); - } +static PyObject * +_wrap_g_object_info_get_signals (PyGIBaseInfo *self) +{ + return _make_infos_tuple (self, g_object_info_get_n_signals, g_object_info_get_signal); +} - return infos; +static PyObject * +_wrap_g_object_info_get_interfaces (PyGIBaseInfo *self) +{ + return _make_infos_tuple (self, g_object_info_get_n_interfaces, g_object_info_get_interface); } static PyObject * _wrap_g_object_info_get_constants (PyGIBaseInfo *self) { - return _get_constants (self, GI_INFO_TYPE_OBJECT); + return _make_infos_tuple (self, g_object_info_get_n_constants, g_object_info_get_constant); } static PyObject * _wrap_g_object_info_get_vfuncs (PyGIBaseInfo *self) { - return _get_vfuncs (self, GI_INFO_TYPE_OBJECT); + return _make_infos_tuple (self, g_object_info_get_n_vfuncs, g_object_info_get_vfunc); } static PyObject * _wrap_g_object_info_get_abstract (PyGIBaseInfo *self) { gboolean is_abstract = g_object_info_get_abstract ( (GIObjectInfo*) self->info); - return PyBool_FromLong (is_abstract); + return pygi_gboolean_to_py (is_abstract); +} + +static PyObject * +_wrap_g_object_info_get_type_name (PyGIBaseInfo *self) +{ + return _get_info_string (self, g_object_info_get_type_name); +} + +static PyObject * +_wrap_g_object_info_get_type_init (PyGIBaseInfo *self) +{ + return _get_info_string (self, g_object_info_get_type_init); +} + +static PyObject * +_wrap_g_object_info_get_fundamental (PyGIBaseInfo *self) +{ + return pygi_gboolean_to_py (g_object_info_get_fundamental ( (GIObjectInfo*) self->info)); } static PyObject * _wrap_g_object_info_get_class_struct (PyGIBaseInfo *self) { - GIBaseInfo *info; + return _get_child_info (self, g_object_info_get_class_struct); +} - info = g_object_info_get_class_struct ((GIObjectInfo*)self->info); +static PyObject * +_wrap_g_object_info_find_vfunc (PyGIBaseInfo *self, PyObject *py_name) +{ + return _get_child_info_by_name (self, py_name, g_object_info_find_vfunc); +} - if (info == NULL) { - Py_RETURN_NONE; - } +static PyObject * +_wrap_g_object_info_get_unref_function (PyGIBaseInfo *self) +{ + return _get_info_string (self, g_object_info_get_unref_function); +} - return _pygi_info_new (info); +static PyObject * +_wrap_g_object_info_get_ref_function (PyGIBaseInfo *self) +{ + return _get_info_string (self, g_object_info_get_ref_function); +} + +static PyObject * +_wrap_g_object_info_get_set_value_function (PyGIBaseInfo *self) +{ + return _get_info_string (self, g_object_info_get_set_value_function); +} + +static PyObject * +_wrap_g_object_info_get_get_value_function (PyGIBaseInfo *self) +{ + return _get_info_string (self, g_object_info_get_get_value_function); } static PyMethodDef _PyGIObjectInfo_methods[] = { { "get_parent", (PyCFunction) _wrap_g_object_info_get_parent, METH_NOARGS }, { "get_methods", (PyCFunction) _wrap_g_object_info_get_methods, METH_NOARGS }, + { "find_method", (PyCFunction) _wrap_g_object_info_find_method, METH_O }, { "get_fields", (PyCFunction) _wrap_g_object_info_get_fields, METH_NOARGS }, + { "get_properties", (PyCFunction) _wrap_g_object_info_get_properties, METH_NOARGS }, + { "get_signals", (PyCFunction) _wrap_g_object_info_get_signals, METH_NOARGS }, { "get_interfaces", (PyCFunction) _wrap_g_object_info_get_interfaces, METH_NOARGS }, { "get_constants", (PyCFunction) _wrap_g_object_info_get_constants, METH_NOARGS }, { "get_vfuncs", (PyCFunction) _wrap_g_object_info_get_vfuncs, METH_NOARGS }, + { "find_vfunc", (PyCFunction) _wrap_g_object_info_find_vfunc, METH_O }, { "get_abstract", (PyCFunction) _wrap_g_object_info_get_abstract, METH_NOARGS }, + { "get_type_name", (PyCFunction) _wrap_g_object_info_get_type_name, METH_NOARGS }, + { "get_type_init", (PyCFunction) _wrap_g_object_info_get_type_init, METH_NOARGS }, + { "get_fundamental", (PyCFunction) _wrap_g_object_info_get_fundamental, METH_NOARGS }, { "get_class_struct", (PyCFunction) _wrap_g_object_info_get_class_struct, METH_NOARGS }, + { "get_unref_function", (PyCFunction) _wrap_g_object_info_get_unref_function, METH_NOARGS }, + { "get_ref_function", (PyCFunction) _wrap_g_object_info_get_ref_function, METH_NOARGS }, + { "get_set_value_function", (PyCFunction) _wrap_g_object_info_get_set_value_function, METH_NOARGS }, + { "get_get_value_function", (PyCFunction) _wrap_g_object_info_get_get_value_function, METH_NOARGS }, { NULL, NULL, 0 } }; /* GIInterfaceInfo */ -PYGLIB_DEFINE_TYPE ("InterfaceInfo", PyGIInterfaceInfo_Type, PyGIBaseInfo); +PYGI_DEFINE_TYPE ("InterfaceInfo", PyGIInterfaceInfo_Type, PyGIBaseInfo); static PyObject * _wrap_g_interface_info_get_methods (PyGIBaseInfo *self) { - gssize n_infos; - PyObject *infos; - gssize i; - - n_infos = g_interface_info_get_n_methods ( (GIInterfaceInfo *) self->info); - - infos = PyTuple_New (n_infos); - if (infos == NULL) { - return NULL; - } + return _make_infos_tuple (self, g_interface_info_get_n_methods, g_interface_info_get_method); +} - for (i = 0; i < n_infos; i++) { - GIBaseInfo *info; - PyObject *py_info; +static PyObject * +_wrap_g_interface_info_find_method (PyGIBaseInfo *self, PyObject *py_name) +{ + return _get_child_info_by_name (self, py_name, g_interface_info_find_method); +} - info = (GIBaseInfo *) g_interface_info_get_method ( (GIInterfaceInfo *) self->info, i); - g_assert (info != NULL); +static PyObject * +_wrap_g_interface_info_get_constants (PyGIBaseInfo *self) +{ + return _make_infos_tuple (self, g_interface_info_get_n_constants, g_interface_info_get_constant); +} - py_info = _pygi_info_new (info); +static PyObject * +_wrap_g_interface_info_get_vfuncs (PyGIBaseInfo *self) +{ + return _make_infos_tuple (self, g_interface_info_get_n_vfuncs, g_interface_info_get_vfunc); +} - g_base_info_unref (info); +static PyObject * +_wrap_g_interface_info_find_vfunc (PyGIBaseInfo *self, PyObject *py_name) +{ + return _get_child_info_by_name (self, py_name, g_interface_info_find_vfunc); +} - if (py_info == NULL) { - Py_CLEAR (infos); - break; - } +static PyObject * +_wrap_g_interface_info_get_prerequisites (PyGIBaseInfo *self) +{ + return _make_infos_tuple (self, g_interface_info_get_n_prerequisites, g_interface_info_get_prerequisite); +} - PyTuple_SET_ITEM (infos, i, py_info); - } +static PyObject * +_wrap_g_interface_info_get_properties (PyGIBaseInfo *self) +{ + return _make_infos_tuple (self, g_interface_info_get_n_properties, g_interface_info_get_property); +} - return infos; +static PyObject * +_wrap_g_interface_info_get_iface_struct (PyGIBaseInfo *self) +{ + return _get_child_info (self, g_interface_info_get_iface_struct); } static PyObject * -_wrap_g_interface_info_get_constants (PyGIBaseInfo *self) +_wrap_g_interface_info_get_signals (PyGIBaseInfo *self) { - return _get_constants (self, GI_INFO_TYPE_INTERFACE); + return _make_infos_tuple (self, g_interface_info_get_n_signals, g_interface_info_get_signal); } static PyObject * -_wrap_g_interface_info_get_vfuncs (PyGIBaseInfo *self) +_wrap_g_interface_info_find_signal (PyGIBaseInfo *self, PyObject *py_name) { - return _get_vfuncs (self, GI_INFO_TYPE_INTERFACE); + return _get_child_info_by_name (self, py_name, g_interface_info_find_signal); } static PyMethodDef _PyGIInterfaceInfo_methods[] = { + { "get_prerequisites", (PyCFunction) _wrap_g_interface_info_get_prerequisites, METH_NOARGS }, + { "get_properties", (PyCFunction) _wrap_g_interface_info_get_properties, METH_NOARGS }, { "get_methods", (PyCFunction) _wrap_g_interface_info_get_methods, METH_NOARGS }, - { "get_constants", (PyCFunction) _wrap_g_interface_info_get_constants, METH_NOARGS }, + { "find_method", (PyCFunction) _wrap_g_interface_info_find_method, METH_O }, + { "get_signals", (PyCFunction) _wrap_g_interface_info_get_signals, METH_NOARGS }, + { "find_signal", (PyCFunction) _wrap_g_interface_info_find_signal, METH_O }, { "get_vfuncs", (PyCFunction) _wrap_g_interface_info_get_vfuncs, METH_NOARGS }, + { "get_constants", (PyCFunction) _wrap_g_interface_info_get_constants, METH_NOARGS }, + { "get_iface_struct", (PyCFunction) _wrap_g_interface_info_get_iface_struct, METH_NOARGS }, + { "find_vfunc", (PyCFunction) _wrap_g_interface_info_find_vfunc, METH_O }, { NULL, NULL, 0 } }; /* GIConstantInfo */ -PYGLIB_DEFINE_TYPE ("gi.ConstantInfo", PyGIConstantInfo_Type, PyGIBaseInfo); +PYGI_DEFINE_TYPE ("gi.ConstantInfo", PyGIConstantInfo_Type, PyGIBaseInfo); static PyObject * _wrap_g_constant_info_get_value (PyGIBaseInfo *self) { GITypeInfo *type_info; - GIArgument value; + GIArgument value = {0}; PyObject *py_value; gboolean free_array = FALSE; @@ -1548,16 +1768,16 @@ static PyMethodDef _PyGIConstantInfo_methods[] = { }; /* GIValueInfo */ -PYGLIB_DEFINE_TYPE ("gi.ValueInfo", PyGIValueInfo_Type, PyGIBaseInfo); +PYGI_DEFINE_TYPE ("gi.ValueInfo", PyGIValueInfo_Type, PyGIBaseInfo); static PyObject * _wrap_g_value_info_get_value (PyGIBaseInfo *self) { - glong value; + gint64 value; value = g_value_info_get_value ( (GIValueInfo *) self->info); - return PYGLIB_PyLong_FromLong (value); + return pygi_gint64_to_py (value); } @@ -1568,7 +1788,119 @@ static PyMethodDef _PyGIValueInfo_methods[] = { /* GIFieldInfo */ -PYGLIB_DEFINE_TYPE ("gi.FieldInfo", PyGIFieldInfo_Type, PyGIBaseInfo); +PYGI_DEFINE_TYPE ("gi.FieldInfo", PyGIFieldInfo_Type, PyGIBaseInfo); + +static gssize +_struct_field_array_length_marshal (gsize length_index, + void *container_ptr, + void *struct_data_ptr) +{ + gssize array_len = -1; + GIFieldInfo *array_len_field = NULL; + GIArgument arg = {0}; + GIBaseInfo *container_info = (GIBaseInfo *)container_ptr; + + switch (g_base_info_get_type (container_info)) { + case GI_INFO_TYPE_UNION: + array_len_field = g_union_info_get_field ((GIUnionInfo *)container_info, (gint)length_index); + break; + case GI_INFO_TYPE_STRUCT: + array_len_field = g_struct_info_get_field ((GIStructInfo *)container_info, (gint)length_index); + break; + case GI_INFO_TYPE_OBJECT: + array_len_field = g_object_info_get_field ((GIObjectInfo *)container_info, (gint)length_index); + break; + default: + /* Other types don't have fields. */ + g_assert_not_reached(); + } + + if (array_len_field == NULL) { + return -1; + } + + if (g_field_info_get_field (array_len_field, struct_data_ptr, &arg)) { + GITypeInfo *array_len_type_info; + + array_len_type_info = g_field_info_get_type (array_len_field); + if (array_len_type_info == NULL) { + goto out; + } + + if (!pygi_argument_to_gssize (&arg, + g_type_info_get_tag (array_len_type_info), + &array_len)) { + array_len = -1; + } + + g_base_info_unref (array_len_type_info); + } + +out: + g_base_info_unref (array_len_field); + return array_len; +} + +static gint +_pygi_g_registered_type_info_check_object (GIRegisteredTypeInfo *info, + PyObject *object) +{ + gint retval; + + GType g_type; + PyObject *py_type; + gchar *type_name_expected = NULL; + GIInfoType interface_type; + + interface_type = g_base_info_get_type (info); + if ( (interface_type == GI_INFO_TYPE_STRUCT) && + (g_struct_info_is_foreign ( (GIStructInfo*) info))) { + /* TODO: Could we check is the correct foreign type? */ + return 1; + } + + g_type = g_registered_type_info_get_g_type (info); + if (g_type != G_TYPE_NONE) { + py_type = pygi_type_get_from_g_type (g_type); + } else { + py_type = pygi_type_import_by_gi_info ( (GIBaseInfo *) info); + } + + if (py_type == NULL) { + return 0; + } + + g_assert (PyType_Check (py_type)); + + retval = PyObject_IsInstance (object, py_type); + if (!retval) { + type_name_expected = _pygi_g_base_info_get_fullname ( + (GIBaseInfo *) info); + } + + Py_DECREF (py_type); + + if (!retval) { + PyTypeObject *object_type; + + if (type_name_expected == NULL) { + return -1; + } + + object_type = (PyTypeObject *) PyObject_Type (object); + if (object_type == NULL) { + g_free (type_name_expected); + return -1; + } + + PyErr_Format (PyExc_TypeError, "Must be %s, not %s", + type_name_expected, object_type->tp_name); + + g_free (type_name_expected); + } + + return retval; +} static PyObject * _wrap_g_field_info_get_value (PyGIBaseInfo *self, @@ -1593,7 +1925,7 @@ _wrap_g_field_info_get_value (PyGIBaseInfo *self, g_assert (container_info != NULL); /* Check the instance. */ - if (!_pygi_g_registered_type_info_check_object ( (GIRegisteredTypeInfo *) container_info, TRUE, instance)) { + if (!_pygi_g_registered_type_info_check_object ( (GIRegisteredTypeInfo *) container_info, instance)) { _PyGI_ERROR_PREFIX ("argument 1: "); return NULL; } @@ -1659,8 +1991,12 @@ _wrap_g_field_info_get_value (PyGIBaseInfo *self, } if (g_type_info_get_tag (field_type_info) == GI_TYPE_TAG_ARRAY) { - value.v_pointer = _pygi_argument_to_array (&value, NULL, NULL, NULL, - field_type_info, &free_array); + value.v_pointer = _pygi_argument_to_array (&value, + _struct_field_array_length_marshal, + container_info, + pointer, + field_type_info, + &free_array); } argument_to_object: @@ -1697,7 +2033,7 @@ _wrap_g_field_info_set_value (PyGIBaseInfo *self, g_assert (container_info != NULL); /* Check the instance. */ - if (!_pygi_g_registered_type_info_check_object ( (GIRegisteredTypeInfo *) container_info, TRUE, instance)) { + if (!_pygi_g_registered_type_info_check_object ( (GIRegisteredTypeInfo *) container_info, instance)) { _PyGI_ERROR_PREFIX ("argument 1: "); return NULL; } @@ -1719,21 +2055,6 @@ _wrap_g_field_info_set_value (PyGIBaseInfo *self, field_type_info = g_field_info_get_type ( (GIFieldInfo *) self->info); - /* Check the value. */ - { - gboolean retval; - - retval = _pygi_g_type_info_check_object (field_type_info, py_value, TRUE); - if (retval < 0) { - goto out; - } - - if (!retval) { - _PyGI_ERROR_PREFIX ("argument 2: "); - goto out; - } - } - /* Set the field's value. */ /* A few types are not handled by g_field_info_set_field, so do it here. */ if (!g_type_info_is_pointer (field_type_info) @@ -1779,7 +2100,7 @@ _wrap_g_field_info_set_value (PyGIBaseInfo *self, size = g_struct_info_get_size ( (GIStructInfo *) info); g_assert (size > 0); - g_memmove ((char*) pointer + offset, value.v_pointer, size); + memmove ((char*) pointer + offset, value.v_pointer, size); g_base_info_unref (info); @@ -1828,122 +2149,116 @@ out: return retval; } +static PyObject * +_wrap_g_field_info_get_flags (PyGIBaseInfo *self) +{ + return pygi_guint_to_py (g_field_info_get_flags (self->info)); +} + +static PyObject * +_wrap_g_field_info_get_size (PyGIBaseInfo *self) +{ + return pygi_gint_to_py (g_field_info_get_size (self->info)); +} + +static PyObject * +_wrap_g_field_info_get_offset (PyGIBaseInfo *self) +{ + return pygi_gint_to_py (g_field_info_get_offset (self->info)); +} + +static PyObject * +_wrap_g_field_info_get_type (PyGIBaseInfo *self) +{ + return _get_child_info (self, g_field_info_get_type); +} + static PyMethodDef _PyGIFieldInfo_methods[] = { { "get_value", (PyCFunction) _wrap_g_field_info_get_value, METH_VARARGS }, { "set_value", (PyCFunction) _wrap_g_field_info_set_value, METH_VARARGS }, + { "get_flags", (PyCFunction) _wrap_g_field_info_get_flags, METH_VARARGS }, + { "get_size", (PyCFunction) _wrap_g_field_info_get_size, METH_VARARGS }, + { "get_offset", (PyCFunction) _wrap_g_field_info_get_offset, METH_VARARGS }, + { "get_type", (PyCFunction) _wrap_g_field_info_get_type, METH_VARARGS }, { NULL, NULL, 0 } }; /* GIUnresolvedInfo */ -PYGLIB_DEFINE_TYPE ("gi.UnresolvedInfo", PyGIUnresolvedInfo_Type, PyGIBaseInfo); +PYGI_DEFINE_TYPE ("gi.UnresolvedInfo", PyGIUnresolvedInfo_Type, PyGIBaseInfo); static PyMethodDef _PyGIUnresolvedInfo_methods[] = { { NULL, NULL, 0 } }; /* GIVFuncInfo */ -PYGLIB_DEFINE_TYPE ("gi.VFuncInfo", PyGIVFuncInfo_Type, PyGICallableInfo); +PYGI_DEFINE_TYPE ("gi.VFuncInfo", PyGIVFuncInfo_Type, PyGICallableInfo); static PyObject * -_wrap_g_vfunc_info_get_invoker (PyGIBaseInfo *self) +_wrap_g_vfunc_info_get_flags (PyGIBaseInfo *self) { - PyObject *result = Py_None; - GIBaseInfo *info; + return pygi_guint_to_py (g_vfunc_info_get_flags ((GIVFuncInfo *) self->info)); +} - info = (GIBaseInfo *) g_vfunc_info_get_invoker ( (GIVFuncInfo *) self->info ); - if (info) - result = _pygi_info_new(info); - else - Py_INCREF(Py_None); +static PyObject * +_wrap_g_vfunc_info_get_offset (PyGIBaseInfo *self) +{ + return pygi_gint_to_py (g_vfunc_info_get_offset ((GIVFuncInfo *) self->info)); +} - return result; +static PyObject * +_wrap_g_vfunc_info_get_signal (PyGIBaseInfo *self) +{ + return _get_child_info (self, g_vfunc_info_get_signal); +} + +static PyObject * +_wrap_g_vfunc_info_get_invoker (PyGIBaseInfo *self) +{ + return _get_child_info (self, g_vfunc_info_get_invoker); } static PyMethodDef _PyGIVFuncInfo_methods[] = { + { "get_flags", (PyCFunction) _wrap_g_vfunc_info_get_flags, METH_NOARGS }, + { "get_offset", (PyCFunction) _wrap_g_vfunc_info_get_offset, METH_NOARGS }, + { "get_signal", (PyCFunction) _wrap_g_vfunc_info_get_signal, METH_NOARGS }, { "get_invoker", (PyCFunction) _wrap_g_vfunc_info_get_invoker, METH_NOARGS }, { NULL, NULL, 0 } }; /* GIUnionInfo */ -PYGLIB_DEFINE_TYPE ("gi.UnionInfo", PyGIUnionInfo_Type, PyGIBaseInfo); +PYGI_DEFINE_TYPE ("gi.UnionInfo", PyGIUnionInfo_Type, PyGIBaseInfo); static PyObject * _wrap_g_union_info_get_fields (PyGIBaseInfo *self) { - gssize n_infos; - PyObject *infos; - gssize i; - - n_infos = g_union_info_get_n_fields ( (GIUnionInfo *) self->info); - - infos = PyTuple_New (n_infos); - if (infos == NULL) { - return NULL; - } - - for (i = 0; i < n_infos; i++) { - GIBaseInfo *info; - PyObject *py_info; - - info = (GIBaseInfo *) g_union_info_get_field ( (GIUnionInfo *) self->info, i); - g_assert (info != NULL); - - py_info = _pygi_info_new (info); - - g_base_info_unref (info); - - if (py_info == NULL) { - Py_CLEAR (infos); - break; - } - - PyTuple_SET_ITEM (infos, i, py_info); - } - - return infos; + return _make_infos_tuple (self, g_union_info_get_n_fields, g_union_info_get_field); } static PyObject * _wrap_g_union_info_get_methods (PyGIBaseInfo *self) { - gssize n_infos; - PyObject *infos; - gssize i; - - n_infos = g_union_info_get_n_methods ( (GIUnionInfo *) self->info); - - infos = PyTuple_New (n_infos); - if (infos == NULL) { - return NULL; - } - - for (i = 0; i < n_infos; i++) { - GIBaseInfo *info; - PyObject *py_info; - - info = (GIBaseInfo *) g_union_info_get_method ( (GIUnionInfo *) self->info, i); - g_assert (info != NULL); - - py_info = _pygi_info_new (info); - - g_base_info_unref (info); - - if (py_info == NULL) { - Py_CLEAR (infos); - break; - } + return _make_infos_tuple (self, g_union_info_get_n_methods, g_union_info_get_method); +} - PyTuple_SET_ITEM (infos, i, py_info); - } +static PyObject * +_wrap_g_union_info_get_size (PyGIBaseInfo *self) +{ + return pygi_gsize_to_py (g_union_info_get_size (self->info)); +} - return infos; +static PyObject * +_wrap_g_union_info_get_alignment (PyGIBaseInfo *self) +{ + return pygi_gsize_to_py (g_union_info_get_alignment (self->info)); } static PyMethodDef _PyGIUnionInfo_methods[] = { { "get_fields", (PyCFunction) _wrap_g_union_info_get_fields, METH_NOARGS }, { "get_methods", (PyCFunction) _wrap_g_union_info_get_methods, METH_NOARGS }, + { "get_size", (PyCFunction) _wrap_g_union_info_get_size, METH_NOARGS }, + { "get_alignment", (PyCFunction) _wrap_g_union_info_get_alignment, METH_NOARGS }, { NULL, NULL, 0 } }; @@ -1959,12 +2274,12 @@ _pygi_g_base_info_get_fullname (GIBaseInfo *info) if (container_info != NULL) { fullname = g_strdup_printf ("%s.%s.%s", g_base_info_get_namespace (container_info), - g_base_info_get_name (container_info), - g_base_info_get_name (info)); + _safe_base_info_get_name (container_info), + _safe_base_info_get_name (info)); } else { fullname = g_strdup_printf ("%s.%s", g_base_info_get_namespace (info), - g_base_info_get_name (info)); + _safe_base_info_get_name (info)); } if (fullname == NULL) { @@ -1974,21 +2289,28 @@ _pygi_g_base_info_get_fullname (GIBaseInfo *info) return fullname; } -void -_pygi_info_register_types (PyObject *m) + +/** + * Returns 0 on success, or -1 and sets an exception. + */ +int +pygi_info_register_types (PyObject *m) { #define _PyGI_REGISTER_TYPE(m, type, cname, base) \ - Py_TYPE(&type) = &PyType_Type; \ + Py_SET_TYPE(&type, &PyType_Type); \ type.tp_flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE); \ type.tp_weaklistoffset = offsetof(PyGIBaseInfo, inst_weakreflist); \ type.tp_methods = _PyGI##cname##_methods; \ type.tp_base = &base; \ - if (PyType_Ready(&type)) \ - return; \ - if (PyModule_AddObject(m, #cname, (PyObject *)&type)) \ - return + if (PyType_Ready(&type) < 0) \ + return -1; \ + Py_INCREF ((PyObject *)&type); \ + if (PyModule_AddObject(m, #cname, (PyObject *)&type) < 0) { \ + Py_DECREF ((PyObject *)&type); \ + return -1; \ + }; - Py_TYPE(&PyGIBaseInfo_Type) = &PyType_Type; + Py_SET_TYPE(&PyGIBaseInfo_Type, &PyType_Type); PyGIBaseInfo_Type.tp_dealloc = (destructor) _base_info_dealloc; PyGIBaseInfo_Type.tp_repr = (reprfunc) _base_info_repr; @@ -1999,36 +2321,44 @@ _pygi_info_register_types (PyObject *m) PyGIBaseInfo_Type.tp_getset = _base_info_getsets; PyGIBaseInfo_Type.tp_getattro = (getattrofunc) _base_info_getattro; - if (PyType_Ready(&PyGIBaseInfo_Type)) - return; - if (PyModule_AddObject(m, "BaseInfo", (PyObject *)&PyGIBaseInfo_Type)) - return; - - if (PyModule_AddObject(m, "DIRECTION_IN", PyLong_FromLong(GI_DIRECTION_IN))) - return; - if (PyModule_AddObject(m, "DIRECTION_OUT", PyLong_FromLong(GI_DIRECTION_OUT))) - return; - if (PyModule_AddObject(m, "DIRECTION_INOUT", PyLong_FromLong(GI_DIRECTION_INOUT))) - return; + if (PyType_Ready(&PyGIBaseInfo_Type) < 0) + return -1; + Py_INCREF ((PyObject *)&PyGIBaseInfo_Type); + if (PyModule_AddObject(m, "BaseInfo", (PyObject *)&PyGIBaseInfo_Type) < 0) { + Py_DECREF ((PyObject *)&PyGIBaseInfo_Type); + return -1; + } - _PyGI_REGISTER_TYPE (m, PyGICallableInfo_Type, CallableInfo, - PyGIBaseInfo_Type); PyGICallableInfo_Type.tp_call = (ternaryfunc) _callable_info_call; + PyGICallableInfo_Type.tp_repr = (reprfunc) _callable_info_repr; PyGICallableInfo_Type.tp_dealloc = (destructor) _callable_info_dealloc; + _PyGI_REGISTER_TYPE (m, PyGICallableInfo_Type, CallableInfo, + PyGIBaseInfo_Type); + // FIXME: this is to work around a pylint issue + // https://gitlab.gnome.org/GNOME/pygobject/issues/217 +#ifndef PYPY_VERSION _PyGI_REGISTER_TYPE (m, PyGIFunctionInfo_Type, FunctionInfo, PyGICallableInfo_Type); +#endif PyGIFunctionInfo_Type.tp_call = (ternaryfunc) _function_info_call; PyGIFunctionInfo_Type.tp_descr_get = (descrgetfunc) _function_info_descr_get; +#ifdef PYPY_VERSION + _PyGI_REGISTER_TYPE (m, PyGIFunctionInfo_Type, FunctionInfo, + PyGICallableInfo_Type); +#endif + PyGIVFuncInfo_Type.tp_descr_get = (descrgetfunc) _vfunc_info_descr_get; _PyGI_REGISTER_TYPE (m, PyGIVFuncInfo_Type, VFuncInfo, PyGICallableInfo_Type); - PyGIVFuncInfo_Type.tp_descr_get = (descrgetfunc) _vfunc_info_descr_get; + + _PyGI_REGISTER_TYPE (m, PyGISignalInfo_Type, SignalInfo, + PyGICallableInfo_Type); _PyGI_REGISTER_TYPE (m, PyGIUnresolvedInfo_Type, UnresolvedInfo, PyGIBaseInfo_Type); _PyGI_REGISTER_TYPE (m, PyGICallbackInfo_Type, CallbackInfo, - PyGIBaseInfo_Type); + PyGICallableInfo_Type); _PyGI_REGISTER_TYPE (m, PyGIRegisteredTypeInfo_Type, RegisteredTypeInfo, PyGIBaseInfo_Type); _PyGI_REGISTER_TYPE (m, PyGIStructInfo_Type, StructInfo, @@ -2047,12 +2377,8 @@ _pygi_info_register_types (PyObject *m) PyGIBaseInfo_Type); _PyGI_REGISTER_TYPE (m, PyGIUnionInfo_Type, UnionInfo, PyGIRegisteredTypeInfo_Type); - _PyGI_REGISTER_TYPE (m, PyGIBoxedInfo_Type, BoxedInfo, - PyGIBaseInfo_Type); _PyGI_REGISTER_TYPE (m, PyGIErrorDomainInfo_Type, ErrorDomainInfo, PyGIBaseInfo_Type); - _PyGI_REGISTER_TYPE (m, PyGISignalInfo_Type, SignalInfo, - PyGIBaseInfo_Type); _PyGI_REGISTER_TYPE (m, PyGIPropertyInfo_Type, PropertyInfo, PyGIBaseInfo_Type); _PyGI_REGISTER_TYPE (m, PyGIArgInfo_Type, ArgInfo, @@ -2060,6 +2386,148 @@ _pygi_info_register_types (PyObject *m) _PyGI_REGISTER_TYPE (m, PyGITypeInfo_Type, TypeInfo, PyGIBaseInfo_Type); - #undef _PyGI_REGISTER_TYPE + +#define _PyGI_ENUM_BEGIN(name) \ + { \ + const char *__enum_name = #name; \ + PyObject *__enum_value = NULL; \ + PyObject *__new_enum_cls = NULL; \ + PyObject *__enum_instance_dict = PyDict_New(); \ + PyObject *__module_name = PyObject_GetAttrString (m, "__name__"); \ + PyDict_SetItemString (__enum_instance_dict, "__module__", __module_name); \ + Py_DECREF (__module_name); + +#define _PyGI_ENUM_ADD_VALUE(prefix, name) \ + __enum_value = pygi_guint_to_py (prefix##_##name); \ + if (PyDict_SetItemString(__enum_instance_dict, #name, __enum_value) < 0) { \ + Py_DECREF (__enum_instance_dict); \ + Py_DECREF (__enum_value); \ + return -1; \ + } \ + Py_DECREF (__enum_value); + +#define _PyGI_ENUM_END \ + __new_enum_cls = PyObject_CallFunction ((PyObject *)&PyType_Type, "s(O)O", \ + __enum_name, (PyObject *)&PyType_Type, \ + __enum_instance_dict); \ + Py_DECREF (__enum_instance_dict); \ + PyModule_AddObject (m, __enum_name, __new_enum_cls); /* steals ref */ \ + } + + + /* GIDirection */ + _PyGI_ENUM_BEGIN (Direction) + _PyGI_ENUM_ADD_VALUE (GI_DIRECTION, IN) + _PyGI_ENUM_ADD_VALUE (GI_DIRECTION, OUT) + _PyGI_ENUM_ADD_VALUE (GI_DIRECTION, INOUT) + _PyGI_ENUM_END + + + /* GITransfer */ + _PyGI_ENUM_BEGIN (Transfer) + _PyGI_ENUM_ADD_VALUE (GI_TRANSFER, NOTHING) + _PyGI_ENUM_ADD_VALUE (GI_TRANSFER, CONTAINER) + _PyGI_ENUM_ADD_VALUE (GI_TRANSFER, EVERYTHING) + _PyGI_ENUM_END + + /* GIArrayType */ + _PyGI_ENUM_BEGIN (ArrayType) + _PyGI_ENUM_ADD_VALUE (GI_ARRAY_TYPE, C) + _PyGI_ENUM_ADD_VALUE (GI_ARRAY_TYPE, ARRAY) + _PyGI_ENUM_ADD_VALUE (GI_ARRAY_TYPE, PTR_ARRAY) + _PyGI_ENUM_ADD_VALUE (GI_ARRAY_TYPE, BYTE_ARRAY) + _PyGI_ENUM_END + + /* GIScopeType */ + _PyGI_ENUM_BEGIN (ScopeType) + _PyGI_ENUM_ADD_VALUE (GI_SCOPE_TYPE, INVALID) + _PyGI_ENUM_ADD_VALUE (GI_SCOPE_TYPE, CALL) + _PyGI_ENUM_ADD_VALUE (GI_SCOPE_TYPE, ASYNC) + _PyGI_ENUM_ADD_VALUE (GI_SCOPE_TYPE, NOTIFIED) + _PyGI_ENUM_END + + /* GIVFuncInfoFlags */ + _PyGI_ENUM_BEGIN (VFuncInfoFlags) + _PyGI_ENUM_ADD_VALUE (GI_VFUNC_MUST, CHAIN_UP) + _PyGI_ENUM_ADD_VALUE (GI_VFUNC_MUST, OVERRIDE) + _PyGI_ENUM_ADD_VALUE (GI_VFUNC_MUST, NOT_OVERRIDE) + _PyGI_ENUM_END + + /* GIFieldInfoFlags */ + _PyGI_ENUM_BEGIN (FieldInfoFlags) + _PyGI_ENUM_ADD_VALUE (GI_FIELD, IS_READABLE) + _PyGI_ENUM_ADD_VALUE (GI_FIELD, IS_WRITABLE) + _PyGI_ENUM_END + + /* GIFunctionInfoFlags */ + _PyGI_ENUM_BEGIN (FunctionInfoFlags) + _PyGI_ENUM_ADD_VALUE (GI_FUNCTION, IS_METHOD) + _PyGI_ENUM_ADD_VALUE (GI_FUNCTION, IS_CONSTRUCTOR) + _PyGI_ENUM_ADD_VALUE (GI_FUNCTION, IS_GETTER) + _PyGI_ENUM_ADD_VALUE (GI_FUNCTION, IS_SETTER) + _PyGI_ENUM_ADD_VALUE (GI_FUNCTION, WRAPS_VFUNC) + _PyGI_ENUM_ADD_VALUE (GI_FUNCTION, THROWS) + _PyGI_ENUM_END + + /* GITypeTag */ + _PyGI_ENUM_BEGIN (TypeTag) + /* Basic types */ + _PyGI_ENUM_ADD_VALUE (GI_TYPE_TAG, VOID) + _PyGI_ENUM_ADD_VALUE (GI_TYPE_TAG, BOOLEAN) + _PyGI_ENUM_ADD_VALUE (GI_TYPE_TAG, INT8) + _PyGI_ENUM_ADD_VALUE (GI_TYPE_TAG, UINT8) + _PyGI_ENUM_ADD_VALUE (GI_TYPE_TAG, INT16) + _PyGI_ENUM_ADD_VALUE (GI_TYPE_TAG, UINT16) + _PyGI_ENUM_ADD_VALUE (GI_TYPE_TAG, INT32) + _PyGI_ENUM_ADD_VALUE (GI_TYPE_TAG, UINT32) + _PyGI_ENUM_ADD_VALUE (GI_TYPE_TAG, INT64) + _PyGI_ENUM_ADD_VALUE (GI_TYPE_TAG, UINT64) + _PyGI_ENUM_ADD_VALUE (GI_TYPE_TAG, FLOAT) + _PyGI_ENUM_ADD_VALUE (GI_TYPE_TAG, DOUBLE) + _PyGI_ENUM_ADD_VALUE (GI_TYPE_TAG, GTYPE) + _PyGI_ENUM_ADD_VALUE (GI_TYPE_TAG, UTF8) + _PyGI_ENUM_ADD_VALUE (GI_TYPE_TAG, FILENAME) + + /* Non-basic types; compare with G_TYPE_TAG_IS_BASIC */ + _PyGI_ENUM_ADD_VALUE (GI_TYPE_TAG, ARRAY) + _PyGI_ENUM_ADD_VALUE (GI_TYPE_TAG, INTERFACE) + _PyGI_ENUM_ADD_VALUE (GI_TYPE_TAG, GLIST) + _PyGI_ENUM_ADD_VALUE (GI_TYPE_TAG, GSLIST) + _PyGI_ENUM_ADD_VALUE (GI_TYPE_TAG, GHASH) + _PyGI_ENUM_ADD_VALUE (GI_TYPE_TAG, ERROR) + + /* Another basic type */ + _PyGI_ENUM_ADD_VALUE (GI_TYPE_TAG, UNICHAR) + _PyGI_ENUM_END + + /* GIInfoType */ + _PyGI_ENUM_BEGIN (InfoType) + _PyGI_ENUM_ADD_VALUE (GI_INFO_TYPE, INVALID) + _PyGI_ENUM_ADD_VALUE (GI_INFO_TYPE, FUNCTION) + _PyGI_ENUM_ADD_VALUE (GI_INFO_TYPE, CALLBACK) + _PyGI_ENUM_ADD_VALUE (GI_INFO_TYPE, STRUCT) + _PyGI_ENUM_ADD_VALUE (GI_INFO_TYPE, BOXED) + _PyGI_ENUM_ADD_VALUE (GI_INFO_TYPE, ENUM) + _PyGI_ENUM_ADD_VALUE (GI_INFO_TYPE, FLAGS) + _PyGI_ENUM_ADD_VALUE (GI_INFO_TYPE, OBJECT) + _PyGI_ENUM_ADD_VALUE (GI_INFO_TYPE, INTERFACE) + _PyGI_ENUM_ADD_VALUE (GI_INFO_TYPE, CONSTANT) + _PyGI_ENUM_ADD_VALUE (GI_INFO_TYPE, INVALID_0) + _PyGI_ENUM_ADD_VALUE (GI_INFO_TYPE, UNION) + _PyGI_ENUM_ADD_VALUE (GI_INFO_TYPE, VALUE) + _PyGI_ENUM_ADD_VALUE (GI_INFO_TYPE, SIGNAL) + _PyGI_ENUM_ADD_VALUE (GI_INFO_TYPE, VFUNC) + _PyGI_ENUM_ADD_VALUE (GI_INFO_TYPE, PROPERTY) + _PyGI_ENUM_ADD_VALUE (GI_INFO_TYPE, FIELD) + _PyGI_ENUM_ADD_VALUE (GI_INFO_TYPE, ARG) + _PyGI_ENUM_ADD_VALUE (GI_INFO_TYPE, TYPE) + _PyGI_ENUM_ADD_VALUE (GI_INFO_TYPE, UNRESOLVED) + _PyGI_ENUM_END + +#undef _PyGI_ENUM_BEGIN +#undef _PyGI_ENUM_ADD_VALUE +#undef _PyGI_ENUM_END + + return 0; } diff --git a/gi/pygi-info.h b/gi/pygi-info.h index d550d8d..12ef491 100644 --- a/gi/pygi-info.h +++ b/gi/pygi-info.h @@ -14,9 +14,7 @@ * 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 + * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ #ifndef __PYGI_INFO_H__ @@ -25,9 +23,31 @@ #include <Python.h> #include <girepository.h> +#include "pygi-cache.h" G_BEGIN_DECLS +typedef struct { + PyObject_HEAD + GIBaseInfo *info; + PyObject *inst_weakreflist; + PyGICallableCache *cache; +} PyGIBaseInfo; + +typedef struct { + PyGIBaseInfo base; + + /* Reference the unbound version of this struct. + * We use this for the actual call to invoke because it manages the cache. + */ + struct PyGICallableInfo *py_unbound_info; + + /* Holds bound argument for instance, class, and vfunc methods. */ + PyObject *py_bound_arg; + +} PyGICallableInfo; + + gboolean pygi_g_struct_info_is_simple (GIStructInfo *struct_info); @@ -66,7 +86,7 @@ gchar* _pygi_g_base_info_get_fullname (GIBaseInfo *info); gsize _pygi_g_type_tag_size (GITypeTag type_tag); gsize _pygi_g_type_info_size (GITypeInfo *type_info); -void _pygi_info_register_types (PyObject *m); +int pygi_info_register_types (PyObject *m); gboolean _pygi_is_python_keyword (const gchar *name); diff --git a/gi/pygi-invoke-state-struct.h b/gi/pygi-invoke-state-struct.h index 1d9e49c..dbf4e66 100644 --- a/gi/pygi-invoke-state-struct.h +++ b/gi/pygi-invoke-state-struct.h @@ -7,42 +7,60 @@ G_BEGIN_DECLS +typedef struct _PyGIInvokeArgState +{ + /* Holds memory for the C value of arguments marshaled "to" or "from" Python. */ + GIArgument arg_value; + + /* Holds pointers to values in arg_values or a caller allocated chunk of + * memory via arg_pointer.v_pointer. + */ + GIArgument arg_pointer; + + /* Holds from_py marshaler cleanup data. */ + gpointer arg_cleanup_data; + + /* Holds to_py marshaler cleanup data. */ + gpointer to_py_arg_cleanup_data; +} PyGIInvokeArgState; + + typedef struct _PyGIInvokeState { PyObject *py_in_args; gssize n_py_in_args; - gssize current_arg; - - GType implementor_gtype; - - GIArgument **args; - GIArgument *in_args; - - /* Generic array allocated to the same length as args - * for use as extra per-arg state data. */ - gpointer *args_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. + + /* 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 args[x].arg_pointer.v_pointer + * member points to memory for the value storage. */ - GIArgument *out_args; - GIArgument *out_values; + GIArgument **ffi_args; + + /* Array of size n_args containing per argument state */ + PyGIInvokeArgState *args; + /* Memory to receive the result of the C ffi function call. */ GIArgument return_arg; + gpointer to_py_return_arg_cleanup_data; + /* 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 17cd278..7b822e4 100644 --- a/gi/pygi-invoke.c +++ b/gi/pygi-invoke.c @@ -17,87 +17,20 @@ * 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 + * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ -#include <pyglib.h> #include "pygi-invoke.h" #include "pygi-marshal-cleanup.h" +#include "pygi-error.h" +#include "pygi-resulttuple.h" +#include "pygi-foreign.h" +#include "pygi-boxed.h" -static inline gboolean -_invoke_callable (PyGIInvokeState *state, - PyGICallableCache *cache, - GICallableInfo *callable_info, - GCallback function_ptr) -{ - GError *error; - gint retval; - - error = NULL; - - 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); - - return FALSE; - } - - if (state->error != NULL) { - if (pyglib_error_check (&(state->error))) { - /* even though we errored out, the call itself was successful, - so we assume the call processed all of the parameters */ - pygi_marshal_cleanup_args_from_py_marshal_success (state, cache); - return FALSE; - } - } - - return TRUE; -} +extern PyObject *_PyGIDefaultArgPlaceholder; static gboolean -_check_for_unexpected_kwargs (const gchar *function_name, +_check_for_unexpected_kwargs (PyGICallableCache *cache, GHashTable *arg_name_hash, PyObject *py_kwargs) { @@ -107,12 +40,6 @@ _check_for_unexpected_kwargs (const gchar *function_name, while (PyDict_Next (py_kwargs, &dict_iter_pos, &dict_key, &dict_value)) { PyObject *key; -#if PY_VERSION_HEX < 0x03000000 - if (PyString_Check (dict_key)) { - Py_INCREF (dict_key); - key = dict_key; - } else -#endif { key = PyUnicode_AsUTF8String (dict_key); if (key == NULL) { @@ -120,12 +47,18 @@ _check_for_unexpected_kwargs (const gchar *function_name, } } - if (g_hash_table_lookup (arg_name_hash, PyBytes_AsString(key)) == NULL) { + /* Use extended lookup because it returns whether or not the key actually + * exists in the hash table. g_hash_table_lookup returns NULL for keys not + * found which maps to index 0 for our hash lookup. + */ + if (!g_hash_table_lookup_extended (arg_name_hash, PyBytes_AsString(key), NULL, NULL)) { + char *full_name = pygi_callable_cache_get_full_name (cache); PyErr_Format (PyExc_TypeError, "%.200s() got an unexpected keyword argument '%.400s'", - function_name, + full_name, PyBytes_AsString (key)); Py_DECREF (key); + g_free (full_name); return FALSE; } @@ -149,9 +82,8 @@ _py_args_combine_and_check_length (PyGICallableCache *cache, { PyObject *combined_py_args = NULL; Py_ssize_t n_py_args, n_py_kwargs, i; - guint n_expected_args; + gssize n_expected_args = cache->n_py_args; GSList *l; - const gchar *function_name = cache->name; n_py_args = PyTuple_GET_SIZE (py_args); if (py_kwargs == NULL) @@ -160,24 +92,34 @@ _py_args_combine_and_check_length (PyGICallableCache *cache, n_py_kwargs = PyDict_Size (py_kwargs); /* Fast path, we already have the exact number of args and not kwargs. */ - n_expected_args = g_slist_length (cache->arg_name_list); - if (n_py_kwargs == 0 && n_py_args == n_expected_args) { + if (n_py_kwargs == 0 && n_py_args == n_expected_args && cache->user_data_varargs_index < 0) { Py_INCREF (py_args); return py_args; } - if (n_expected_args < n_py_args) { + if (cache->user_data_varargs_index < 0 && n_expected_args < n_py_args) { + char *full_name = pygi_callable_cache_get_full_name (cache); PyErr_Format (PyExc_TypeError, - "%.200s() takes exactly %d %sargument%s (%zd given)", - function_name, + "%.200s() takes exactly %zd %sargument%s (%zd given)", + full_name, n_expected_args, n_py_kwargs > 0 ? "non-keyword " : "", n_expected_args == 1 ? "" : "s", n_py_args); + g_free (full_name); return NULL; } - if (n_py_kwargs > 0 && !_check_for_unexpected_kwargs (function_name, + if (cache->user_data_varargs_index >= 0 && n_py_kwargs > 0 && n_expected_args < n_py_args) { + char *full_name = pygi_callable_cache_get_full_name (cache); + PyErr_Format (PyExc_TypeError, + "%.200s() cannot use variable user data arguments with keyword arguments", + full_name); + g_free (full_name); + return NULL; + } + + if (n_py_kwargs > 0 && !_check_for_unexpected_kwargs (cache, cache->arg_name_hash, py_kwargs)) { return NULL; @@ -187,46 +129,84 @@ _py_args_combine_and_check_length (PyGICallableCache *cache, * when they are combined into a single tuple */ combined_py_args = PyTuple_New (n_expected_args); - for (i = 0; i < n_py_args; i++) { - PyObject *item = PyTuple_GET_ITEM (py_args, i); - Py_INCREF (item); - PyTuple_SET_ITEM (combined_py_args, i, item); - } - for (i = 0, l = cache->arg_name_list; i < n_expected_args && l; i++, l = l->next) { - PyObject *py_arg_item, *kw_arg_item = NULL; + PyObject *py_arg_item = NULL; + PyObject *kw_arg_item = NULL; const gchar *arg_name = l->data; + int arg_cache_index = -1; + gboolean is_varargs_user_data = FALSE; + + if (arg_name != NULL) + arg_cache_index = GPOINTER_TO_INT (g_hash_table_lookup (cache->arg_name_hash, arg_name)); + + is_varargs_user_data = cache->user_data_varargs_index >= 0 && + arg_cache_index == cache->user_data_varargs_index; if (n_py_kwargs > 0 && arg_name != NULL) { /* NULL means this argument has no keyword name */ /* ex. the first argument to a method or constructor */ kw_arg_item = PyDict_GetItemString (py_kwargs, arg_name); } - py_arg_item = PyTuple_GET_ITEM (combined_py_args, i); - if (kw_arg_item != NULL && py_arg_item == NULL) { - Py_INCREF (kw_arg_item); - PyTuple_SET_ITEM (combined_py_args, i, kw_arg_item); + /* use a bounded retrieval of the original input */ + if (i < n_py_args) + py_arg_item = PyTuple_GET_ITEM (py_args, i); + + if (kw_arg_item == NULL && py_arg_item != NULL) { + if (is_varargs_user_data) { + /* For tail end user_data varargs, pull a slice off and we are done. */ + PyObject *user_data = PyTuple_GetSlice (py_args, i, PY_SSIZE_T_MAX); + PyTuple_SET_ITEM (combined_py_args, i, user_data); + return combined_py_args; + } else { + Py_INCREF (py_arg_item); + PyTuple_SET_ITEM (combined_py_args, i, py_arg_item); + } + } else if (kw_arg_item != NULL && py_arg_item == NULL) { + if (is_varargs_user_data) { + /* Special case where user_data is passed as a keyword argument (user_data=foo) + * Wrap the value in a tuple to represent variable args for marshaling later on. + */ + PyObject *user_data = Py_BuildValue("(O)", kw_arg_item, NULL); + PyTuple_SET_ITEM (combined_py_args, i, user_data); + } else { + Py_INCREF (kw_arg_item); + PyTuple_SET_ITEM (combined_py_args, i, kw_arg_item); + } } else if (kw_arg_item == NULL && py_arg_item == NULL) { - PyErr_Format (PyExc_TypeError, - "%.200s() takes exactly %d %sargument%s (%zd given)", - function_name, - n_expected_args, - n_py_kwargs > 0 ? "non-keyword " : "", - n_expected_args == 1 ? "" : "s", - n_py_args); - - Py_DECREF (combined_py_args); - return NULL; - + if (is_varargs_user_data) { + /* For varargs user_data, pass an empty tuple when nothing is given. */ + PyTuple_SET_ITEM (combined_py_args, i, PyTuple_New (0)); + } else if (arg_cache_index >= 0 && _pygi_callable_cache_get_arg (cache, arg_cache_index)->has_default) { + /* If the argument supports a default, use a place holder in the + * argument tuple, this will be checked later during marshaling. + */ + Py_INCREF (_PyGIDefaultArgPlaceholder); + PyTuple_SET_ITEM (combined_py_args, i, _PyGIDefaultArgPlaceholder); + } else { + char *full_name = pygi_callable_cache_get_full_name (cache); + PyErr_Format (PyExc_TypeError, + "%.200s() takes exactly %zd %sargument%s (%zd given)", + full_name, + n_expected_args, + n_py_kwargs > 0 ? "non-keyword " : "", + n_expected_args == 1 ? "" : "s", + n_py_args); + g_free (full_name); + + Py_DECREF (combined_py_args); + return NULL; + } } else if (kw_arg_item != NULL && py_arg_item != NULL) { + char *full_name = pygi_callable_cache_get_full_name (cache); PyErr_Format (PyExc_TypeError, "%.200s() got multiple values for keyword argument '%.200s'", - function_name, + full_name, arg_name); Py_DECREF (combined_py_args); + g_free (full_name); return NULL; } } @@ -234,209 +214,230 @@ _py_args_combine_and_check_length (PyGICallableCache *cache, return combined_py_args; } -static inline gboolean -_invoke_state_init_from_callable_cache (PyGIInvokeState *state, - PyGICallableCache *cache, - PyObject *py_args, - PyObject *kwargs) -{ - PyObject *combined_args = NULL; - state->implementor_gtype = 0; - - /* 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 - * around if we want to call actual gobject constructors - * in the future instead of calling g_object_new - */ - if (cache->function_type == PYGI_FUNCTION_TYPE_CONSTRUCTOR) { - PyObject *constructor_class; - constructor_class = PyTuple_GetItem (py_args, 0); - - if (constructor_class == NULL) { - PyErr_Clear (); - PyErr_Format (PyExc_TypeError, - "Constructors require the class to be passed in as an argument, " - "No arguments passed to the %s constructor.", - cache->name); - - return FALSE; - } - } else if (cache->function_type == PYGI_FUNCTION_TYPE_VFUNC) { - PyObject *py_gtype; - py_gtype = PyTuple_GetItem (py_args, 0); - if (py_gtype == NULL) { - PyErr_SetString (PyExc_TypeError, - "need the GType of the implementor class"); - return FALSE; - } +/* To reduce calls to g_slice_*() we (1) allocate all the memory depended on + * the argument count in one go and (2) keep one version per argument count + * around for faster reuse. + */ - state->implementor_gtype = pyg_type_from_object (py_gtype); +#define PyGI_INVOKE_ARG_STATE_SIZE(n) (n * (sizeof (PyGIInvokeArgState) + sizeof (GIArgument *))) +#define PyGI_INVOKE_ARG_STATE_N_MAX 10 +static gpointer free_arg_state[PyGI_INVOKE_ARG_STATE_N_MAX]; - if (state->implementor_gtype == 0) - return FALSE; - } +/** + * _pygi_invoke_arg_state_init: + * Sets PyGIInvokeState.args and PyGIInvokeState.ffi_args. + * On error returns FALSE and sets an exception. + */ +gboolean +_pygi_invoke_arg_state_init (PyGIInvokeState *state) { - if (cache->function_type == PYGI_FUNCTION_TYPE_CONSTRUCTOR || - cache->function_type == PYGI_FUNCTION_TYPE_VFUNC) { + gpointer mem; - /* we could optimize this by using offsets instead of modifying the tuple but it makes the - * code more error prone and confusing so don't do that unless profiling shows - * significant gain - */ - combined_args = PyTuple_GetSlice (py_args, 1, PyTuple_Size (py_args)); + if (state->n_args < PyGI_INVOKE_ARG_STATE_N_MAX && (mem = free_arg_state[state->n_args]) != NULL) { + free_arg_state[state->n_args] = NULL; + memset (mem, 0, PyGI_INVOKE_ARG_STATE_SIZE (state->n_args)); } else { - combined_args = py_args; - Py_INCREF (combined_args); + mem = g_slice_alloc0 (PyGI_INVOKE_ARG_STATE_SIZE (state->n_args)); } - state->py_in_args = _py_args_combine_and_check_length (cache, - combined_args, - kwargs); - Py_DECREF (combined_args); - - if (state->py_in_args == NULL) { + if (mem == NULL && state->n_args != 0) { + PyErr_NoMemory(); return FALSE; } - state->n_py_in_args = PyTuple_Size (state->py_in_args); - state->args = g_slice_alloc0 (cache->n_args * sizeof (GIArgument *)); - if (state->args == NULL && cache->n_args != 0) { - PyErr_NoMemory(); - return FALSE; + if (mem != NULL) { + state->args = mem; + state->ffi_args = (gpointer)((gchar *)mem + state->n_args * sizeof (PyGIInvokeArgState)); } - state->args_data = g_slice_alloc0 (cache->n_args * sizeof (gpointer)); - if (state->args_data == NULL && cache->n_args != 0) { - PyErr_NoMemory(); - return FALSE; + return TRUE; +} + +/** + * _pygi_invoke_arg_state_free: + * Frees PyGIInvokeState.args and PyGIInvokeState.ffi_args + */ +void +_pygi_invoke_arg_state_free(PyGIInvokeState *state) { + if (state->n_args < PyGI_INVOKE_ARG_STATE_N_MAX && free_arg_state[state->n_args] == NULL) { + free_arg_state[state->n_args] = state->args; + return; } - state->in_args = g_slice_alloc0 (cache->n_from_py_args * sizeof(GIArgument)); - if (state->in_args == NULL && cache->n_from_py_args != 0) { - PyErr_NoMemory (); - return FALSE; + g_slice_free1 (PyGI_INVOKE_ARG_STATE_SIZE (state->n_args), state->args); +} + +static gboolean +_invoke_state_init_from_cache (PyGIInvokeState *state, + PyGIFunctionCache *function_cache, + PyObject *py_args, + PyObject *kwargs) +{ + PyGICallableCache *cache = (PyGICallableCache *) function_cache; + + state->n_args = _pygi_callable_cache_args_len (cache); + + if (cache->throws) { + state->n_args++; } - 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 (); + /* Copy the function pointer to the state for the normal case. For vfuncs, + * this has already been filled out based on the implementor's GType. + */ + if (state->function_ptr == NULL) + state->function_ptr = function_cache->invoker.native_address; + + state->py_in_args = _py_args_combine_and_check_length (cache, + py_args, + kwargs); + + if (state->py_in_args == NULL) { return FALSE; } + state->n_py_in_args = PyTuple_Size (state->py_in_args); - state->out_args = g_slice_alloc0 (cache->n_to_py_args * sizeof(GIArgument)); - if (state->out_args == NULL && cache->n_to_py_args != 0) { - PyErr_NoMemory (); + if (!_pygi_invoke_arg_state_init (state)) { 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->args[error_index].arg_pointer.v_pointer = &state->error; + state->ffi_args[error_index] = &(state->args[error_index].arg_pointer); + } + return TRUE; } -static inline void -_invoke_state_clear (PyGIInvokeState *state, PyGICallableCache *cache) +static void +_invoke_state_clear (PyGIInvokeState *state, PyGIFunctionCache *function_cache) { - g_slice_free1 (cache->n_args * sizeof(GIArgument *), state->args); - g_slice_free1 (cache->n_args * sizeof(gpointer), state->args_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); - + _pygi_invoke_arg_state_free (state); 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 = - _pygi_boxed_alloc (iface_cache->interface_info, NULL); + 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 ( iface_cache->interface_info, + GI_TRANSFER_NOTHING, NULL); 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) { - PyGISequenceCache *seq_cache = (PyGISequenceCache *)arg_cache; + PyGIArgGArray *array_cache = (PyGIArgGArray *)arg_cache; - state->out_args[out_count].v_pointer = g_array_new (TRUE, TRUE, seq_cache->item_size); - state->args[arg_count] = &state->out_args[out_count]; + arg->v_pointer = g_array_new (TRUE, TRUE, (guint)array_cache->item_size); } else { return FALSE; } - if (state->args[arg_count]->v_pointer == NULL) + if (arg->v_pointer == NULL) return FALSE; return TRUE; } -static inline gboolean -_invoke_marshal_in_args (PyGIInvokeState *state, PyGICallableCache *cache) +/* pygi_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 gboolean +_invoke_marshal_in_args (PyGIInvokeState *state, PyGIFunctionCache *function_cache) { - gssize i, in_count, out_count; - in_count = 0; - out_count = 0; + PyGICallableCache *cache = (PyGICallableCache *) function_cache; + gssize i; if (state->n_py_in_args > cache->n_py_args) { + char *full_name = pygi_callable_cache_get_full_name (cache); PyErr_Format (PyExc_TypeError, "%s() takes exactly %zd argument(s) (%zd given)", - cache->name, + full_name, cache->n_py_args, state->n_py_in_args); + g_free (full_name); return FALSE; } - for (i = 0; i < cache->n_args; i++) { - GIArgument *c_arg; - PyGIArgCache *arg_cache = cache->args_cache[i]; + for (i = 0; (gsize)i < _pygi_callable_cache_args_len (cache); i++) { + GIArgument *c_arg = &state->args[i].arg_value; + 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->ffi_args[i] = c_arg; if (arg_cache->meta_type == PYGI_META_ARG_TYPE_CLOSURE) { - state->args[i]->v_pointer = state->user_data; + state->ffi_args[i]->v_pointer = state->user_data; continue; } else if (arg_cache->meta_type != PYGI_META_ARG_TYPE_PARENT) continue; if (arg_cache->py_arg_index >= state->n_py_in_args) { + char *full_name = pygi_callable_cache_get_full_name (cache); PyErr_Format (PyExc_TypeError, "%s() takes exactly %zd argument(s) (%zd given)", - cache->name, + full_name, cache->n_py_args, state->n_py_in_args); + g_free (full_name); /* clean up all of the args we have already marshalled, * since invoke will not be called */ pygi_marshal_cleanup_args_from_py_parameter_fail (state, cache, - i - 1); + i); return FALSE; } @@ -446,23 +447,18 @@ _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) { + char *full_name = pygi_callable_cache_get_full_name (cache); PyErr_Format (PyExc_TypeError, "%s() takes exactly %zd argument(s) (%zd given)", - cache->name, + full_name, cache->n_py_args, state->n_py_in_args); + g_free (full_name); pygi_marshal_cleanup_args_from_py_parameter_fail (state, cache, - i - 1); + i); return FALSE; } @@ -470,28 +466,56 @@ _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->args[i].arg_pointer.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->ffi_args[i] = c_arg; + + if (!_caller_alloc (arg_cache, c_arg)) { + char *full_name = pygi_callable_cache_get_full_name (cache); PyErr_Format (PyExc_TypeError, "Could not caller allocate argument %zd of callable %s", - i, cache->name); + i, full_name); + g_free (full_name); pygi_marshal_cleanup_args_from_py_parameter_fail (state, cache, - i - 1); + i); 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->ffi_args[i] = &state->args[i].arg_pointer; } - out_count++; + + break; + default: + g_assert_not_reached(); break; } - c_arg = state->args[i]; - if (arg_cache->from_py_marshaller != NULL) { + if (py_arg == _PyGIDefaultArgPlaceholder) { + *c_arg = arg_cache->default_value; + } else if (arg_cache->from_py_marshaller != NULL && + arg_cache->meta_type != PYGI_META_ARG_TYPE_CHILD) { gboolean success; + gpointer cleanup_data = NULL; + if (!arg_cache->allow_none && py_arg == Py_None) { PyErr_Format (PyExc_TypeError, "Argument %zd does not allow None as a value", @@ -499,18 +523,21 @@ _invoke_marshal_in_args (PyGIInvokeState *state, PyGICallableCache *cache) pygi_marshal_cleanup_args_from_py_parameter_fail (state, cache, - i - 1); + i); return FALSE; } success = arg_cache->from_py_marshaller (state, - cache, - arg_cache, - py_arg, - c_arg); + cache, + arg_cache, + py_arg, + c_arg, + &cleanup_data); + state->args[i].arg_cleanup_data = cleanup_data; + if (!success) { pygi_marshal_cleanup_args_from_py_parameter_fail (state, cache, - i - 1); + i); return FALSE; } @@ -521,57 +548,44 @@ _invoke_marshal_in_args (PyGIInvokeState *state, PyGICallableCache *cache) return TRUE; } -static inline PyObject * -_invoke_marshal_out_args (PyGIInvokeState *state, PyGICallableCache *cache) +static PyObject * +_invoke_marshal_out_args (PyGIInvokeState *state, PyGIFunctionCache *function_cache) { + PyGICallableCache *cache = (PyGICallableCache *) function_cache; PyObject *py_out = NULL; PyObject *py_return = NULL; - gssize total_out_args = cache->n_to_py_args; - gboolean has_return = FALSE; + gssize n_out_args = cache->n_to_py_args - cache->n_to_py_child_args; if (cache->return_cache) { if (!cache->return_cache->is_skipped) { - if (cache->function_type == PYGI_FUNCTION_TYPE_CONSTRUCTOR) { - if (state->return_arg.v_pointer == NULL) { - PyErr_SetString (PyExc_TypeError, "constructor returned NULL"); - pygi_marshal_cleanup_args_return_fail (state, - cache); - return NULL; - } - } - + gpointer cleanup_data = NULL; py_return = cache->return_cache->to_py_marshaller ( state, cache, cache->return_cache, - &state->return_arg); + &state->return_arg, + &cleanup_data); + state->to_py_return_arg_cleanup_data = cleanup_data; if (py_return == NULL) { pygi_marshal_cleanup_args_return_fail (state, cache); return NULL; } - - - if (cache->return_cache->type_tag != GI_TYPE_TAG_VOID) { - total_out_args++; - has_return = TRUE; - } } else { if (cache->return_cache->transfer == GI_TRANSFER_EVERYTHING) { - PyGIMarshalCleanupFunc to_py_cleanup = + PyGIMarshalToPyCleanupFunc to_py_cleanup = cache->return_cache->to_py_cleanup; if (to_py_cleanup != NULL) to_py_cleanup ( state, cache->return_cache, + NULL, &state->return_arg, FALSE); } } } - total_out_args -= cache->n_to_py_child_args; - - if (cache->n_to_py_args - cache->n_to_py_child_args == 0) { + if (n_out_args == 0) { if (cache->return_cache->is_skipped && state->error == NULL) { /* we skip the return value and have no (out) arguments to return, * so py_return should be NULL. But we must not return NULL, @@ -583,13 +597,16 @@ _invoke_marshal_out_args (PyGIInvokeState *state, PyGICallableCache *cache) } py_out = py_return; - } else if (total_out_args == 1) { + } else if (!cache->has_return && n_out_args == 1) { /* if we get here there is one out arg an no return */ PyGIArgCache *arg_cache = (PyGIArgCache *)cache->to_py_args->data; + gpointer cleanup_data = NULL; py_out = arg_cache->to_py_marshaller (state, cache, arg_cache, - state->args[arg_cache->c_arg_index]); + state->args[arg_cache->c_arg_index].arg_pointer.v_pointer, + &cleanup_data); + state->args[arg_cache->c_arg_index].to_py_arg_cleanup_data = cleanup_data; if (py_out == NULL) { pygi_marshal_cleanup_args_to_py_parameter_fail (state, cache, @@ -598,26 +615,39 @@ _invoke_marshal_out_args (PyGIInvokeState *state, PyGICallableCache *cache) } } else { + /* return a tuple */ gssize py_arg_index = 0; GSList *cache_item = cache->to_py_args; - /* return a tuple */ - py_out = PyTuple_New (total_out_args); - if (has_return) { + gssize tuple_len = cache->has_return + n_out_args; + + py_out = pygi_resulttuple_new (cache->resulttuple_type, tuple_len); + + if (py_out == NULL) { + pygi_marshal_cleanup_args_to_py_parameter_fail (state, + cache, + py_arg_index); + return NULL; + } + + if (cache->has_return) { PyTuple_SET_ITEM (py_out, py_arg_index, py_return); py_arg_index++; } - for(; py_arg_index < total_out_args; py_arg_index++) { + for (; py_arg_index < tuple_len; py_arg_index++) { PyGIArgCache *arg_cache = (PyGIArgCache *)cache_item->data; + gpointer cleanup_data = NULL; PyObject *py_obj = arg_cache->to_py_marshaller (state, cache, arg_cache, - state->args[arg_cache->c_arg_index]); + state->args[arg_cache->c_arg_index].arg_pointer.v_pointer, + &cleanup_data); + state->args[arg_cache->c_arg_index].to_py_arg_cleanup_data = cleanup_data; if (py_obj == NULL) { - if (has_return) + if (cache->has_return) py_arg_index--; - + pygi_marshal_cleanup_args_to_py_parameter_fail (state, cache, py_arg_index); @@ -633,44 +663,103 @@ _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) +pygi_invoke_c_callable (PyGIFunctionCache *function_cache, + PyGIInvokeState *state, + PyObject *py_args, + PyObject *py_kwargs) { - PyGIInvokeState state = { 0, }; + PyGICallableCache *cache = (PyGICallableCache *) function_cache; + GIFFIReturnValue ffi_return_value = {0}; PyObject *ret = NULL; - if (!_invoke_state_init_from_callable_cache (&state, cache, py_args, kwargs)) - goto err; + if (!_invoke_state_init_from_cache (state, function_cache, + py_args, py_kwargs)) + goto err; - if (cache->function_type == PYGI_FUNCTION_TYPE_CCALLBACK) - state.user_data = user_data; + if (!_invoke_marshal_in_args (state, function_cache)) + goto err; - if (!_invoke_marshal_in_args (&state, cache)) - goto err; + Py_BEGIN_ALLOW_THREADS; - if (!_invoke_callable (&state, cache, info, function_ptr)) - goto err; + ffi_call (&function_cache->invoker.cif, + state->function_ptr, + (void *) &ffi_return_value, + (void **) state->ffi_args); - pygi_marshal_cleanup_args_from_py_marshal_success (&state, cache); + 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 (pygi_error_check (&state->error)) { + /* even though we errored out, the call itself was successful, + so we assume the call processed all of the parameters */ + pygi_marshal_cleanup_args_from_py_marshal_success (state, cache); + goto err; + } + } + + if (cache->return_cache) { + gi_type_info_extract_ffi_return_value (cache->return_cache->type_info, + &ffi_return_value, + &state->return_arg); + } + + ret = _invoke_marshal_out_args (state, function_cache); + pygi_marshal_cleanup_args_from_py_marshal_success (state, cache); + + if (ret != NULL) + pygi_marshal_cleanup_args_to_py_marshal_success (state, cache); - ret = _invoke_marshal_out_args (&state, cache); - if (ret) - pygi_marshal_cleanup_args_to_py_marshal_success (&state, cache); err: - _invoke_state_clear (&state, cache); + _invoke_state_clear (state, function_cache); return ret; } PyObject * +pygi_callable_info_invoke (GIBaseInfo *info, PyObject *py_args, + PyObject *kwargs, PyGICallableCache *cache, + gpointer user_data) +{ + return pygi_function_cache_invoke ((PyGIFunctionCache *) cache, + py_args, kwargs); +} + +PyObject * _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); + PyGIFunctionCache *function_cache; + GIInfoType type = g_base_info_get_type (self->info); + + if (type == GI_INFO_TYPE_FUNCTION) { + GIFunctionInfoFlags flags; + + flags = g_function_info_get_flags ( (GIFunctionInfo *)self->info); + + if (flags & GI_FUNCTION_IS_CONSTRUCTOR) { + function_cache = pygi_constructor_cache_new (self->info); + } else if (flags & GI_FUNCTION_IS_METHOD) { + function_cache = pygi_method_cache_new (self->info); + } else { + function_cache = pygi_function_cache_new (self->info); + } + } else if (type == GI_INFO_TYPE_VFUNC) { + function_cache = pygi_vfunc_cache_new (self->info); + } else if (type == GI_INFO_TYPE_CALLBACK) { + g_error ("Cannot invoke callback types"); + } else { + function_cache = pygi_method_cache_new (self->info); + } + + self->cache = (PyGICallableCache *)function_cache; 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..aa51f3f 100644 --- a/gi/pygi-invoke.h +++ b/gi/pygi-invoke.h @@ -14,9 +14,7 @@ * 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 + * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ #ifndef __PYGI_INVOKE_H__ @@ -26,16 +24,24 @@ #include <girepository.h> -#include "pygi-private.h" +#include "pygi-info.h" #include "pygi-invoke-state-struct.h" + G_BEGIN_DECLS +PyObject *pygi_invoke_c_callable (PyGIFunctionCache *function_cache, + PyGIInvokeState *state, + PyObject *py_args, PyObject *py_kwargs); 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); +gboolean _pygi_invoke_arg_state_init (PyGIInvokeState *state); + +void _pygi_invoke_arg_state_free (PyGIInvokeState *state); + G_END_DECLS #endif /* __PYGI_INVOKE_H__ */ diff --git a/gi/pygi-list.c b/gi/pygi-list.c new file mode 100644 index 0000000..712c372 --- /dev/null +++ b/gi/pygi-list.c @@ -0,0 +1,500 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- + * vim: tabstop=4 shiftwidth=4 expandtab + * + * Copyright (C) 2011 John (J5) Palmieri <johnp@redhat.com> + * Copyright (C) 2014 Simon Feltman <sfeltman@gnome.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <Python.h> +#include "pygi-list.h" +#include "pygi-argument.h" +#include "pygi-util.h" + +typedef PyGISequenceCache PyGIArgGList; + +/* + * GList and GSList from Python + */ +static gboolean +_pygi_marshal_from_py_glist (PyGIInvokeState *state, + PyGICallableCache *callable_cache, + PyGIArgCache *arg_cache, + PyObject *py_arg, + GIArgument *arg, + gpointer *cleanup_data) +{ + PyGIMarshalFromPyFunc from_py_marshaller; + int i; + Py_ssize_t length; + GList *list_ = NULL; + PyGISequenceCache *sequence_cache = (PyGISequenceCache *)arg_cache; + + + if (py_arg == Py_None) { + arg->v_pointer = NULL; + return TRUE; + } + + if (!PySequence_Check (py_arg)) { + PyErr_Format (PyExc_TypeError, "Must be sequence, not %s", + Py_TYPE (py_arg)->tp_name); + return FALSE; + } + + length = PySequence_Length (py_arg); + if (length < 0) + return FALSE; + + from_py_marshaller = sequence_cache->item_cache->from_py_marshaller; + for (i = 0; i < length; i++) { + GIArgument item = {0}; + gpointer item_cleanup_data = NULL; + PyObject *py_item = PySequence_GetItem (py_arg, i); + if (py_item == NULL) + goto err; + + if (!from_py_marshaller ( state, + callable_cache, + sequence_cache->item_cache, + py_item, + &item, + &item_cleanup_data)) + goto err; + + Py_DECREF (py_item); + list_ = g_list_prepend (list_, _pygi_arg_to_hash_pointer (&item, sequence_cache->item_cache->type_info)); + continue; +err: + /* FIXME: clean up list + if (sequence_cache->item_cache->from_py_cleanup != NULL) { + PyGIMarshalCleanupFunc cleanup = sequence_cache->item_cache->from_py_cleanup; + } + */ + Py_XDECREF (py_item); + g_list_free (list_); + _PyGI_ERROR_PREFIX ("Item %i: ", i); + return FALSE; + } + + arg->v_pointer = g_list_reverse (list_); + + if (arg_cache->transfer == GI_TRANSFER_NOTHING) { + /* Free everything in cleanup. */ + *cleanup_data = arg->v_pointer; + } else if (arg_cache->transfer == GI_TRANSFER_CONTAINER) { + /* Make a shallow copy so we can free the elements later in cleanup + * because it is possible invoke will free the list before our cleanup. */ + *cleanup_data = g_list_copy (arg->v_pointer); + } else { /* GI_TRANSFER_EVERYTHING */ + /* No cleanup, everything is given to the callee. */ + *cleanup_data = NULL; + } + return TRUE; +} + + +static gboolean +_pygi_marshal_from_py_gslist (PyGIInvokeState *state, + PyGICallableCache *callable_cache, + PyGIArgCache *arg_cache, + PyObject *py_arg, + GIArgument *arg, + gpointer *cleanup_data) +{ + PyGIMarshalFromPyFunc from_py_marshaller; + int i; + Py_ssize_t length; + GSList *list_ = NULL; + PyGISequenceCache *sequence_cache = (PyGISequenceCache *)arg_cache; + + if (py_arg == Py_None) { + arg->v_pointer = NULL; + return TRUE; + } + + if (!PySequence_Check (py_arg)) { + PyErr_Format (PyExc_TypeError, "Must be sequence, not %s", + Py_TYPE (py_arg)->tp_name); + return FALSE; + } + + length = PySequence_Length (py_arg); + if (length < 0) + return FALSE; + + from_py_marshaller = sequence_cache->item_cache->from_py_marshaller; + for (i = 0; i < length; i++) { + GIArgument item = {0}; + gpointer item_cleanup_data = NULL; + PyObject *py_item = PySequence_GetItem (py_arg, i); + if (py_item == NULL) + goto err; + + if (!from_py_marshaller ( state, + callable_cache, + sequence_cache->item_cache, + py_item, + &item, + &item_cleanup_data)) + goto err; + + Py_DECREF (py_item); + list_ = g_slist_prepend (list_, _pygi_arg_to_hash_pointer (&item, sequence_cache->item_cache->type_info)); + continue; +err: + /* FIXME: Clean up list + if (sequence_cache->item_cache->from_py_cleanup != NULL) { + PyGIMarshalCleanupFunc cleanup = sequence_cache->item_cache->from_py_cleanup; + } + */ + + Py_XDECREF (py_item); + g_slist_free (list_); + _PyGI_ERROR_PREFIX ("Item %i: ", i); + return FALSE; + } + + arg->v_pointer = g_slist_reverse (list_); + + if (arg_cache->transfer == GI_TRANSFER_NOTHING) { + /* Free everything in cleanup. */ + *cleanup_data = arg->v_pointer; + } else if (arg_cache->transfer == GI_TRANSFER_CONTAINER) { + /* Make a shallow copy so we can free the elements later in cleanup + * because it is possible invoke will free the list before our cleanup. */ + *cleanup_data = g_slist_copy (arg->v_pointer); + } else { /* GI_TRANSFER_EVERYTHING */ + /* No cleanup, everything is given to the callee. */ + *cleanup_data = NULL; + } + + return TRUE; +} + +static void +_pygi_marshal_cleanup_from_py_glist (PyGIInvokeState *state, + PyGIArgCache *arg_cache, + PyObject *py_arg, + gpointer data, + gboolean was_processed) +{ + if (was_processed) { + GSList *list_; + PyGISequenceCache *sequence_cache = (PyGISequenceCache *)arg_cache; + + list_ = (GSList *)data; + + /* clean up items first */ + if (sequence_cache->item_cache->from_py_cleanup != NULL) { + PyGIMarshalCleanupFunc cleanup_func = + sequence_cache->item_cache->from_py_cleanup; + GSList *node = list_; + gsize i = 0; + while (node != NULL) { + PyObject *py_item = PySequence_GetItem (py_arg, i); + cleanup_func (state, + sequence_cache->item_cache, + py_item, + node->data, + TRUE); + Py_XDECREF (py_item); + node = node->next; + i++; + } + } + + if (arg_cache->type_tag == GI_TYPE_TAG_GLIST) { + g_list_free ( (GList *)list_); + } else if (arg_cache->type_tag == GI_TYPE_TAG_GSLIST) { + g_slist_free (list_); + } else { + g_assert_not_reached(); + } + } +} + + +/* + * GList and GSList to Python + */ +static PyObject * +_pygi_marshal_to_py_glist (PyGIInvokeState *state, + PyGICallableCache *callable_cache, + PyGIArgCache *arg_cache, + GIArgument *arg, + gpointer *cleanup_data) +{ + GList *list_; + guint length; + guint i; + GPtrArray *item_cleanups; + + PyGIMarshalToPyFunc item_to_py_marshaller; + PyGIArgCache *item_arg_cache; + PyGISequenceCache *seq_cache = (PyGISequenceCache *)arg_cache; + + PyObject *py_obj = NULL; + + list_ = arg->v_pointer; + length = g_list_length (list_); + + py_obj = PyList_New (length); + if (py_obj == NULL) + return NULL; + + item_cleanups = g_ptr_array_sized_new (length); + *cleanup_data = item_cleanups; + + item_arg_cache = seq_cache->item_cache; + item_to_py_marshaller = item_arg_cache->to_py_marshaller; + + for (i = 0; list_ != NULL; list_ = g_list_next (list_), i++) { + GIArgument item_arg; + PyObject *py_item; + gpointer item_cleanup_data = NULL; + + item_arg.v_pointer = list_->data; + _pygi_hash_pointer_to_arg (&item_arg, item_arg_cache->type_info); + py_item = item_to_py_marshaller (state, + callable_cache, + item_arg_cache, + &item_arg, + &item_cleanup_data); + + g_ptr_array_index (item_cleanups, i) = item_cleanup_data; + + if (py_item == NULL) { + Py_CLEAR (py_obj); + _PyGI_ERROR_PREFIX ("Item %u: ", i); + g_ptr_array_unref (item_cleanups); + return NULL; + } + + PyList_SET_ITEM (py_obj, i, py_item); + } + + return py_obj; +} + +static PyObject * +_pygi_marshal_to_py_gslist (PyGIInvokeState *state, + PyGICallableCache *callable_cache, + PyGIArgCache *arg_cache, + GIArgument *arg, + gpointer *cleanup_data) +{ + GSList *list_; + guint length; + guint i; + GPtrArray *item_cleanups; + + PyGIMarshalToPyFunc item_to_py_marshaller; + PyGIArgCache *item_arg_cache; + PyGISequenceCache *seq_cache = (PyGISequenceCache *)arg_cache; + + PyObject *py_obj = NULL; + + list_ = arg->v_pointer; + length = g_slist_length (list_); + + py_obj = PyList_New (length); + if (py_obj == NULL) + return NULL; + + item_cleanups = g_ptr_array_sized_new (length); + *cleanup_data = item_cleanups; + + item_arg_cache = seq_cache->item_cache; + item_to_py_marshaller = item_arg_cache->to_py_marshaller; + + for (i = 0; list_ != NULL; list_ = g_slist_next (list_), i++) { + GIArgument item_arg; + PyObject *py_item; + gpointer item_cleanup_data = NULL; + + item_arg.v_pointer = list_->data; + _pygi_hash_pointer_to_arg (&item_arg, item_arg_cache->type_info); + py_item = item_to_py_marshaller (state, + callable_cache, + item_arg_cache, + &item_arg, + &item_cleanup_data); + + g_ptr_array_index (item_cleanups, i) = item_cleanup_data; + if (py_item == NULL) { + Py_CLEAR (py_obj); + _PyGI_ERROR_PREFIX ("Item %u: ", i); + g_ptr_array_unref (item_cleanups); + return NULL; + } + + PyList_SET_ITEM (py_obj, i, py_item); + } + + return py_obj; +} + +static void +_pygi_marshal_cleanup_to_py_glist (PyGIInvokeState *state, + PyGIArgCache *arg_cache, + gpointer cleanup_data, + gpointer data, + gboolean was_processed) +{ + GPtrArray *item_cleanups = (GPtrArray *) cleanup_data; + PyGISequenceCache *sequence_cache = (PyGISequenceCache *)arg_cache; + GSList *list_ = (GSList *)data; + + if (sequence_cache->item_cache->to_py_cleanup != NULL) { + PyGIMarshalToPyCleanupFunc cleanup_func = + sequence_cache->item_cache->to_py_cleanup; + GSList *node = list_; + guint i = 0; + + while (node != NULL) { + cleanup_func (state, + sequence_cache->item_cache, + g_ptr_array_index(item_cleanups, i), + node->data, + was_processed); + node = node->next; + i++; + } + } + + if (arg_cache->transfer == GI_TRANSFER_EVERYTHING || + arg_cache->transfer == GI_TRANSFER_CONTAINER) { + + if (arg_cache->type_tag == GI_TYPE_TAG_GLIST) { + g_list_free ( (GList *)list_); + } else if (arg_cache->type_tag == GI_TYPE_TAG_GSLIST) { + g_slist_free (list_); + } else { + g_assert_not_reached(); + } + } + + g_ptr_array_unref (item_cleanups); +} + +static void +_arg_cache_from_py_glist_setup (PyGIArgCache *arg_cache, + GITransfer transfer) +{ + arg_cache->from_py_marshaller = _pygi_marshal_from_py_glist; + arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_glist; +} + +static void +_arg_cache_to_py_glist_setup (PyGIArgCache *arg_cache, + GITransfer transfer) +{ + arg_cache->to_py_marshaller = _pygi_marshal_to_py_glist; + arg_cache->to_py_cleanup = _pygi_marshal_cleanup_to_py_glist; +} + +static void +_arg_cache_from_py_gslist_setup (PyGIArgCache *arg_cache, + GITransfer transfer) +{ + arg_cache->from_py_marshaller = _pygi_marshal_from_py_gslist; + arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_glist; +} + +static void +_arg_cache_to_py_gslist_setup (PyGIArgCache *arg_cache, + GITransfer transfer) +{ + arg_cache->to_py_marshaller = _pygi_marshal_to_py_gslist; + arg_cache->to_py_cleanup = _pygi_marshal_cleanup_to_py_glist; +} + + +/* + * GList/GSList Interface + */ + +static gboolean +pygi_arg_glist_setup_from_info (PyGIArgCache *arg_cache, + GITypeInfo *type_info, + GIArgInfo *arg_info, + GITransfer transfer, + PyGIDirection direction, + PyGICallableCache *callable_cache) +{ + GITypeTag type_tag = g_type_info_get_tag (type_info); + + if (!pygi_arg_sequence_setup ((PyGISequenceCache *)arg_cache, + type_info, + arg_info, + transfer, + direction, + callable_cache)) + return FALSE; + + switch (type_tag) { + case GI_TYPE_TAG_GLIST: + { + if (direction & PYGI_DIRECTION_FROM_PYTHON) + _arg_cache_from_py_glist_setup (arg_cache, transfer); + + if (direction & PYGI_DIRECTION_TO_PYTHON) + _arg_cache_to_py_glist_setup (arg_cache, transfer); + break; + } + case GI_TYPE_TAG_GSLIST: + { + if (direction & PYGI_DIRECTION_FROM_PYTHON) + _arg_cache_from_py_gslist_setup (arg_cache, transfer); + + if (direction & PYGI_DIRECTION_TO_PYTHON) + _arg_cache_to_py_gslist_setup (arg_cache, transfer); + + break; + } + default: + g_assert_not_reached (); + } + + return TRUE; +} + +PyGIArgCache * +pygi_arg_glist_new_from_info (GITypeInfo *type_info, + GIArgInfo *arg_info, + GITransfer transfer, + PyGIDirection direction, + PyGICallableCache *callable_cache) +{ + gboolean res = FALSE; + + PyGIArgCache *arg_cache = (PyGIArgCache *) g_slice_new0 (PyGIArgGList); + if (arg_cache == NULL) + return NULL; + + res = pygi_arg_glist_setup_from_info (arg_cache, + type_info, + arg_info, + transfer, + direction, + callable_cache); + if (res) { + return arg_cache; + } else { + pygi_arg_cache_free (arg_cache); + return NULL; + } +} diff --git a/gi/pygi-list.h b/gi/pygi-list.h new file mode 100644 index 0000000..f22e024 --- /dev/null +++ b/gi/pygi-list.h @@ -0,0 +1,39 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- + * vim: tabstop=4 shiftwidth=4 expandtab + * + * Copyright (C) 2014 Simon Feltman <sfeltman@gnome.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __PYGI_LIST_H__ +#define __PYGI_LIST_H__ + +#include <girepository.h> +#include "pygi-cache.h" + +G_BEGIN_DECLS + +PyGIArgCache *pygi_arg_glist_new_from_info (GITypeInfo *type_info, + GIArgInfo *arg_info, /* may be null */ + GITransfer transfer, + PyGIDirection direction, + PyGICallableCache *callable_cache); + +/* Internally dispatches GList and GSList */ +#define pygi_arg_gslist_new_from_info pygi_arg_glist_new_from_info + +G_END_DECLS + +#endif /*__PYGI_LIST_H__*/ diff --git a/gi/pygi-marshal-cleanup.c b/gi/pygi-marshal-cleanup.c index d7d1b63..98fbe47 100644 --- a/gi/pygi-marshal-cleanup.c +++ b/gi/pygi-marshal-cleanup.c @@ -14,31 +14,33 @@ * 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 + * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ - - #include "pygi-marshal-cleanup.h" - #include <glib.h> + +#include "pygi-marshal-cleanup.h" +#include "pygi-foreign.h" +#include <glib.h> + static inline void _cleanup_caller_allocates (PyGIInvokeState *state, PyGIArgCache *cache, + PyObject *py_obj, gpointer data, gboolean was_processed) { PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)cache; - if (g_type_is_a (iface_cache->g_type, G_TYPE_BOXED)) { + /* check GValue first because GValue is also a boxed sub-type */ + if (g_type_is_a (iface_cache->g_type, G_TYPE_VALUE)) { + if (was_processed) + g_value_unset (data); + g_slice_free (GValue, data); + } else if (g_type_is_a (iface_cache->g_type, G_TYPE_BOXED)) { gsize size; if (was_processed) return; /* will be cleaned up at deallocation */ size = g_struct_info_get_size (iface_cache->interface_info); g_slice_free1 (size, data); - } else if (iface_cache->g_type == G_TYPE_VALUE) { - if (was_processed) - g_value_unset (data); - g_slice_free (GValue, data); } else if (iface_cache->is_foreign) { if (was_processed) return; /* will be cleaned up at deallocation */ @@ -90,24 +92,34 @@ void pygi_marshal_cleanup_args_from_py_marshal_success (PyGIInvokeState *state, PyGICallableCache *cache) { - gssize i; + guint i; + PyObject *error_type, *error_value, *error_traceback; + gboolean have_error = !!PyErr_Occurred (); - /* For in success, call cleanup for all GI_DIRECTION_IN values only. */ - for (i = 0; i < cache->n_args; i++) { - PyGIArgCache *arg_cache = cache->args_cache[i]; - PyGIMarshalCleanupFunc cleanup_func = arg_cache->from_py_cleanup; + if (have_error) + PyErr_Fetch (&error_type, &error_value, &error_traceback); - if (cleanup_func && - arg_cache->direction == PYGI_DIRECTION_FROM_PYTHON && - state->args[i]->v_pointer != NULL) - cleanup_func (state, arg_cache, state->args[i]->v_pointer, TRUE); - - if (cleanup_func && - arg_cache->direction == PYGI_DIRECTION_BIDIRECTIONAL && - state->args_data[i] != NULL) { - cleanup_func (state, arg_cache, state->args_data[i], TRUE); + for (i = 0; i < _pygi_callable_cache_args_len (cache); i++) { + PyGIArgCache *arg_cache = _pygi_callable_cache_get_arg (cache, i); + PyGIMarshalCleanupFunc cleanup_func = arg_cache->from_py_cleanup; + gpointer cleanup_data = state->args[i].arg_cleanup_data; + + /* Only cleanup using args_cleanup_data when available. + * It is the responsibility of the various "from_py" marshalers to return + * cleanup_data which is then passed into their respective cleanup function. + * PyGIInvokeState.args_cleanup_data stores this data (via _invoke_marshal_in_args) + * for the duration of the invoke up until this point. + */ + if (cleanup_func && cleanup_data != NULL && arg_cache->py_arg_index >= 0 && + arg_cache->direction & PYGI_DIRECTION_FROM_PYTHON) { + PyObject *py_arg = PyTuple_GET_ITEM (state->py_in_args, arg_cache->py_arg_index); + cleanup_func (state, arg_cache, py_arg, cleanup_data, TRUE); + state->args[i].arg_cleanup_data = NULL; } } + + if (have_error) + PyErr_Restore (error_type, error_value, error_traceback); } void @@ -115,12 +127,20 @@ pygi_marshal_cleanup_args_to_py_marshal_success (PyGIInvokeState *state, PyGICallableCache *cache) { GSList *cache_item; + guint i = 0; + PyObject *error_type, *error_value, *error_traceback; + gboolean have_error = !!PyErr_Occurred (); + + if (have_error) + PyErr_Fetch (&error_type, &error_value, &error_traceback); + /* clean up the return if available */ if (cache->return_cache != NULL) { - PyGIMarshalCleanupFunc cleanup_func = cache->return_cache->to_py_cleanup; + PyGIMarshalToPyCleanupFunc cleanup_func = cache->return_cache->to_py_cleanup; if (cleanup_func && state->return_arg.v_pointer != NULL) cleanup_func (state, cache->return_cache, + state->to_py_return_arg_cleanup_data, state->return_arg.v_pointer, TRUE); } @@ -129,23 +149,29 @@ pygi_marshal_cleanup_args_to_py_marshal_success (PyGIInvokeState *state, cache_item = cache->to_py_args; 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; + PyGIMarshalToPyCleanupFunc cleanup_func = arg_cache->to_py_cleanup; + gpointer data = state->args[arg_cache->c_arg_index].arg_value.v_pointer; if (cleanup_func != NULL && data != NULL) cleanup_func (state, arg_cache, + state->args[arg_cache->c_arg_index].to_py_arg_cleanup_data, data, TRUE); else if (arg_cache->is_caller_allocates && data != NULL) { _cleanup_caller_allocates (state, arg_cache, + state->args[arg_cache->c_arg_index].to_py_arg_cleanup_data, data, TRUE); } + i++; cache_item = cache_item->next; } + + if (have_error) + PyErr_Restore (error_type, error_value, error_traceback); } void @@ -153,30 +179,46 @@ pygi_marshal_cleanup_args_from_py_parameter_fail (PyGIInvokeState *state, PyGICallableCache *cache, gssize failed_arg_index) { - gssize i; + guint i; + PyObject *error_type, *error_value, *error_traceback; + gboolean have_error = !!PyErr_Occurred (); + + if (have_error) + PyErr_Fetch (&error_type, &error_value, &error_traceback); state->failed = TRUE; - for (i = 0; i < cache->n_args && i <= failed_arg_index; i++) { - PyGIArgCache *arg_cache = cache->args_cache[i]; + for (i = 0; i < _pygi_callable_cache_args_len (cache) && i <= (guint)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 cleanup_data = state->args[i].arg_cleanup_data; + PyObject *py_arg = NULL; - if (cleanup_func && - arg_cache->direction == PYGI_DIRECTION_FROM_PYTHON && - data != NULL) { + if (arg_cache->py_arg_index < 0) { + continue; + } + py_arg = PyTuple_GET_ITEM (state->py_in_args, arg_cache->py_arg_index); + + if (cleanup_func && cleanup_data != NULL && + arg_cache->direction == PYGI_DIRECTION_FROM_PYTHON) { cleanup_func (state, arg_cache, - data, - i < failed_arg_index); + py_arg, + cleanup_data, + i < (guint)failed_arg_index); - } else if (arg_cache->is_caller_allocates && data != NULL) { + } else if (arg_cache->is_caller_allocates && cleanup_data != NULL) { _cleanup_caller_allocates (state, arg_cache, - data, + py_arg, + cleanup_data, FALSE); } + state->args[i].arg_cleanup_data = NULL; } + + if (have_error) + PyErr_Restore (error_type, error_value, error_traceback); } void @@ -193,406 +235,3 @@ pygi_marshal_cleanup_args_to_py_parameter_fail (PyGIInvokeState *state, { state->failed = TRUE; } - -void -_pygi_marshal_cleanup_from_py_utf8 (PyGIInvokeState *state, - PyGIArgCache *arg_cache, - gpointer data, - gboolean was_processed) -{ - /* We strdup strings so always free if we have processed this - parameter for input */ - if (was_processed) - g_free (data); -} - -void -_pygi_marshal_cleanup_to_py_utf8 (PyGIInvokeState *state, - PyGIArgCache *arg_cache, - gpointer data, - gboolean was_processed) -{ - /* Python copies the string so we need to free it - if the interface is transfering ownership, - whether or not it has been processed yet */ - if (arg_cache->transfer == GI_TRANSFER_EVERYTHING) - g_free (data); -} - -void -_pygi_marshal_cleanup_from_py_interface_object (PyGIInvokeState *state, - PyGIArgCache *arg_cache, - gpointer data, - gboolean was_processed) -{ - /* If we processed the parameter but fail before invoking the method, - we need to remove the ref we added */ - if (was_processed && state->failed && data != NULL && - arg_cache->transfer == GI_TRANSFER_EVERYTHING) - g_object_unref (G_OBJECT(data)); -} - -void -_pygi_marshal_cleanup_to_py_interface_object (PyGIInvokeState *state, - PyGIArgCache *arg_cache, - gpointer data, - gboolean was_processed) -{ - /* If we error out and the object is not marshalled into a PyGObject - we must take care of removing the ref */ - if (!was_processed && arg_cache->transfer == GI_TRANSFER_EVERYTHING) - g_object_unref (G_OBJECT(data)); -} - - -void -_pygi_marshal_cleanup_from_py_interface_callback (PyGIInvokeState *state, - PyGIArgCache *arg_cache, - gpointer data, - gboolean was_processed) -{ - PyGICallbackCache *callback_cache = (PyGICallbackCache *)arg_cache; - if (was_processed && callback_cache->scope == GI_SCOPE_TYPE_CALL) { - _pygi_invoke_closure_free (state->args_data[arg_cache->c_arg_index]); - state->args_data[arg_cache->c_arg_index] = NULL; - } -} - -void -_pygi_marshal_cleanup_from_py_interface_struct_gvalue (PyGIInvokeState *state, - PyGIArgCache *arg_cache, - gpointer data, - gboolean was_processed) -{ - if (was_processed) { - PyObject *py_arg = PyTuple_GET_ITEM (state->py_in_args, - arg_cache->py_arg_index); - GType py_object_type = - pyg_type_from_object_strict ( (PyObject *) py_arg->ob_type, FALSE); - - if (py_object_type != G_TYPE_VALUE) { - g_value_unset ((GValue *) data); - g_slice_free (GValue, data); - } - } -} - -void -_pygi_marshal_cleanup_from_py_interface_struct_foreign (PyGIInvokeState *state, - PyGIArgCache *arg_cache, - gpointer data, - gboolean was_processed) -{ - if (state->failed && was_processed) - pygi_struct_foreign_release ( - ( (PyGIInterfaceCache *)arg_cache)->interface_info, - data); -} - -void -_pygi_marshal_cleanup_to_py_interface_struct_foreign (PyGIInvokeState *state, - PyGIArgCache *arg_cache, - gpointer data, - gboolean was_processed) -{ - if (!was_processed && arg_cache->transfer == GI_TRANSFER_EVERYTHING) - pygi_struct_foreign_release ( - ( (PyGIInterfaceCache *)arg_cache)->interface_info, - data); -} - -static GArray* -_wrap_c_array (PyGIInvokeState *state, - PyGISequenceCache *sequence_cache, - gpointer data) -{ - GArray *array_; - gsize len = 0; - - if (sequence_cache->fixed_size >= 0) { - len = sequence_cache->fixed_size; - } else if (sequence_cache->is_zero_terminated) { - len = g_strv_length ((gchar **)data); - } else if (sequence_cache->len_arg_index >= 0) { - GIArgument *len_arg = state->args[sequence_cache->len_arg_index]; - len = len_arg->v_long; - } - - array_ = g_array_new (FALSE, - FALSE, - sequence_cache->item_size); - - if (array_ == NULL) - return NULL; - - g_free (array_->data); - array_->data = data; - array_->len = len; - - return array_; -} - -void -_pygi_marshal_cleanup_from_py_array (PyGIInvokeState *state, - PyGIArgCache *arg_cache, - gpointer data, - gboolean was_processed) -{ - if (was_processed) { - GArray *array_ = NULL; - GPtrArray *ptr_array_ = NULL; - PyGISequenceCache *sequence_cache = (PyGISequenceCache *)arg_cache; - - /* If this isn't a garray create one to help process variable sized - array elements */ - if (sequence_cache->array_type == GI_ARRAY_TYPE_C) { - array_ = _wrap_c_array (state, sequence_cache, data); - - if (array_ == NULL) - return; - - } else if (sequence_cache->array_type == GI_ARRAY_TYPE_PTR_ARRAY) { - ptr_array_ = (GPtrArray *) data; - } else { - array_ = (GArray *) data; - } - - /* clean up items first */ - if (sequence_cache->item_cache->from_py_cleanup != NULL) { - gsize i; - guint len = (array_ != NULL) ? array_->len : ptr_array_->len; - PyGIMarshalCleanupFunc cleanup_func = - sequence_cache->item_cache->from_py_cleanup; - - for (i = 0; i < len; i++) { - gpointer item; - - /* case 1: GPtrArray */ - if (ptr_array_ != NULL) - item = g_ptr_array_index (ptr_array_, i); - /* case 2: C array or GArray with object pointers */ - else if (sequence_cache->item_cache->is_pointer) - item = g_array_index (array_, gpointer, i); - /* case 3: C array or GArray with simple types or structs */ - else { - item = array_->data + i * sequence_cache->item_size; - /* special-case hack: GValue array items do not get slice - * allocated in _pygi_marshal_from_py_array(), so we must - * not try to deallocate it as a slice and thus - * short-circuit cleanup_func. */ - if (cleanup_func == _pygi_marshal_cleanup_from_py_interface_struct_gvalue) { - g_value_unset ((GValue*) item); - continue; - } - } - - cleanup_func (state, sequence_cache->item_cache, item, TRUE); - } - } - - /* Only free the array when we didn't transfer ownership */ - if (sequence_cache->array_type == GI_ARRAY_TYPE_C) { - g_array_free (array_, arg_cache->transfer == GI_TRANSFER_NOTHING); - } else if (state->failed || - arg_cache->transfer == GI_TRANSFER_NOTHING) { - if (array_ != NULL) - g_array_free (array_, TRUE); - else - g_ptr_array_free (ptr_array_, TRUE); - } - } -} - -void -_pygi_marshal_cleanup_to_py_array (PyGIInvokeState *state, - PyGIArgCache *arg_cache, - gpointer data, - gboolean was_processed) -{ - if (arg_cache->transfer == GI_TRANSFER_EVERYTHING || - arg_cache->transfer == GI_TRANSFER_CONTAINER) { - GArray *array_ = NULL; - GPtrArray *ptr_array_ = NULL; - PyGISequenceCache *sequence_cache = (PyGISequenceCache *)arg_cache; - - /* If this isn't a garray create one to help process variable sized - array elements */ - if (sequence_cache->array_type == GI_ARRAY_TYPE_C) { - array_ = _wrap_c_array (state, sequence_cache, data); - - if (array_ == NULL) - return; - - } else if (sequence_cache->array_type == GI_ARRAY_TYPE_PTR_ARRAY) { - ptr_array_ = (GPtrArray *) data; - } else { - array_ = (GArray *) data; - } - - if (sequence_cache->item_cache->to_py_cleanup != NULL) { - gsize i; - guint len = (array_ != NULL) ? array_->len : ptr_array_->len; - - PyGIMarshalCleanupFunc cleanup_func = sequence_cache->item_cache->to_py_cleanup; - for (i = 0; i < len; i++) { - cleanup_func (state, - sequence_cache->item_cache, - (array_ != NULL) ? g_array_index (array_, gpointer, i) : g_ptr_array_index (ptr_array_, i), - was_processed); - } - } - - if (array_ != NULL) - g_array_free (array_, TRUE); - else - g_ptr_array_free (ptr_array_, TRUE); - } -} - -void -_pygi_marshal_cleanup_from_py_glist (PyGIInvokeState *state, - PyGIArgCache *arg_cache, - gpointer data, - gboolean was_processed) -{ - if (was_processed) { - GSList *list_; - PyGISequenceCache *sequence_cache = (PyGISequenceCache *)arg_cache; - - list_ = (GSList *)data; - - /* clean up items first */ - if (sequence_cache->item_cache->from_py_cleanup != NULL) { - PyGIMarshalCleanupFunc cleanup_func = - sequence_cache->item_cache->from_py_cleanup; - GSList *node = list_; - while (node != NULL) { - cleanup_func (state, - sequence_cache->item_cache, - node->data, - TRUE); - node = node->next; - } - } - - if (state->failed || - arg_cache->transfer == GI_TRANSFER_NOTHING || - arg_cache->transfer == GI_TRANSFER_CONTAINER) { - switch (arg_cache->type_tag) { - case GI_TYPE_TAG_GLIST: - g_list_free ( (GList *)list_); - break; - case GI_TYPE_TAG_GSLIST: - g_slist_free (list_); - break; - default: - g_assert_not_reached(); - } - } - } -} - -void -_pygi_marshal_cleanup_to_py_glist (PyGIInvokeState *state, - PyGIArgCache *arg_cache, - gpointer data, - gboolean was_processed) -{ - PyGISequenceCache *sequence_cache = (PyGISequenceCache *)arg_cache; - - if (arg_cache->transfer == GI_TRANSFER_EVERYTHING || - arg_cache->transfer == GI_TRANSFER_CONTAINER) { - GSList *list_ = (GSList *)data; - - if (sequence_cache->item_cache->to_py_cleanup != NULL) { - PyGIMarshalCleanupFunc cleanup_func = - sequence_cache->item_cache->to_py_cleanup; - GSList *node = list_; - - while (node != NULL) { - cleanup_func (state, - sequence_cache->item_cache, - node->data, - was_processed); - node = node->next; - } - } - - if (arg_cache->transfer == GI_TRANSFER_EVERYTHING) { - switch (arg_cache->type_tag) { - case GI_TYPE_TAG_GLIST: - g_list_free ( (GList *)list_); - break; - case GI_TYPE_TAG_GSLIST: - g_slist_free (list_); - break; - default: - g_assert_not_reached(); - } - } - } -} - -void -_pygi_marshal_cleanup_from_py_ghash (PyGIInvokeState *state, - PyGIArgCache *arg_cache, - gpointer data, - gboolean was_processed) -{ - if (data == NULL) - return; - - if (was_processed) { - GHashTable *hash_; - PyGIHashCache *hash_cache = (PyGIHashCache *)arg_cache; - - hash_ = (GHashTable *)data; - - /* clean up keys and values first */ - if (hash_cache->key_cache->from_py_cleanup != NULL || - hash_cache->value_cache->from_py_cleanup != NULL) { - GHashTableIter hiter; - gpointer key; - gpointer value; - - PyGIMarshalCleanupFunc key_cleanup_func = - hash_cache->key_cache->from_py_cleanup; - PyGIMarshalCleanupFunc value_cleanup_func = - hash_cache->value_cache->from_py_cleanup; - - g_hash_table_iter_init (&hiter, hash_); - while (g_hash_table_iter_next (&hiter, &key, &value)) { - if (key != NULL && key_cleanup_func != NULL) - key_cleanup_func (state, - hash_cache->key_cache, - key, - TRUE); - if (value != NULL && value_cleanup_func != NULL) - value_cleanup_func (state, - hash_cache->value_cache, - value, - TRUE); - } - } - - if (state->failed || - arg_cache->transfer == GI_TRANSFER_NOTHING || - arg_cache->transfer == GI_TRANSFER_CONTAINER) - g_hash_table_destroy (hash_); - - } -} - -void -_pygi_marshal_cleanup_to_py_ghash (PyGIInvokeState *state, - PyGIArgCache *arg_cache, - gpointer data, - gboolean was_processed) -{ - if (data == NULL) - return; - - /* assume hashtable has boxed key and value */ - if (arg_cache->transfer == GI_TRANSFER_EVERYTHING) - g_hash_table_destroy ( (GHashTable *)data); -} diff --git a/gi/pygi-marshal-cleanup.h b/gi/pygi-marshal-cleanup.h index 234e49c..18ba007 100644 --- a/gi/pygi-marshal-cleanup.h +++ b/gi/pygi-marshal-cleanup.h @@ -14,15 +14,15 @@ * 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 + * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ #ifndef __PYGI_MARSHAL_CLEANUP_H__ #define __PYGI_MARSHAL_CLEANUP_H__ -#include "pygi-private.h" +#include "pygi-struct.h" +#include "pygi-invoke-state-struct.h" +#include "pygi-cache.h" G_BEGIN_DECLS @@ -39,63 +39,6 @@ void pygi_marshal_cleanup_args_return_fail (PyGIInvokeState *state, void pygi_marshal_cleanup_args_to_py_parameter_fail (PyGIInvokeState *state, PyGICallableCache *cache, gssize failed_to_py_arg_index); - -void _pygi_marshal_cleanup_from_py_utf8 (PyGIInvokeState *state, - PyGIArgCache *arg_cache, - gpointer data, - gboolean was_processed); -void _pygi_marshal_cleanup_to_py_utf8 (PyGIInvokeState *state, - PyGIArgCache *arg_cache, - gpointer data, - gboolean was_processed); -void _pygi_marshal_cleanup_from_py_interface_struct_gvalue (PyGIInvokeState *state, - PyGIArgCache *arg_cache, - gpointer data, - gboolean was_processed); -void _pygi_marshal_cleanup_from_py_interface_struct_foreign (PyGIInvokeState *state, - PyGIArgCache *arg_cache, - gpointer data, - gboolean was_processed); -void _pygi_marshal_cleanup_to_py_interface_struct_foreign (PyGIInvokeState *state, - PyGIArgCache *arg_cache, - gpointer data, - gboolean was_processed); -void _pygi_marshal_cleanup_from_py_interface_object (PyGIInvokeState *state, - PyGIArgCache *arg_cache, - gpointer data, - gboolean was_processed); -void _pygi_marshal_cleanup_to_py_interface_object (PyGIInvokeState *state, - PyGIArgCache *arg_cache, - gpointer data, - gboolean was_processed); -void _pygi_marshal_cleanup_from_py_interface_callback (PyGIInvokeState *state, - PyGIArgCache *arg_cache, - gpointer data, - gboolean was_processed); -void _pygi_marshal_cleanup_from_py_array (PyGIInvokeState *state, - PyGIArgCache *arg_cache, - gpointer data, - gboolean was_processed); -void _pygi_marshal_cleanup_to_py_array (PyGIInvokeState *state, - PyGIArgCache *arg_cache, - gpointer data, - gboolean was_processed); -void _pygi_marshal_cleanup_from_py_glist (PyGIInvokeState *state, - PyGIArgCache *arg_cache, - gpointer data, - gboolean was_processed); -void _pygi_marshal_cleanup_to_py_glist (PyGIInvokeState *state, - PyGIArgCache *arg_cache, - gpointer data, - gboolean was_processed); -void _pygi_marshal_cleanup_from_py_ghash (PyGIInvokeState *state, - PyGIArgCache *arg_cache, - gpointer data, - gboolean was_processed); -void _pygi_marshal_cleanup_to_py_ghash (PyGIInvokeState *state, - PyGIArgCache *arg_cache, - gpointer data, - gboolean was_processed); G_END_DECLS #endif /* __PYGI_MARSHAL_CLEANUP_H__ */ diff --git a/gi/pygi-marshal-from-py.c b/gi/pygi-marshal-from-py.c deleted file mode 100644 index 57b4126..0000000 --- a/gi/pygi-marshal-from-py.c +++ /dev/null @@ -1,1870 +0,0 @@ -/* -*- Mode: C; c-basic-offset: 4 -*- - * vim: tabstop=4 shiftwidth=4 expandtab - * - * Copyright (C) 2011 John (J5) Palmieri <johnp@redhat.com>, Red Hat, Inc. - * - * pygi-marshal-from-py.c: Functions to convert PyObjects to C types. - * - * 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 - */ - -#include "pygi-private.h" - -#include <string.h> -#include <time.h> -#include <pygobject.h> -#include <pyglib-python-compat.h> - -#include "pygi-cache.h" -#include "pygi-marshal-cleanup.h" -#include "pygi-marshal-from-py.h" - -#ifdef _WIN32 -#ifdef _MSC_VER -#include <math.h> - -#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_py_ssize_t (GIArgument *arg_out, - Py_ssize_t size_in, - GITypeTag type_tag) -{ - switch (type_tag) { - case GI_TYPE_TAG_VOID: - case GI_TYPE_TAG_BOOLEAN: - goto unhandled_type; - - case GI_TYPE_TAG_INT8: - if (size_in >= G_MININT8 && size_in <= G_MAXINT8) { - arg_out->v_int8 = size_in; - return TRUE; - } else { - goto overflow; - } - - case GI_TYPE_TAG_UINT8: - if (size_in >= 0 && size_in <= G_MAXUINT8) { - arg_out->v_uint8 = size_in; - return TRUE; - } else { - goto overflow; - } - - case GI_TYPE_TAG_INT16: - if (size_in >= G_MININT16 && size_in <= G_MAXINT16) { - arg_out->v_int16 = size_in; - return TRUE; - } else { - goto overflow; - } - - case GI_TYPE_TAG_UINT16: - if (size_in >= 0 && size_in <= G_MAXUINT16) { - arg_out->v_uint16 = size_in; - return TRUE; - } else { - goto overflow; - } - - /* Ranges assume two's complement */ - case GI_TYPE_TAG_INT32: - if (size_in >= G_MININT32 && size_in <= G_MAXINT32) { - arg_out->v_int32 = size_in; - return TRUE; - } else { - goto overflow; - } - - case GI_TYPE_TAG_UINT32: - if (size_in >= 0 && size_in <= G_MAXUINT32) { - arg_out->v_uint32 = size_in; - return TRUE; - } else { - goto overflow; - } - - case GI_TYPE_TAG_INT64: - arg_out->v_int64 = size_in; - return TRUE; - - case GI_TYPE_TAG_UINT64: - if (size_in >= 0) { - arg_out->v_uint64 = size_in; - return TRUE; - } else { - goto overflow; - } - - case GI_TYPE_TAG_FLOAT: - case GI_TYPE_TAG_DOUBLE: - case GI_TYPE_TAG_GTYPE: - case GI_TYPE_TAG_UTF8: - case GI_TYPE_TAG_FILENAME: - case GI_TYPE_TAG_ARRAY: - case GI_TYPE_TAG_INTERFACE: - case GI_TYPE_TAG_GLIST: - case GI_TYPE_TAG_GSLIST: - case GI_TYPE_TAG_GHASH: - case GI_TYPE_TAG_ERROR: - case GI_TYPE_TAG_UNICHAR: - default: - goto unhandled_type; - } - - overflow: - PyErr_Format (PyExc_OverflowError, - "Unable to marshal C Py_ssize_t %zd to %s", - size_in, - g_type_tag_to_string (type_tag)); - return FALSE; - - unhandled_type: - PyErr_Format (PyExc_TypeError, - "Unable to marshal C Py_ssize_t %zd to %s", - size_in, - g_type_tag_to_string (type_tag)); - return FALSE; -} - -static gboolean -gi_argument_from_c_long (GIArgument *arg_out, - long c_long_in, - GITypeTag type_tag) -{ - switch (type_tag) { - case GI_TYPE_TAG_INT8: - arg_out->v_int8 = c_long_in; - return TRUE; - case GI_TYPE_TAG_UINT8: - arg_out->v_uint8 = c_long_in; - return TRUE; - case GI_TYPE_TAG_INT16: - arg_out->v_int16 = c_long_in; - return TRUE; - case GI_TYPE_TAG_UINT16: - arg_out->v_uint16 = c_long_in; - return TRUE; - case GI_TYPE_TAG_INT32: - arg_out->v_int32 = c_long_in; - return TRUE; - case GI_TYPE_TAG_UINT32: - arg_out->v_uint32 = c_long_in; - return TRUE; - case GI_TYPE_TAG_INT64: - arg_out->v_int64 = c_long_in; - return TRUE; - case GI_TYPE_TAG_UINT64: - arg_out->v_uint64 = c_long_in; - return TRUE; - default: - PyErr_Format (PyExc_TypeError, - "Unable to marshal C long %ld to %s", - c_long_in, - g_type_tag_to_string (type_tag)); - return FALSE; - } -} - -/* - * _is_union_member - check to see if the py_arg is actually a member of the - * expected C union - */ -static gboolean -_is_union_member (GIInterfaceInfo *interface_info, PyObject *py_arg) { - gint i; - gint n_fields; - GIUnionInfo *union_info; - GIInfoType info_type; - gboolean is_member = FALSE; - - info_type = g_base_info_get_type (interface_info); - - if (info_type != GI_INFO_TYPE_UNION) - return FALSE; - - union_info = (GIUnionInfo *) interface_info; - n_fields = g_union_info_get_n_fields (union_info); - - for (i = 0; i < n_fields; i++) { - GIFieldInfo *field_info; - GITypeInfo *field_type_info; - - field_info = g_union_info_get_field (union_info, i); - field_type_info = g_field_info_get_type (field_info); - - /* we can only check if the members are interfaces */ - if (g_type_info_get_tag (field_type_info) == GI_TYPE_TAG_INTERFACE) { - GIInterfaceInfo *field_iface_info; - PyObject *py_type; - - field_iface_info = g_type_info_get_interface (field_type_info); - py_type = _pygi_type_import_by_gi_info ((GIBaseInfo *) field_iface_info); - - if (py_type != NULL && PyObject_IsInstance (py_arg, py_type)) { - is_member = TRUE; - } - - Py_XDECREF (py_type); - g_base_info_unref ( ( GIBaseInfo *) field_iface_info); - } - - g_base_info_unref ( ( GIBaseInfo *) field_type_info); - g_base_info_unref ( ( GIBaseInfo *) field_info); - - if (is_member) - break; - } - - return is_member; -} - -gboolean -_pygi_marshal_from_py_void (PyGIInvokeState *state, - PyGICallableCache *callable_cache, - PyGIArgCache *arg_cache, - PyObject *py_arg, - GIArgument *arg) -{ - g_warn_if_fail (arg_cache->transfer == GI_TRANSFER_NOTHING); - - if (py_arg == Py_None) { - arg->v_pointer = NULL; - } else if (PYGLIB_CPointer_Check(py_arg)) { - arg->v_pointer = PYGLIB_CPointer_GetPointer (py_arg, NULL); - } else { - /* NOTE: This will change to only allow integers and the deprecation - * warning will become a runtime exception. Using the following: - * arg->v_pointer = PyLong_AsVoidPtr (py_arg); - * See: https://bugzilla.gnome.org/show_bug.cgi?id=688081 - */ - - if (!PYGLIB_PyLong_Check(py_arg) && !PyLong_Check(py_arg)) { - if (PyErr_WarnEx(PyGIDeprecationWarning, - "Pointer arguments will be restricted to integers, capsules, and None. " - "See: https://bugzilla.gnome.org/show_bug.cgi?id=683599", - 1)) - return FALSE; - } - arg->v_pointer = py_arg; - } - - return TRUE; -} - -static gboolean -check_valid_double (double x, double min, double max) -{ - char buf[100]; - - if ((x < min || x > max) && x != INFINITY && x != -INFINITY && x != NAN) { - if (PyErr_Occurred()) - PyErr_Clear (); - - /* we need this as PyErr_Format() does not support float types */ - snprintf (buf, sizeof (buf), "%g not in range %g to %g", x, min, max); - PyErr_SetString (PyExc_OverflowError, buf); - return FALSE; - } - return TRUE; -} - -static gboolean -_pygi_py_arg_to_double (PyObject *py_arg, double *double_) -{ - PyObject *py_float; - - if (!PyNumber_Check (py_arg)) { - PyErr_Format (PyExc_TypeError, "Must be number, not %s", - py_arg->ob_type->tp_name); - return FALSE; - } - - py_float = PyNumber_Float (py_arg); - if (!py_float) - return FALSE; - - *double_ = PyFloat_AsDouble (py_float); - Py_DECREF (py_float); - - - return TRUE; -} - -static gboolean -_pygi_marshal_from_py_float (PyObject *py_arg, - GIArgument *arg) -{ - double double_; - - if (!_pygi_py_arg_to_double (py_arg, &double_)) - return FALSE; - - if (PyErr_Occurred () || !check_valid_double (double_, -G_MAXFLOAT, G_MAXFLOAT)) - return FALSE; - - arg->v_float = double_; - return TRUE; -} - -static gboolean -_pygi_marshal_from_py_double (PyObject *py_arg, - GIArgument *arg) -{ - double double_; - - if (!_pygi_py_arg_to_double (py_arg, &double_)) - return FALSE; - - if (PyErr_Occurred () || !check_valid_double (double_, -G_MAXDOUBLE, G_MAXDOUBLE)) - return FALSE; - - arg->v_double = double_; - return TRUE; -} - -static gboolean -_pygi_marshal_from_py_unichar (PyObject *py_arg, - GIArgument *arg) -{ - Py_ssize_t size; - gchar *string_; - - if (py_arg == Py_None) { - arg->v_uint32 = 0; - return FALSE; - } - - if (PyUnicode_Check (py_arg)) { - PyObject *py_bytes; - - size = PyUnicode_GET_SIZE (py_arg); - py_bytes = PyUnicode_AsUTF8String (py_arg); - if (!py_bytes) - return FALSE; - - string_ = g_strdup(PYGLIB_PyBytes_AsString (py_bytes)); - Py_DECREF (py_bytes); - -#if PY_VERSION_HEX < 0x03000000 - } else if (PyString_Check (py_arg)) { - PyObject *pyuni = PyUnicode_FromEncodedObject (py_arg, "UTF-8", "strict"); - if (!pyuni) - return FALSE; - - size = PyUnicode_GET_SIZE (pyuni); - string_ = g_strdup (PyString_AsString(py_arg)); - Py_DECREF (pyuni); -#endif - } else { - PyErr_Format (PyExc_TypeError, "Must be string, not %s", - py_arg->ob_type->tp_name); - return FALSE; - } - - if (size != 1) { - PyErr_Format (PyExc_TypeError, "Must be a one character string, not %lld characters", - (long long) size); - g_free (string_); - return FALSE; - } - - arg->v_uint32 = g_utf8_get_char (string_); - g_free (string_); - - return TRUE; -} - -static gboolean -_pygi_marshal_from_py_gtype (PyObject *py_arg, - GIArgument *arg) -{ - long type_ = pyg_type_from_object (py_arg); - - if (type_ == 0) { - PyErr_Format (PyExc_TypeError, "Must be gobject.GType, not %s", - py_arg->ob_type->tp_name); - return FALSE; - } - - arg->v_long = type_; - return TRUE; -} - -static gboolean -_pygi_marshal_from_py_utf8 (PyObject *py_arg, - GIArgument *arg) -{ - gchar *string_; - - if (py_arg == Py_None) { - arg->v_pointer = NULL; - return TRUE; - } - - if (PyUnicode_Check (py_arg)) { - PyObject *pystr_obj = PyUnicode_AsUTF8String (py_arg); - if (!pystr_obj) - return FALSE; - - string_ = g_strdup (PYGLIB_PyBytes_AsString (pystr_obj)); - Py_DECREF (pystr_obj); - } -#if PY_VERSION_HEX < 0x03000000 - else if (PyString_Check (py_arg)) { - string_ = g_strdup (PyString_AsString (py_arg)); - } -#endif - else { - PyErr_Format (PyExc_TypeError, "Must be string, not %s", - py_arg->ob_type->tp_name); - return FALSE; - } - - arg->v_string = string_; - return TRUE; -} - -static gboolean -_pygi_marshal_from_py_filename (PyObject *py_arg, - GIArgument *arg) -{ - gchar *string_; - GError *error = NULL; - - if (PyUnicode_Check (py_arg)) { - PyObject *pystr_obj = PyUnicode_AsUTF8String (py_arg); - if (!pystr_obj) - return FALSE; - - string_ = g_strdup (PYGLIB_PyBytes_AsString (pystr_obj)); - Py_DECREF (pystr_obj); - } -#if PY_VERSION_HEX < 0x03000000 - else if (PyString_Check (py_arg)) { - string_ = g_strdup (PyString_AsString (py_arg)); - } -#endif - else { - PyErr_Format (PyExc_TypeError, "Must be string, not %s", - py_arg->ob_type->tp_name); - return FALSE; - } - - arg->v_string = g_filename_from_utf8 (string_, -1, NULL, NULL, &error); - g_free (string_); - - if (arg->v_string == NULL) { - PyErr_SetString (PyExc_Exception, error->message); - g_error_free (error); - /* TODO: Convert the error to an exception. */ - return FALSE; - } - - return TRUE; -} - -static gboolean -_pygi_marshal_from_py_long (PyObject *object, /* in */ - GIArgument *arg, /* out */ - GITypeTag type_tag, - GITransfer transfer) -{ - PyObject *number; - - if (!PyNumber_Check (object)) { - PyErr_Format (PyExc_TypeError, "Must be number, not %s", - object->ob_type->tp_name); - return FALSE; - } - -#if PY_MAJOR_VERSION < 3 - { - PyObject *tmp = PyNumber_Int (object); - if (tmp) { - number = PyNumber_Long (tmp); - Py_DECREF (tmp); - } else { - number = PyNumber_Long (object); - } - } -#else - number = PyNumber_Long (object); -#endif - - if (number == NULL) { - PyErr_SetString (PyExc_TypeError, "expected int argument"); - return FALSE; - } - - switch (type_tag) { - case GI_TYPE_TAG_INT8: - { - long long_value = PyLong_AsLong (number); - if (PyErr_Occurred()) { - break; - } else if (long_value < G_MININT8 || long_value > G_MAXINT8) { - PyErr_Format (PyExc_OverflowError, "%ld not in range %ld to %ld", - long_value, (long)G_MININT8, (long)G_MAXINT8); - } else { - arg->v_int8 = long_value; - } - break; - } - - case GI_TYPE_TAG_UINT8: - { - long long_value = PyLong_AsLong (number); - if (PyErr_Occurred()) { - break; - } else if (long_value < 0 || long_value > G_MAXUINT8) { - PyErr_Format (PyExc_OverflowError, "%ld not in range %ld to %ld", - long_value, (long)0, (long)G_MAXUINT8); - } else { - arg->v_uint8 = long_value; - } - break; - } - - case GI_TYPE_TAG_INT16: - { - long long_value = PyLong_AsLong (number); - if (PyErr_Occurred()) { - break; - } else if (long_value < G_MININT16 || long_value > G_MAXINT16) { - PyErr_Format (PyExc_OverflowError, "%ld not in range %ld to %ld", - long_value, (long)G_MININT16, (long)G_MAXINT16); - } else { - arg->v_int16 = long_value; - } - break; - } - - case GI_TYPE_TAG_UINT16: - { - long long_value = PyLong_AsLong (number); - if (PyErr_Occurred()) { - break; - } else if (long_value < 0 || long_value > G_MAXUINT16) { - PyErr_Format (PyExc_OverflowError, "%ld not in range %ld to %ld", - long_value, (long)0, (long)G_MAXUINT16); - } else { - arg->v_uint16 = long_value; - } - break; - } - - case GI_TYPE_TAG_INT32: - { - long long_value = PyLong_AsLong (number); - if (PyErr_Occurred()) { - break; - } else if (long_value < G_MININT32 || long_value > G_MAXINT32) { - PyErr_Format (PyExc_OverflowError, "%ld not in range %ld to %ld", - long_value, (long)G_MININT32, (long)G_MAXINT32); - } else { - arg->v_int32 = long_value; - } - break; - } - - case GI_TYPE_TAG_UINT32: - { - PY_LONG_LONG long_value = PyLong_AsLongLong (number); - if (PyErr_Occurred()) { - break; - } else if (long_value < 0 || long_value > G_MAXUINT32) { - PyErr_Format (PyExc_OverflowError, "%lld not in range %ld to %lu", - long_value, (long)0, (unsigned long)G_MAXUINT32); - } else { - arg->v_uint32 = long_value; - } - break; - } - - case GI_TYPE_TAG_INT64: - { - /* Rely on Python overflow error and convert to ValueError for 64 bit values */ - arg->v_int64 = PyLong_AsLongLong (number); - break; - } - - case GI_TYPE_TAG_UINT64: - { - /* Rely on Python overflow error and convert to ValueError for 64 bit values */ - arg->v_uint64 = PyLong_AsUnsignedLongLong (number); - break; - } - - default: - g_assert_not_reached (); - } - - Py_DECREF (number); - - if (PyErr_Occurred()) - return FALSE; - return TRUE; -} - -gboolean -_pygi_marshal_from_py_basic_type (PyObject *object, /* in */ - GIArgument *arg, /* out */ - GITypeTag type_tag, - GITransfer transfer) -{ - switch (type_tag) { - case GI_TYPE_TAG_VOID: - g_warn_if_fail (transfer == GI_TRANSFER_NOTHING); - if (object == Py_None) { - arg->v_pointer = NULL; - } else if (!PYGLIB_PyLong_Check(object) && !PyLong_Check(object)) { - PyErr_SetString(PyExc_TypeError, - "Pointer assignment is restricted to integer values. " - "See: https://bugzilla.gnome.org/show_bug.cgi?id=683599"); - } else { - arg->v_pointer = PyLong_AsVoidPtr (object); - } - break; - case GI_TYPE_TAG_INT8: - case GI_TYPE_TAG_UINT8: - if (PYGLIB_PyBytes_Check (object)) { - if (PYGLIB_PyBytes_Size (object) != 1) { - PyErr_Format (PyExc_TypeError, "Must be a single character"); - return FALSE; - } - if (type_tag == GI_TYPE_TAG_INT8) { - arg->v_int8 = (gint8)(PYGLIB_PyBytes_AsString (object)[0]); - } else { - arg->v_uint8 = (guint8)(PYGLIB_PyBytes_AsString (object)[0]); - } - } else { - return _pygi_marshal_from_py_long (object, arg, type_tag, transfer); - } - break; - case GI_TYPE_TAG_INT16: - case GI_TYPE_TAG_UINT16: - case GI_TYPE_TAG_INT32: - case GI_TYPE_TAG_UINT32: - case GI_TYPE_TAG_INT64: - case GI_TYPE_TAG_UINT64: - return _pygi_marshal_from_py_long (object, arg, type_tag, transfer); - - case GI_TYPE_TAG_BOOLEAN: - arg->v_boolean = PyObject_IsTrue (object); - break; - - case GI_TYPE_TAG_FLOAT: - return _pygi_marshal_from_py_float (object, arg); - - case GI_TYPE_TAG_DOUBLE: - return _pygi_marshal_from_py_double (object, arg); - - case GI_TYPE_TAG_GTYPE: - return _pygi_marshal_from_py_gtype (object, arg); - - case GI_TYPE_TAG_UNICHAR: - return _pygi_marshal_from_py_unichar (object, arg); - - case GI_TYPE_TAG_UTF8: - return _pygi_marshal_from_py_utf8 (object, arg); - - case GI_TYPE_TAG_FILENAME: - return _pygi_marshal_from_py_filename (object, arg); - - default: - return FALSE; - } - - if (PyErr_Occurred()) - return FALSE; - - return TRUE; -} - -gboolean -_pygi_marshal_from_py_basic_type_cache_adapter (PyGIInvokeState *state, - PyGICallableCache *callable_cache, - PyGIArgCache *arg_cache, - PyObject *py_arg, - GIArgument *arg) -{ - return _pygi_marshal_from_py_basic_type (py_arg, - arg, - arg_cache->type_tag, - arg_cache->transfer); -} - -gboolean -_pygi_marshal_from_py_array (PyGIInvokeState *state, - PyGICallableCache *callable_cache, - PyGIArgCache *arg_cache, - PyObject *py_arg, - GIArgument *arg) -{ - PyGIMarshalFromPyFunc from_py_marshaller; - int i = 0; - Py_ssize_t length; - gssize item_size; - gboolean is_ptr_array; - GArray *array_ = NULL; - PyGISequenceCache *sequence_cache = (PyGISequenceCache *)arg_cache; - - - if (py_arg == Py_None) { - arg->v_pointer = NULL; - return TRUE; - } - - if (!PySequence_Check (py_arg)) { - PyErr_Format (PyExc_TypeError, "Must be sequence, not %s", - py_arg->ob_type->tp_name); - return FALSE; - } - - length = PySequence_Length (py_arg); - if (length < 0) - return FALSE; - - if (sequence_cache->fixed_size >= 0 && - sequence_cache->fixed_size != length) { - PyErr_Format (PyExc_ValueError, "Must contain %zd items, not %zd", - sequence_cache->fixed_size, length); - - return FALSE; - } - - item_size = sequence_cache->item_size; - is_ptr_array = (sequence_cache->array_type == GI_ARRAY_TYPE_PTR_ARRAY); - if (is_ptr_array) { - array_ = (GArray *)g_ptr_array_new (); - } else { - array_ = g_array_sized_new (sequence_cache->is_zero_terminated, - FALSE, - item_size, - length); - } - - if (array_ == NULL) { - PyErr_NoMemory (); - return FALSE; - } - - if (sequence_cache->item_cache->type_tag == GI_TYPE_TAG_UINT8 && - PYGLIB_PyBytes_Check (py_arg)) { - memcpy(array_->data, PYGLIB_PyBytes_AsString (py_arg), length); - array_->len = length; - if (sequence_cache->is_zero_terminated) { - /* If array_ has been created with zero_termination, space for the - * terminator is properly allocated, so we're not off-by-one here. */ - array_->data[length] = '\0'; - } - goto array_success; - } - - from_py_marshaller = sequence_cache->item_cache->from_py_marshaller; - for (i = 0; i < length; i++) { - GIArgument item; - PyObject *py_item = PySequence_GetItem (py_arg, i); - if (py_item == NULL) - goto err; - - if (!from_py_marshaller ( state, - callable_cache, - sequence_cache->item_cache, - py_item, - &item)) - goto err; - - /* FIXME: it is much more efficent to have seperate marshaller - * for ptr arrays than doing the evaluation - * and casting each loop iteration - */ - if (is_ptr_array) { - g_ptr_array_add((GPtrArray *)array_, item.v_pointer); - } else if (sequence_cache->item_cache->type_tag == GI_TYPE_TAG_INTERFACE) { - PyGIInterfaceCache *item_iface_cache = (PyGIInterfaceCache *) sequence_cache->item_cache; - GIBaseInfo *base_info = (GIBaseInfo *) item_iface_cache->interface_info; - GIInfoType info_type = g_base_info_get_type (base_info); - - switch (info_type) { - case GI_INFO_TYPE_UNION: - case GI_INFO_TYPE_STRUCT: - { - PyGIArgCache *item_arg_cache = (PyGIArgCache *)item_iface_cache; - PyGIMarshalCleanupFunc from_py_cleanup = item_arg_cache->from_py_cleanup; - gboolean is_boxed = g_type_is_a (item_iface_cache->g_type, G_TYPE_BOXED); - gboolean is_gvalue = item_iface_cache->g_type == G_TYPE_VALUE; - gboolean is_gvariant = item_iface_cache->g_type == G_TYPE_VARIANT; - - if (is_gvariant) { - /* Item size will always be that of a pointer, - * since GVariants are opaque hence always passed by ref */ - g_assert (item_size == sizeof (item.v_pointer)); - g_array_insert_val (array_, i, item.v_pointer); - } else if (is_gvalue) { - GValue* dest = (GValue*) (array_->data + (i * item_size)); - memset (dest, 0, item_size); - if (item.v_pointer != NULL) { - g_value_init (dest, G_VALUE_TYPE ((GValue*) item.v_pointer)); - g_value_copy ((GValue*) item.v_pointer, dest); - } - /* we free the original copy already, the new one is a plain struct - * in an array. _pygi_marshal_cleanup_from_py_array() does not free it again */ - if (from_py_cleanup) - from_py_cleanup (state, item_arg_cache, item.v_pointer, TRUE); - } else if (!is_boxed) { - /* HACK: Gdk.Atom is merely an integer wrapped in a pointer, - * so we must not dereference it; just copy the pointer - * value, and don't attempt to free it. TODO: find out - * if there are other data types with similar behaviour - * and generalize. */ - if (g_strcmp0 (item_iface_cache->type_name, "Gdk.Atom") == 0) { - g_assert (item_size == sizeof (item.v_pointer)); - memcpy (array_->data + (i * item_size), &item.v_pointer, item_size); - } else { - memcpy (array_->data + (i * item_size), item.v_pointer, item_size); - - if (from_py_cleanup) - from_py_cleanup (state, item_arg_cache, item.v_pointer, TRUE); - } - } else if (is_boxed && !item_iface_cache->arg_cache.is_pointer) { - /* The array elements are not expected to be pointers, but the - * elements obtained are boxed pointers themselves, so insert - * the pointed to data. - */ - g_array_insert_vals (array_, i, item.v_pointer, 1); - } else { - g_array_insert_val (array_, i, item); - } - break; - } - default: - g_array_insert_val (array_, i, item); - } - } else { - g_array_insert_val (array_, i, item); - } - continue; -err: - if (sequence_cache->item_cache->from_py_cleanup != NULL) { - gsize j; - PyGIMarshalCleanupFunc cleanup_func = - sequence_cache->item_cache->from_py_cleanup; - - for(j = 0; j < i; j++) { - cleanup_func (state, - sequence_cache->item_cache, - g_array_index (array_, gpointer, j), - TRUE); - } - } - - if (is_ptr_array) - g_ptr_array_free ( ( GPtrArray *)array_, TRUE); - else - g_array_free (array_, TRUE); - _PyGI_ERROR_PREFIX ("Item %i: ", i); - return FALSE; - } - -array_success: - if (sequence_cache->len_arg_index >= 0) { - /* we have an child arg to handle */ - PyGIArgCache *child_cache = - callable_cache->args_cache[sequence_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 (sequence_cache->array_type == GI_ARRAY_TYPE_C) { - arg->v_pointer = array_->data; - g_array_free (array_, FALSE); - /* remember the originally allocated array in args_data, as args and - * in_args get changed for (inout) arguments */ - if (arg_cache->transfer == GI_TRANSFER_NOTHING) - state->args_data[arg_cache->c_arg_index] = arg->v_pointer; - } else { - arg->v_pointer = array_; - } - - return TRUE; -} - -gboolean -_pygi_marshal_from_py_glist (PyGIInvokeState *state, - PyGICallableCache *callable_cache, - PyGIArgCache *arg_cache, - PyObject *py_arg, - GIArgument *arg) -{ - PyGIMarshalFromPyFunc from_py_marshaller; - int i; - Py_ssize_t length; - GList *list_ = NULL; - PyGISequenceCache *sequence_cache = (PyGISequenceCache *)arg_cache; - - - if (py_arg == Py_None) { - arg->v_pointer = NULL; - return TRUE; - } - - if (!PySequence_Check (py_arg)) { - PyErr_Format (PyExc_TypeError, "Must be sequence, not %s", - py_arg->ob_type->tp_name); - return FALSE; - } - - length = PySequence_Length (py_arg); - if (length < 0) - return FALSE; - - if (sequence_cache->fixed_size >= 0 && - sequence_cache->fixed_size != length) { - PyErr_Format (PyExc_ValueError, "Must contain %zd items, not %zd", - sequence_cache->fixed_size, length); - - return FALSE; - } - - from_py_marshaller = sequence_cache->item_cache->from_py_marshaller; - for (i = 0; i < length; i++) { - GIArgument item; - PyObject *py_item = PySequence_GetItem (py_arg, i); - if (py_item == NULL) - goto err; - - if (!from_py_marshaller ( state, - callable_cache, - sequence_cache->item_cache, - py_item, - &item)) - goto err; - - list_ = g_list_prepend (list_, _pygi_arg_to_hash_pointer (&item, sequence_cache->item_cache->type_tag)); - continue; -err: - /* FIXME: clean up list - if (sequence_cache->item_cache->from_py_cleanup != NULL) { - PyGIMarshalCleanupFunc cleanup = sequence_cache->item_cache->from_py_cleanup; - } - */ - g_list_free (list_); - _PyGI_ERROR_PREFIX ("Item %i: ", i); - return FALSE; - } - - arg->v_pointer = g_list_reverse (list_); - return TRUE; -} - -gboolean -_pygi_marshal_from_py_gslist (PyGIInvokeState *state, - PyGICallableCache *callable_cache, - PyGIArgCache *arg_cache, - PyObject *py_arg, - GIArgument *arg) -{ - PyGIMarshalFromPyFunc from_py_marshaller; - int i; - Py_ssize_t length; - GSList *list_ = NULL; - PyGISequenceCache *sequence_cache = (PyGISequenceCache *)arg_cache; - - if (py_arg == Py_None) { - arg->v_pointer = NULL; - return TRUE; - } - - if (!PySequence_Check (py_arg)) { - PyErr_Format (PyExc_TypeError, "Must be sequence, not %s", - py_arg->ob_type->tp_name); - return FALSE; - } - - length = PySequence_Length (py_arg); - if (length < 0) - return FALSE; - - if (sequence_cache->fixed_size >= 0 && - sequence_cache->fixed_size != length) { - PyErr_Format (PyExc_ValueError, "Must contain %zd items, not %zd", - sequence_cache->fixed_size, length); - - return FALSE; - } - - from_py_marshaller = sequence_cache->item_cache->from_py_marshaller; - for (i = 0; i < length; i++) { - GIArgument item; - PyObject *py_item = PySequence_GetItem (py_arg, i); - if (py_item == NULL) - goto err; - - if (!from_py_marshaller ( state, - callable_cache, - sequence_cache->item_cache, - py_item, - &item)) - goto err; - - list_ = g_slist_prepend (list_, _pygi_arg_to_hash_pointer (&item, sequence_cache->item_cache->type_tag)); - continue; -err: - /* FIXME: Clean up list - if (sequence_cache->item_cache->from_py_cleanup != NULL) { - PyGIMarshalCleanupFunc cleanup = sequence_cache->item_cache->from_py_cleanup; - } - */ - - g_slist_free (list_); - _PyGI_ERROR_PREFIX ("Item %i: ", i); - return FALSE; - } - - arg->v_pointer = g_slist_reverse (list_); - return TRUE; -} - -gboolean -_pygi_marshal_from_py_ghash (PyGIInvokeState *state, - PyGICallableCache *callable_cache, - PyGIArgCache *arg_cache, - PyObject *py_arg, - GIArgument *arg) -{ - PyGIMarshalFromPyFunc key_from_py_marshaller; - PyGIMarshalFromPyFunc value_from_py_marshaller; - - int i; - Py_ssize_t length; - PyObject *py_keys, *py_values; - - GHashFunc hash_func; - GEqualFunc equal_func; - - GHashTable *hash_ = NULL; - PyGIHashCache *hash_cache = (PyGIHashCache *)arg_cache; - - if (py_arg == Py_None) { - arg->v_pointer = NULL; - return TRUE; - } - - py_keys = PyMapping_Keys (py_arg); - if (py_keys == NULL) { - PyErr_Format (PyExc_TypeError, "Must be mapping, not %s", - py_arg->ob_type->tp_name); - return FALSE; - } - - length = PyMapping_Length (py_arg); - if (length < 0) { - Py_DECREF (py_keys); - return FALSE; - } - - py_values = PyMapping_Values (py_arg); - if (py_values == NULL) { - Py_DECREF (py_keys); - return FALSE; - } - - key_from_py_marshaller = hash_cache->key_cache->from_py_marshaller; - value_from_py_marshaller = hash_cache->value_cache->from_py_marshaller; - - switch (hash_cache->key_cache->type_tag) { - case GI_TYPE_TAG_UTF8: - case GI_TYPE_TAG_FILENAME: - hash_func = g_str_hash; - equal_func = g_str_equal; - break; - default: - hash_func = NULL; - equal_func = NULL; - } - - hash_ = g_hash_table_new (hash_func, equal_func); - if (hash_ == NULL) { - PyErr_NoMemory (); - Py_DECREF (py_keys); - Py_DECREF (py_values); - return FALSE; - } - - for (i = 0; i < length; i++) { - GIArgument key, value; - PyObject *py_key = PyList_GET_ITEM (py_keys, i); - PyObject *py_value = PyList_GET_ITEM (py_values, i); - if (py_key == NULL || py_value == NULL) - goto err; - - if (!key_from_py_marshaller ( state, - callable_cache, - hash_cache->key_cache, - py_key, - &key)) - goto err; - - if (!value_from_py_marshaller ( state, - callable_cache, - hash_cache->value_cache, - py_value, - &value)) - goto err; - - g_hash_table_insert (hash_, - _pygi_arg_to_hash_pointer (&key, hash_cache->key_cache->type_tag), - _pygi_arg_to_hash_pointer (&value, hash_cache->value_cache->type_tag)); - continue; -err: - /* FIXME: cleanup hash keys and values */ - Py_XDECREF (py_key); - Py_XDECREF (py_value); - Py_DECREF (py_keys); - Py_DECREF (py_values); - g_hash_table_unref (hash_); - _PyGI_ERROR_PREFIX ("Item %i: ", i); - return FALSE; - } - - arg->v_pointer = hash_; - return TRUE; -} - -gboolean -_pygi_marshal_from_py_gerror (PyGIInvokeState *state, - PyGICallableCache *callable_cache, - PyGIArgCache *arg_cache, - PyObject *py_arg, - GIArgument *arg) -{ - PyErr_Format (PyExc_NotImplementedError, - "Marshalling for GErrors is not implemented"); - return FALSE; -} - -/* _pygi_destroy_notify_dummy: - * - * Dummy method used in the occasion when a method has a GDestroyNotify - * argument without user data. - */ -static void -_pygi_destroy_notify_dummy (gpointer data) { -} - -static PyGICClosure *global_destroy_notify; - -static void -_pygi_destroy_notify_callback_closure (ffi_cif *cif, - void *result, - void **args, - void *data) -{ - PyGICClosure *info = * (void**) (args[0]); - - g_assert (info); - - _pygi_invoke_closure_free (info); -} - -/* _pygi_destroy_notify_create: - * - * Method used in the occasion when a method has a GDestroyNotify - * argument with user data. - */ -static PyGICClosure* -_pygi_destroy_notify_create (void) -{ - if (!global_destroy_notify) { - - PyGICClosure *destroy_notify = g_slice_new0 (PyGICClosure); - GIBaseInfo* glib_destroy_notify; - - g_assert (destroy_notify); - - glib_destroy_notify = g_irepository_find_by_name (NULL, "GLib", "DestroyNotify"); - g_assert (glib_destroy_notify != NULL); - g_assert (g_base_info_get_type (glib_destroy_notify) == GI_INFO_TYPE_CALLBACK); - - destroy_notify->closure = g_callable_info_prepare_closure ( (GICallableInfo*) glib_destroy_notify, - &destroy_notify->cif, - _pygi_destroy_notify_callback_closure, - NULL); - - global_destroy_notify = destroy_notify; - } - - return global_destroy_notify; -} - -gboolean -_pygi_marshal_from_py_interface_callback (PyGIInvokeState *state, - PyGICallableCache *callable_cache, - PyGIArgCache *arg_cache, - PyObject *py_arg, - GIArgument *arg) -{ - GICallableInfo *callable_info; - PyGICClosure *closure; - PyGIArgCache *user_data_cache = NULL; - PyGIArgCache *destroy_cache = NULL; - PyGICallbackCache *callback_cache; - PyObject *py_user_data = NULL; - - callback_cache = (PyGICallbackCache *)arg_cache; - - if (callback_cache->user_data_index > 0) { - user_data_cache = callable_cache->args_cache[callback_cache->user_data_index]; - if (user_data_cache->py_arg_index < state->n_py_in_args) { - /* py_user_data is a borrowed reference. */ - py_user_data = PyTuple_GetItem (state->py_in_args, user_data_cache->py_arg_index); - if (!py_user_data) - return FALSE; - } - } - - if (py_arg == Py_None && !(py_user_data == Py_None || py_user_data == NULL)) { - PyErr_Format (PyExc_TypeError, - "When passing None for a callback userdata must also be None"); - - return FALSE; - } - - if (py_arg == Py_None) { - return TRUE; - } - - if (!PyCallable_Check (py_arg)) { - PyErr_Format (PyExc_TypeError, - "Callback needs to be a function or method not %s", - py_arg->ob_type->tp_name); - - return FALSE; - } - - callable_info = (GICallableInfo *)callback_cache->interface_info; - - closure = _pygi_make_native_closure (callable_info, callback_cache->scope, py_arg, py_user_data); - arg->v_pointer = closure->closure; - - /* The PyGICClosure instance is used as user data passed into the C function. - * 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; - } - - /* Setup a GDestroyNotify callback if this method supports it along with - * a user data field. The user data field is a requirement in order - * free resources and ref counts associated with this arguments closure. - * In case a user data field is not available, show a warning giving - * explicit information and setup a dummy notification to avoid a crash - * later on in _pygi_destroy_notify_callback_closure. - */ - if (callback_cache->destroy_notify_index > 0) { - destroy_cache = callable_cache->args_cache[callback_cache->destroy_notify_index]; - } - - 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; - } else { - gchar *msg = g_strdup_printf("Callables passed to %s will leak references because " - "the method does not support a user_data argument. " - "See: https://bugzilla.gnome.org/show_bug.cgi?id=685598", - callable_cache->name); - if (PyErr_WarnEx(PyExc_RuntimeWarning, msg, 2)) { - g_free(msg); - _pygi_invoke_closure_free(closure); - return FALSE; - } - g_free(msg); - state->in_args[destroy_cache->c_arg_index].v_pointer = _pygi_destroy_notify_dummy; - } - } - - /* Store the PyGIClosure as extra args data so _pygi_marshal_cleanup_from_py_interface_callback - * can clean it up later for GI_SCOPE_TYPE_CALL based closures. - */ - state->args_data[arg_cache->c_arg_index] = closure; - - return TRUE; -} - -gboolean -_pygi_marshal_from_py_interface_enum (PyGIInvokeState *state, - PyGICallableCache *callable_cache, - PyGIArgCache *arg_cache, - PyObject *py_arg, - GIArgument *arg) -{ - PyObject *py_long; - long c_long; - gint is_instance; - PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache; - GIBaseInfo *interface = NULL; - - is_instance = PyObject_IsInstance (py_arg, iface_cache->py_type); - - py_long = PYGLIB_PyNumber_Long (py_arg); - if (py_long == NULL) { - PyErr_Clear(); - goto err; - } - - c_long = PYGLIB_PyLong_AsLong (py_long); - Py_DECREF (py_long); - - /* Write c_long into arg */ - interface = g_type_info_get_interface (arg_cache->type_info); - assert(g_base_info_get_type (interface) == GI_INFO_TYPE_ENUM); - if (!gi_argument_from_c_long(arg, - c_long, - g_enum_info_get_storage_type ((GIEnumInfo *)interface))) { - g_assert_not_reached(); - g_base_info_unref (interface); - return FALSE; - } - - /* If this is not an instance of the Enum type that we want - * we need to check if the value is equivilant to one of the - * Enum's memebers */ - if (!is_instance) { - int i; - gboolean is_found = FALSE; - - for (i = 0; i < g_enum_info_get_n_values (iface_cache->interface_info); i++) { - GIValueInfo *value_info = - g_enum_info_get_value (iface_cache->interface_info, i); - glong enum_value = g_value_info_get_value (value_info); - g_base_info_unref ( (GIBaseInfo *)value_info); - if (c_long == enum_value) { - is_found = TRUE; - break; - } - } - - if (!is_found) - goto err; - } - - g_base_info_unref (interface); - return TRUE; - -err: - if (interface) - g_base_info_unref (interface); - PyErr_Format (PyExc_TypeError, "Expected a %s, but got %s", - iface_cache->type_name, py_arg->ob_type->tp_name); - return FALSE; -} - -gboolean -_pygi_marshal_from_py_interface_flags (PyGIInvokeState *state, - PyGICallableCache *callable_cache, - PyGIArgCache *arg_cache, - PyObject *py_arg, - GIArgument *arg) -{ - PyObject *py_long; - long c_long; - gint is_instance; - PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache; - GIBaseInfo *interface; - - is_instance = PyObject_IsInstance (py_arg, iface_cache->py_type); - - py_long = PYGLIB_PyNumber_Long (py_arg); - if (py_long == NULL) { - PyErr_Clear (); - goto err; - } - - c_long = PYGLIB_PyLong_AsLong (py_long); - Py_DECREF (py_long); - - /* only 0 or argument of type Flag is allowed */ - if (!is_instance && c_long != 0) - goto err; - - /* Write c_long into arg */ - interface = g_type_info_get_interface (arg_cache->type_info); - g_assert (g_base_info_get_type (interface) == GI_INFO_TYPE_FLAGS); - if (!gi_argument_from_c_long(arg, c_long, - g_enum_info_get_storage_type ((GIEnumInfo *)interface))) { - g_base_info_unref (interface); - return FALSE; - } - - g_base_info_unref (interface); - return TRUE; - -err: - PyErr_Format (PyExc_TypeError, "Expected a %s, but got %s", - iface_cache->type_name, py_arg->ob_type->tp_name); - return FALSE; - -} - -gboolean -_pygi_marshal_from_py_interface_struct_cache_adapter (PyGIInvokeState *state, - PyGICallableCache *callable_cache, - PyGIArgCache *arg_cache, - PyObject *py_arg, - GIArgument *arg) -{ - PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache; - - return _pygi_marshal_from_py_interface_struct (py_arg, - arg, - arg_cache->arg_name, - iface_cache->interface_info, - arg_cache->type_info, - iface_cache->g_type, - iface_cache->py_type, - arg_cache->transfer, - TRUE, /*copy_reference*/ - iface_cache->is_foreign); -} - -gboolean -_pygi_marshal_from_py_interface_boxed (PyGIInvokeState *state, - PyGICallableCache *callable_cache, - PyGIArgCache *arg_cache, - PyObject *py_arg, - GIArgument *arg) -{ - PyErr_Format (PyExc_NotImplementedError, - "Marshalling for this type is not implemented yet"); - return FALSE; -} - -gboolean -_pygi_marshal_from_py_interface_object (PyGIInvokeState *state, - PyGICallableCache *callable_cache, - PyGIArgCache *arg_cache, - PyObject *py_arg, - GIArgument *arg) -{ - if (py_arg == Py_None) { - arg->v_pointer = NULL; - return TRUE; - } - - if (!PyObject_IsInstance (py_arg, ( (PyGIInterfaceCache *)arg_cache)->py_type)) { - PyObject *module = PyObject_GetAttrString(py_arg, "__module__"); - - PyErr_Format (PyExc_TypeError, "argument %s: Expected %s, but got %s%s%s", - arg_cache->arg_name ? arg_cache->arg_name : "self", - ( (PyGIInterfaceCache *)arg_cache)->type_name, - module ? PYGLIB_PyUnicode_AsString(module) : "", - module ? "." : "", - py_arg->ob_type->tp_name); - if (module) - Py_DECREF (module); - return FALSE; - } - - return _pygi_marshal_from_py_gobject (py_arg, arg, arg_cache->transfer); -} - -gboolean -_pygi_marshal_from_py_interface_union (PyGIInvokeState *state, - PyGICallableCache *callable_cache, - PyGIArgCache *arg_cache, - PyObject *py_arg, - GIArgument *arg) -{ - PyErr_Format(PyExc_NotImplementedError, - "Marshalling for this type is not implemented yet"); - return FALSE; -} - -gboolean _pygi_marshal_from_py_interface_instance (PyGIInvokeState *state, - PyGICallableCache *callable_cache, - PyGIArgCache *arg_cache, - PyObject *py_arg, - GIArgument *arg) -{ - GIInfoType info_type; - PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache; - - info_type = g_base_info_get_type (iface_cache->interface_info); - switch (info_type) { - case GI_INFO_TYPE_UNION: - case GI_INFO_TYPE_STRUCT: - { - GType type = iface_cache->g_type; - - if (!PyObject_IsInstance (py_arg, iface_cache->py_type)) { - /* wait, we might be a member of a union so manually check */ - if (!_is_union_member (iface_cache->interface_info, py_arg)) { - if (!PyErr_Occurred()) { - PyObject *module = PyObject_GetAttrString(py_arg, "__module__"); - PyErr_Format (PyExc_TypeError, - "argument %s: Expected a %s, but got %s%s%s", - arg_cache->arg_name ? arg_cache->arg_name : "self", - iface_cache->type_name, - module ? PYGLIB_PyUnicode_AsString(module) : "", - module ? "." : "", - py_arg->ob_type->tp_name); - if (module) - Py_DECREF (module); - } - return FALSE; - } - } - - if (g_type_is_a (type, G_TYPE_BOXED)) { - arg->v_pointer = pyg_boxed_get (py_arg, void); - } else if (g_type_is_a (type, G_TYPE_POINTER) || - g_type_is_a (type, G_TYPE_VARIANT) || - type == G_TYPE_NONE) { - arg->v_pointer = pyg_pointer_get (py_arg, void); - } else { - PyErr_Format (PyExc_TypeError, "unable to convert an instance of '%s'", g_type_name (type)); - return FALSE; - } - - break; - } - case GI_INFO_TYPE_OBJECT: - case GI_INFO_TYPE_INTERFACE: - arg->v_pointer = pygobject_get (py_arg); - if (arg->v_pointer != NULL) { - GType obj_type = G_OBJECT_TYPE (( GObject *)arg->v_pointer); - GType expected_type = iface_cache->g_type; - - if (!g_type_is_a (obj_type, expected_type)) { - PyObject *module = PyObject_GetAttrString(py_arg, "__module__"); - PyErr_Format (PyExc_TypeError, "argument %s: Expected %s, but got %s%s%s", - arg_cache->arg_name ? arg_cache->arg_name : "self", - iface_cache->type_name, - module ? PYGLIB_PyUnicode_AsString(module) : "", - module ? "." : "", - py_arg->ob_type->tp_name); - if (module) - Py_DECREF (module); - return FALSE; - } - } - break; - default: - /* Other types don't have methods. */ - g_assert_not_reached (); - } - - return TRUE; -} - -/* _pygi_marshal_from_py_gobject: - * py_arg: (in): - * arg: (out): - */ -gboolean -_pygi_marshal_from_py_gobject (PyObject *py_arg, /*in*/ - GIArgument *arg, /*out*/ - GITransfer transfer) { - GObject *gobj; - - if (py_arg == Py_None) { - arg->v_pointer = NULL; - return TRUE; - } - - if (!pygobject_check (py_arg, &PyGObject_Type)) { - PyObject *repr = PyObject_Repr (py_arg); - PyErr_Format(PyExc_TypeError, "expected GObject but got %s", - PYGLIB_PyUnicode_AsString (repr)); - Py_DECREF (repr); - return FALSE; - } - - gobj = pygobject_get (py_arg); - if (transfer == GI_TRANSFER_EVERYTHING) { - /* For transfer everything, add a new ref that the callee will take ownership of. - * Pythons existing ref to the GObject will be managed with the PyGObject wrapper. - */ - g_object_ref (gobj); - } - - arg->v_pointer = gobj; - return TRUE; -} - -/* _pygi_marshal_from_py_gobject_out_arg: - * py_arg: (in): - * arg: (out): - * - * A specialization for marshaling Python GObjects used for out/return values - * from a Python implemented vfuncs, signals, or an assignment to a GObject property. - */ -gboolean -_pygi_marshal_from_py_gobject_out_arg (PyObject *py_arg, /*in*/ - GIArgument *arg, /*out*/ - GITransfer transfer) { - GObject *gobj; - if (!_pygi_marshal_from_py_gobject (py_arg, arg, transfer)) { - return FALSE; - } - - /* HACK: At this point the basic marshaling of the GObject was successful - * but we add some special case hacks for vfunc returns due to buggy APIs: - * https://bugzilla.gnome.org/show_bug.cgi?id=693393 - */ - gobj = arg->v_pointer; - if (py_arg->ob_refcnt == 1 && gobj->ref_count == 1) { - /* If both object ref counts are only 1 at this point (the reference held - * in a return tuple), we assume the GObject will be free'd before reaching - * its target and become invalid. So instead of getting invalid object errors - * we add a new GObject ref. - */ - g_object_ref (gobj); - - if (((PyGObject *)py_arg)->private_flags.flags & PYGOBJECT_GOBJECT_WAS_FLOATING) { - /* - * We want to re-float instances that were floating and the Python - * wrapper assumed ownership. With the additional caveat that there - * are not any strong references beyond the return tuple. - */ - g_object_force_floating (gobj); - - } else { - PyObject *repr = PyObject_Repr (py_arg); - gchar *msg = g_strdup_printf ("Expecting to marshal a borrowed reference for %s, " - "but nothing in Python is holding a reference to this object. " - "See: https://bugzilla.gnome.org/show_bug.cgi?id=687522", - PYGLIB_PyUnicode_AsString(repr)); - Py_DECREF (repr); - if (PyErr_WarnEx (PyExc_RuntimeWarning, msg, 2)) { - g_free (msg); - return FALSE; - } - g_free (msg); - } - } - - return TRUE; -} - -/* _pygi_marshal_from_py_gvalue: - * py_arg: (in): - * arg: (out): - * transfer: - * copy_reference: TRUE if arg should use the pointer reference held by py_arg - * when it is already holding a GValue vs. copying the value. - */ -gboolean -_pygi_marshal_from_py_gvalue (PyObject *py_arg, - GIArgument *arg, - GITransfer transfer, - gboolean copy_reference) { - GValue *value; - GType object_type; - - object_type = pyg_type_from_object_strict ( (PyObject *) py_arg->ob_type, FALSE); - if (object_type == G_TYPE_INVALID) { - PyErr_SetString (PyExc_RuntimeError, "unable to retrieve object's GType"); - return FALSE; - } - - /* if already a gvalue, use that, else marshal into gvalue */ - if (object_type == G_TYPE_VALUE) { - GValue *source_value = pyg_boxed_get (py_arg, GValue); - if (copy_reference) { - value = source_value; - } else { - value = g_slice_new0 (GValue); - g_value_init (value, G_VALUE_TYPE (source_value)); - g_value_copy (source_value, value); - } - } else { - value = g_slice_new0 (GValue); - g_value_init (value, object_type); - if (pyg_value_from_pyobject (value, py_arg) < 0) { - g_slice_free (GValue, value); - PyErr_SetString (PyExc_RuntimeError, "PyObject conversion to GValue failed"); - return FALSE; - } - } - - arg->v_pointer = value; - return TRUE; -} - -/* _pygi_marshal_from_py_gclosure: - * py_arg: (in): - * arg: (out): - */ -gboolean -_pygi_marshal_from_py_gclosure(PyObject *py_arg, - GIArgument *arg) -{ - GClosure *closure; - GType object_gtype = pyg_type_from_object_strict (py_arg, FALSE); - - if ( !(PyCallable_Check(py_arg) || - g_type_is_a (object_gtype, G_TYPE_CLOSURE))) { - PyErr_Format (PyExc_TypeError, "Must be callable, not %s", - py_arg->ob_type->tp_name); - return FALSE; - } - - if (g_type_is_a (object_gtype, G_TYPE_CLOSURE)) - closure = (GClosure *)pyg_boxed_get (py_arg, void); - else - closure = pyg_closure_new (py_arg, NULL, NULL); - - if (closure == NULL) { - PyErr_SetString (PyExc_RuntimeError, "PyObject conversion to GClosure failed"); - return FALSE; - } - - arg->v_pointer = closure; - return TRUE; -} - -gboolean -_pygi_marshal_from_py_interface_struct (PyObject *py_arg, - GIArgument *arg, - const gchar *arg_name, - GIBaseInfo *interface_info, - GITypeInfo *type_info, - GType g_type, - PyObject *py_type, - GITransfer transfer, - gboolean copy_reference, - gboolean is_foreign) -{ - gboolean is_union = FALSE; - - if (py_arg == Py_None) { - arg->v_pointer = NULL; - return TRUE; - } - - /* FIXME: handle this large if statement in the cache - * and set the correct marshaller - */ - - if (g_type_is_a (g_type, G_TYPE_CLOSURE)) { - return _pygi_marshal_from_py_gclosure (py_arg, arg); - } else if (g_type_is_a (g_type, G_TYPE_VALUE)) { - return _pygi_marshal_from_py_gvalue(py_arg, - arg, - transfer, - copy_reference); - } else if (is_foreign) { - PyObject *success; - success = pygi_struct_foreign_convert_to_g_argument (py_arg, - interface_info, - transfer, - arg); - - return (success == Py_None); - } else if (!PyObject_IsInstance (py_arg, py_type)) { - /* first check to see if this is a member of the expected union */ - is_union = _is_union_member (interface_info, py_arg); - if (!is_union) { - goto type_error; - } - } - - if (g_type_is_a (g_type, G_TYPE_BOXED)) { - /* Additionally use pyg_type_from_object to pull the stashed __gtype__ - * attribute off of the input argument for type checking. This is needed - * to work around type discrepancies in cases with aliased (typedef) types. - * e.g. GtkAllocation, GdkRectangle. - * See: https://bugzilla.gnomethere are .org/show_bug.cgi?id=707140 - */ - if (is_union || pyg_boxed_check (py_arg, g_type) || - g_type_is_a (pyg_type_from_object (py_arg), g_type)) { - arg->v_pointer = pyg_boxed_get (py_arg, void); - if (transfer == GI_TRANSFER_EVERYTHING) { - arg->v_pointer = g_boxed_copy (g_type, arg->v_pointer); - } - } else { - goto type_error; - } - - } else if (g_type_is_a (g_type, G_TYPE_POINTER) || - g_type_is_a (g_type, G_TYPE_VARIANT) || - g_type == G_TYPE_NONE) { - g_warn_if_fail (g_type_is_a (g_type, G_TYPE_VARIANT) || !g_type_info_is_pointer (type_info) || transfer == GI_TRANSFER_NOTHING); - - if (g_type_is_a (g_type, G_TYPE_VARIANT) && - pyg_type_from_object (py_arg) != G_TYPE_VARIANT) { - PyErr_SetString (PyExc_TypeError, "expected GLib.Variant"); - return FALSE; - } - arg->v_pointer = pyg_pointer_get (py_arg, void); - - } else { - PyErr_Format (PyExc_NotImplementedError, - "structure type '%s' is not supported yet", - g_type_name(g_type)); - return FALSE; - } - return TRUE; - -type_error: - { - gchar *type_name = _pygi_g_base_info_get_fullname (interface_info); - PyObject *module = PyObject_GetAttrString(py_arg, "__module__"); - - PyErr_Format (PyExc_TypeError, "argument %s: Expected %s, but got %s%s%s", - arg_name ? arg_name : "self", - type_name, - module ? PYGLIB_PyUnicode_AsString(module) : "", - module ? "." : "", - py_arg->ob_type->tp_name); - if (module) - Py_DECREF (module); - g_free (type_name); - return FALSE; - } -} diff --git a/gi/pygi-marshal-from-py.h b/gi/pygi-marshal-from-py.h deleted file mode 100644 index 9f56a6f..0000000 --- a/gi/pygi-marshal-from-py.h +++ /dev/null @@ -1,151 +0,0 @@ -/* -*- Mode: C; c-basic-offset: 4 -*- - * vim: tabstop=4 shiftwidth=4 expandtab - * - * Copyright (C) 2011 John (J5) Palmieri <johnp@redhat.com>, Red Hat, Inc. - * - * 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 - */ - -#ifndef __PYGI_MARSHAL_from_py_PY_H__ -#define __PYGI_MARSHAL_from_py_PY_H__ - -#include <Python.h> - -#include <girepository.h> - -#include "pygi-private.h" - -G_BEGIN_DECLS - -gboolean _pygi_marshal_from_py_ssize_t (PyGIArgCache *arg_cache, - Py_ssize_t size, - GIArgument *arg); -gboolean _pygi_marshal_from_py_void (PyGIInvokeState *state, - PyGICallableCache *callable_cache, - PyGIArgCache *arg_cache, - PyObject *py_arg, - GIArgument *arg); -gboolean _pygi_marshal_from_py_array (PyGIInvokeState *state, - PyGICallableCache *callable_cache, - PyGIArgCache *arg_cache, - PyObject *py_arg, - GIArgument *arg); -gboolean _pygi_marshal_from_py_glist (PyGIInvokeState *state, - PyGICallableCache *callable_cache, - PyGIArgCache *arg_cache, - PyObject *py_arg, - GIArgument *arg); -gboolean _pygi_marshal_from_py_gslist (PyGIInvokeState *state, - PyGICallableCache *callable_cache, - PyGIArgCache *arg_cache, - PyObject *py_arg, - GIArgument *arg); -gboolean _pygi_marshal_from_py_ghash (PyGIInvokeState *state, - PyGICallableCache *callable_cache, - PyGIArgCache *arg_cache, - PyObject *py_arg, - GIArgument *arg); -gboolean _pygi_marshal_from_py_gerror (PyGIInvokeState *state, - PyGICallableCache *callable_cache, - PyGIArgCache *arg_cache, - PyObject *py_arg, - GIArgument *arg); -gboolean _pygi_marshal_from_py_interface_callback (PyGIInvokeState *state, - PyGICallableCache *callable_cache, - PyGIArgCache *arg_cache, - PyObject *py_arg, - GIArgument *arg); -gboolean _pygi_marshal_from_py_interface_enum (PyGIInvokeState *state, - PyGICallableCache *callable_cache, - PyGIArgCache *arg_cache, - PyObject *py_arg, - GIArgument *arg); -gboolean _pygi_marshal_from_py_interface_flags (PyGIInvokeState *state, - PyGICallableCache *callable_cache, - PyGIArgCache *arg_cache, - PyObject *py_arg, - GIArgument *arg); -gboolean _pygi_marshal_from_py_interface_struct_cache_adapter (PyGIInvokeState *state, - PyGICallableCache *callable_cache, - PyGIArgCache *arg_cache, - PyObject *py_arg, - GIArgument *arg); -gboolean _pygi_marshal_from_py_interface_interface(PyGIInvokeState *state, - PyGICallableCache *callable_cache, - PyGIArgCache *arg_cache, - PyObject *py_arg, - GIArgument *arg); -gboolean _pygi_marshal_from_py_interface_boxed (PyGIInvokeState *state, - PyGICallableCache *callable_cache, - PyGIArgCache *arg_cache, - PyObject *py_arg, - GIArgument *arg); -gboolean _pygi_marshal_from_py_interface_object (PyGIInvokeState *state, - PyGICallableCache *callable_cache, - PyGIArgCache *arg_cache, - PyObject *py_arg, - GIArgument *arg); -gboolean _pygi_marshal_from_py_interface_union (PyGIInvokeState *state, - PyGICallableCache *callable_cache, - PyGIArgCache *arg_cache, - PyObject *py_arg, - GIArgument *arg); -gboolean _pygi_marshal_from_py_interface_instance (PyGIInvokeState *state, - PyGICallableCache *callable_cache, - PyGIArgCache *arg_cache, - PyObject *py_arg, - GIArgument *arg); - -/* Simplified marshalers shared between vfunc/closure and direct function calls. */ -gboolean _pygi_marshal_from_py_basic_type (PyObject *object, /* in */ - GIArgument *arg, /* out */ - GITypeTag type_tag, - GITransfer transfer); -gboolean _pygi_marshal_from_py_basic_type_cache_adapter (PyGIInvokeState *state, - PyGICallableCache *callable_cache, - PyGIArgCache *arg_cache, - PyObject *py_arg, - GIArgument *arg); - -gboolean _pygi_marshal_from_py_gobject (PyObject *py_arg, /*in*/ - GIArgument *arg, /*out*/ - GITransfer transfer); -gboolean _pygi_marshal_from_py_gobject_out_arg (PyObject *py_arg, /*in*/ - GIArgument *arg, /*out*/ - GITransfer transfer); - -gboolean _pygi_marshal_from_py_gvalue (PyObject *py_arg, /*in*/ - GIArgument *arg, /*out*/ - GITransfer transfer, - gboolean is_allocated); - -gboolean _pygi_marshal_from_py_gclosure(PyObject *py_arg, /*in*/ - GIArgument *arg); /*out*/ - -gboolean _pygi_marshal_from_py_interface_struct (PyObject *py_arg, - GIArgument *arg, - const gchar *arg_name, - GIBaseInfo *interface_info, - GITypeInfo *type_info, - GType g_type, - PyObject *py_type, - GITransfer transfer, - gboolean is_allocated, - gboolean is_foreign); - -G_END_DECLS - -#endif /* __PYGI_MARSHAL_from_py_PY__ */ diff --git a/gi/pygi-marshal-to-py.c b/gi/pygi-marshal-to-py.c deleted file mode 100644 index 7c260f7..0000000 --- a/gi/pygi-marshal-to-py.c +++ /dev/null @@ -1,891 +0,0 @@ -/* -*- Mode: C; c-basic-offset: 4 -*- - * vim: tabstop=4 shiftwidth=4 expandtab - * - * Copyright (C) 2011 John (J5) Palmieri <johnp@redhat.com>, Red Hat, Inc. - * - * pygi-marshal-from-py.c: functions for converting C types to PyObject - * - * 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 - */ - -#include "pygi-private.h" - -#include <string.h> -#include <time.h> - -#include <pyglib.h> -#include <pygobject.h> -#include <pyglib-python-compat.h> - -#include "pygi-cache.h" -#include "pygi-marshal-cleanup.h" -#include "pygi-marshal-to-py.h" -#include "pygi-argument.h" - -static gboolean -gi_argument_to_c_long (GIArgument *arg_in, - long *c_long_out, - GITypeTag type_tag) -{ - switch (type_tag) { - case GI_TYPE_TAG_INT8: - *c_long_out = arg_in->v_int8; - return TRUE; - case GI_TYPE_TAG_UINT8: - *c_long_out = arg_in->v_uint8; - return TRUE; - case GI_TYPE_TAG_INT16: - *c_long_out = arg_in->v_int16; - return TRUE; - case GI_TYPE_TAG_UINT16: - *c_long_out = arg_in->v_uint16; - return TRUE; - case GI_TYPE_TAG_INT32: - *c_long_out = arg_in->v_int32; - return TRUE; - case GI_TYPE_TAG_UINT32: - *c_long_out = arg_in->v_uint32; - return TRUE; - case GI_TYPE_TAG_INT64: - *c_long_out = arg_in->v_int64; - return TRUE; - case GI_TYPE_TAG_UINT64: - *c_long_out = arg_in->v_uint64; - return TRUE; - default: - PyErr_Format (PyExc_TypeError, - "Unable to marshal %s to C long", - g_type_tag_to_string (type_tag)); - return FALSE; - } -} - -static gboolean -gi_argument_to_gsize (GIArgument *arg_in, - gsize *gsize_out, - GITypeTag type_tag) -{ - switch (type_tag) { - case GI_TYPE_TAG_INT8: - *gsize_out = arg_in->v_int8; - return TRUE; - case GI_TYPE_TAG_UINT8: - *gsize_out = arg_in->v_uint8; - return TRUE; - case GI_TYPE_TAG_INT16: - *gsize_out = arg_in->v_int16; - return TRUE; - case GI_TYPE_TAG_UINT16: - *gsize_out = arg_in->v_uint16; - return TRUE; - case GI_TYPE_TAG_INT32: - *gsize_out = arg_in->v_int32; - return TRUE; - case GI_TYPE_TAG_UINT32: - *gsize_out = arg_in->v_uint32; - return TRUE; - case GI_TYPE_TAG_INT64: - *gsize_out = arg_in->v_int64; - return TRUE; - case GI_TYPE_TAG_UINT64: - *gsize_out = arg_in->v_uint64; - return TRUE; - default: - PyErr_Format (PyExc_TypeError, - "Unable to marshal %s to gsize", - g_type_tag_to_string (type_tag)); - return FALSE; - } -} - -PyObject * -_pygi_marshal_to_py_void (PyGIInvokeState *state, - PyGICallableCache *callable_cache, - PyGIArgCache *arg_cache, - GIArgument *arg) -{ - PyObject *py_obj = NULL; - if (arg_cache->is_pointer) { - /* NOTE: This will change to interpret pointers as integer values - * by using the following: - * py_obj = PyLong_FromVoidPtr (arg->v_pointer); - * See: https://bugzilla.gnome.org/show_bug.cgi?id=688081 - */ - py_obj = arg->v_pointer; - } else { - py_obj = Py_None; - } - - Py_XINCREF (py_obj); - return py_obj; -} - -static PyObject * -_pygi_marshal_to_py_unichar (GIArgument *arg) -{ - PyObject *py_obj = NULL; - - /* Preserve the bidirectional mapping between 0 and "" */ - if (arg->v_uint32 == 0) { - py_obj = PYGLIB_PyUnicode_FromString (""); - } else if (g_unichar_validate (arg->v_uint32)) { - gchar utf8[6]; - gint bytes; - - bytes = g_unichar_to_utf8 (arg->v_uint32, utf8); - py_obj = PYGLIB_PyUnicode_FromStringAndSize ((char*)utf8, bytes); - } else { - /* TODO: Convert the error to an exception. */ - PyErr_Format (PyExc_TypeError, - "Invalid unicode codepoint %" G_GUINT32_FORMAT, - arg->v_uint32); - } - - return py_obj; -} - -static PyObject * -_pygi_marshal_to_py_utf8 (GIArgument *arg) -{ - PyObject *py_obj = NULL; - if (arg->v_string == NULL) { - Py_RETURN_NONE; - } - - py_obj = PYGLIB_PyUnicode_FromString (arg->v_string); - return py_obj; -} - -static PyObject * -_pygi_marshal_to_py_filename (GIArgument *arg) -{ - gchar *string = NULL; - PyObject *py_obj = NULL; - GError *error = NULL; - - if (arg->v_string == NULL) { - Py_RETURN_NONE; - } - - string = g_filename_to_utf8 (arg->v_string, -1, NULL, NULL, &error); - if (string == NULL) { - PyErr_SetString (PyExc_Exception, error->message); - /* TODO: Convert the error to an exception. */ - return NULL; - } - - py_obj = PYGLIB_PyUnicode_FromString (string); - g_free (string); - - return py_obj; -} - - -/** - * _pygi_marshal_to_py_basic_type: - * @arg: The argument to convert to an object. - * @type_tag: Type tag for @arg - * @transfer: Transfer annotation - * - * Convert the given argument to a Python object. This function - * is restricted to simple types that only require the GITypeTag - * and GITransfer. For a more complete conversion routine, use: - * _pygi_argument_to_object. - * - * Returns: A PyObject representing @arg or NULL if it cannot convert - * the argument. - */ -PyObject * -_pygi_marshal_to_py_basic_type (GIArgument *arg, - GITypeTag type_tag, - GITransfer transfer) -{ - switch (type_tag) { - case GI_TYPE_TAG_BOOLEAN: - return PyBool_FromLong (arg->v_boolean); - - case GI_TYPE_TAG_INT8: - return PYGLIB_PyLong_FromLong (arg->v_int8); - - case GI_TYPE_TAG_UINT8: - return PYGLIB_PyLong_FromLong (arg->v_uint8); - - case GI_TYPE_TAG_INT16: - return PYGLIB_PyLong_FromLong (arg->v_int16); - - case GI_TYPE_TAG_UINT16: - return PYGLIB_PyLong_FromLong (arg->v_uint16); - - case GI_TYPE_TAG_INT32: - return PYGLIB_PyLong_FromLong (arg->v_int32); - - case GI_TYPE_TAG_UINT32: - return PyLong_FromLongLong (arg->v_uint32); - - case GI_TYPE_TAG_INT64: - return PyLong_FromLongLong (arg->v_int64); - - case GI_TYPE_TAG_UINT64: - return PyLong_FromUnsignedLongLong (arg->v_uint64); - - case GI_TYPE_TAG_FLOAT: - return PyFloat_FromDouble (arg->v_float); - - case GI_TYPE_TAG_DOUBLE: - return PyFloat_FromDouble (arg->v_double); - - case GI_TYPE_TAG_GTYPE: - return pyg_type_wrapper_new ( (GType) arg->v_long); - - case GI_TYPE_TAG_UNICHAR: - return _pygi_marshal_to_py_unichar (arg); - - case GI_TYPE_TAG_UTF8: - return _pygi_marshal_to_py_utf8 (arg); - - case GI_TYPE_TAG_FILENAME: - return _pygi_marshal_to_py_filename (arg); - - default: - return NULL; - } - return NULL; -} - -PyObject * -_pygi_marshal_to_py_basic_type_cache_adapter (PyGIInvokeState *state, - PyGICallableCache *callable_cache, - PyGIArgCache *arg_cache, - GIArgument *arg) -{ - return _pygi_marshal_to_py_basic_type (arg, - arg_cache->type_tag, - arg_cache->transfer); -} - -PyObject * -_pygi_marshal_to_py_array (PyGIInvokeState *state, - PyGICallableCache *callable_cache, - PyGIArgCache *arg_cache, - GIArgument *arg) -{ - GArray *array_; - PyObject *py_obj = NULL; - PyGISequenceCache *seq_cache = (PyGISequenceCache *)arg_cache; - gsize processed_items = 0; - - /* GArrays make it easier to iterate over arrays - * with different element sizes but requires that - * we allocate a GArray if the argument was a C array - */ - if (seq_cache->array_type == GI_ARRAY_TYPE_C) { - gsize len; - if (seq_cache->fixed_size >= 0) { - g_assert(arg->v_pointer != NULL); - len = seq_cache->fixed_size; - } else if (seq_cache->is_zero_terminated) { - if (arg->v_pointer == NULL) { - len = 0; - } else if (seq_cache->item_cache->type_tag == GI_TYPE_TAG_UINT8) { - len = strlen (arg->v_pointer); - } else { - len = g_strv_length ((gchar **)arg->v_pointer); - } - } else { - GIArgument *len_arg = state->args[seq_cache->len_arg_index]; - - if (!gi_argument_to_gsize (len_arg, - &len, - callable_cache->args_cache[seq_cache->len_arg_index]->type_tag)) { - return NULL; - } - } - - array_ = g_array_new (FALSE, - FALSE, - seq_cache->item_size); - if (array_ == NULL) { - PyErr_NoMemory (); - - if (arg_cache->transfer == GI_TRANSFER_EVERYTHING && arg->v_pointer != NULL) - g_free (arg->v_pointer); - - return NULL; - } - - if (array_->data != NULL) - g_free (array_->data); - array_->data = arg->v_pointer; - array_->len = len; - } else { - array_ = arg->v_pointer; - } - - if (seq_cache->item_cache->type_tag == GI_TYPE_TAG_UINT8) { - if (arg->v_pointer == NULL) { - py_obj = PYGLIB_PyBytes_FromString (""); - } else { - py_obj = PYGLIB_PyBytes_FromStringAndSize (array_->data, array_->len); - } - } else { - if (arg->v_pointer == NULL) { - py_obj = PyList_New (0); - } else { - int i; - - gsize item_size; - PyGIMarshalToPyFunc item_to_py_marshaller; - PyGIArgCache *item_arg_cache; - - py_obj = PyList_New (array_->len); - if (py_obj == NULL) - goto err; - - - item_arg_cache = seq_cache->item_cache; - item_to_py_marshaller = item_arg_cache->to_py_marshaller; - - item_size = g_array_get_element_size (array_); - - for (i = 0; i < array_->len; i++) { - GIArgument item_arg; - PyObject *py_item; - - if (seq_cache->array_type == GI_ARRAY_TYPE_PTR_ARRAY) { - item_arg.v_pointer = g_ptr_array_index ( ( GPtrArray *)array_, i); - } else if (item_arg_cache->type_tag == GI_TYPE_TAG_INTERFACE) { - PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *) item_arg_cache; - gboolean is_gvariant = iface_cache->g_type == G_TYPE_VARIANT; - - // 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 (is_gvariant) { - g_assert (item_size == sizeof (gpointer)); - if (arg_cache->transfer == GI_TRANSFER_EVERYTHING) - item_arg.v_pointer = g_variant_ref_sink (g_array_index (array_, gpointer, i)); - else - item_arg.v_pointer = g_array_index (array_, gpointer, i); - } else if (arg_cache->transfer == GI_TRANSFER_EVERYTHING && !item_arg_cache->is_pointer && - !g_type_is_a (iface_cache->g_type, G_TYPE_BOXED)) { - /* array elements are structs */ - gpointer *_struct = g_malloc (item_size); - memcpy (_struct, array_->data + i * item_size, - item_size); - item_arg.v_pointer = _struct; - } else if (item_arg_cache->is_pointer) - /* array elements are pointers to values */ - item_arg.v_pointer = g_array_index (array_, gpointer, i); - else - item_arg.v_pointer = array_->data + i * item_size; - break; - default: - item_arg.v_pointer = g_array_index (array_, gpointer, i); - break; - } - } else { - memcpy (&item_arg, array_->data + i * item_size, item_size); - } - - py_item = item_to_py_marshaller ( state, - callable_cache, - item_arg_cache, - &item_arg); - - if (py_item == NULL) { - Py_CLEAR (py_obj); - - if (seq_cache->array_type == GI_ARRAY_TYPE_C) - g_array_unref (array_); - - goto err; - } - PyList_SET_ITEM (py_obj, i, py_item); - processed_items++; - } - } - } - - if (seq_cache->array_type == GI_ARRAY_TYPE_C) - g_array_free (array_, FALSE); - - return py_obj; - -err: - if (seq_cache->array_type == GI_ARRAY_TYPE_C) { - g_array_free (array_, arg_cache->transfer == GI_TRANSFER_EVERYTHING); - } else { - /* clean up unprocessed items */ - if (seq_cache->item_cache->to_py_cleanup != NULL) { - int j; - PyGIMarshalCleanupFunc cleanup_func = seq_cache->item_cache->to_py_cleanup; - for (j = processed_items; j < array_->len; j++) { - cleanup_func (state, - seq_cache->item_cache, - g_array_index (array_, gpointer, j), - FALSE); - } - } - - if (arg_cache->transfer == GI_TRANSFER_EVERYTHING) - g_array_free (array_, TRUE); - } - - return NULL; -} - -PyObject * -_pygi_marshal_to_py_glist (PyGIInvokeState *state, - PyGICallableCache *callable_cache, - PyGIArgCache *arg_cache, - GIArgument *arg) -{ - GList *list_; - gsize length; - gsize i; - - PyGIMarshalToPyFunc item_to_py_marshaller; - PyGIArgCache *item_arg_cache; - PyGISequenceCache *seq_cache = (PyGISequenceCache *)arg_cache; - - PyObject *py_obj = NULL; - - list_ = arg->v_pointer; - length = g_list_length (list_); - - py_obj = PyList_New (length); - if (py_obj == NULL) - return NULL; - - item_arg_cache = seq_cache->item_cache; - item_to_py_marshaller = item_arg_cache->to_py_marshaller; - - for (i = 0; list_ != NULL; list_ = g_list_next (list_), i++) { - GIArgument item_arg; - PyObject *py_item; - - item_arg.v_pointer = list_->data; - _pygi_hash_pointer_to_arg (&item_arg, item_arg_cache->type_tag); - py_item = item_to_py_marshaller (state, - callable_cache, - item_arg_cache, - &item_arg); - - if (py_item == NULL) { - Py_CLEAR (py_obj); - _PyGI_ERROR_PREFIX ("Item %zu: ", i); - return NULL; - } - - PyList_SET_ITEM (py_obj, i, py_item); - } - - return py_obj; -} - -PyObject * -_pygi_marshal_to_py_gslist (PyGIInvokeState *state, - PyGICallableCache *callable_cache, - PyGIArgCache *arg_cache, - GIArgument *arg) -{ - GSList *list_; - gsize length; - gsize i; - - PyGIMarshalToPyFunc item_to_py_marshaller; - PyGIArgCache *item_arg_cache; - PyGISequenceCache *seq_cache = (PyGISequenceCache *)arg_cache; - - PyObject *py_obj = NULL; - - list_ = arg->v_pointer; - length = g_slist_length (list_); - - py_obj = PyList_New (length); - if (py_obj == NULL) - return NULL; - - item_arg_cache = seq_cache->item_cache; - item_to_py_marshaller = item_arg_cache->to_py_marshaller; - - for (i = 0; list_ != NULL; list_ = g_slist_next (list_), i++) { - GIArgument item_arg; - PyObject *py_item; - - item_arg.v_pointer = list_->data; - _pygi_hash_pointer_to_arg (&item_arg, item_arg_cache->type_tag); - py_item = item_to_py_marshaller (state, - callable_cache, - item_arg_cache, - &item_arg); - - if (py_item == NULL) { - Py_CLEAR (py_obj); - _PyGI_ERROR_PREFIX ("Item %zu: ", i); - return NULL; - } - - PyList_SET_ITEM (py_obj, i, py_item); - } - - return py_obj; -} - -PyObject * -_pygi_marshal_to_py_ghash (PyGIInvokeState *state, - PyGICallableCache *callable_cache, - PyGIArgCache *arg_cache, - GIArgument *arg) -{ - GHashTable *hash_; - GHashTableIter hash_table_iter; - - PyGIMarshalToPyFunc key_to_py_marshaller; - PyGIMarshalToPyFunc value_to_py_marshaller; - - PyGIArgCache *key_arg_cache; - PyGIArgCache *value_arg_cache; - PyGIHashCache *hash_cache = (PyGIHashCache *)arg_cache; - - GIArgument key_arg; - GIArgument value_arg; - - PyObject *py_obj = NULL; - - hash_ = arg->v_pointer; - - if (hash_ == NULL) { - py_obj = Py_None; - Py_INCREF (py_obj); - return py_obj; - } - - py_obj = PyDict_New (); - if (py_obj == NULL) - return NULL; - - key_arg_cache = hash_cache->key_cache; - key_to_py_marshaller = key_arg_cache->to_py_marshaller; - - value_arg_cache = hash_cache->value_cache; - value_to_py_marshaller = value_arg_cache->to_py_marshaller; - - g_hash_table_iter_init (&hash_table_iter, hash_); - while (g_hash_table_iter_next (&hash_table_iter, - &key_arg.v_pointer, - &value_arg.v_pointer)) { - PyObject *py_key; - PyObject *py_value; - int retval; - - - _pygi_hash_pointer_to_arg (&key_arg, hash_cache->key_cache->type_tag); - py_key = key_to_py_marshaller ( state, - callable_cache, - key_arg_cache, - &key_arg); - - if (py_key == NULL) { - Py_CLEAR (py_obj); - return NULL; - } - - _pygi_hash_pointer_to_arg (&value_arg, hash_cache->value_cache->type_tag); - py_value = value_to_py_marshaller ( state, - callable_cache, - value_arg_cache, - &value_arg); - - if (py_value == NULL) { - Py_CLEAR (py_obj); - Py_DECREF(py_key); - return NULL; - } - - retval = PyDict_SetItem (py_obj, py_key, py_value); - - Py_DECREF (py_key); - Py_DECREF (py_value); - - if (retval < 0) { - Py_CLEAR (py_obj); - return NULL; - } - } - - return py_obj; -} - -PyObject * -_pygi_marshal_to_py_gerror (PyGIInvokeState *state, - PyGICallableCache *callable_cache, - PyGIArgCache *arg_cache, - GIArgument *arg) -{ - GError *error = arg->v_pointer; - PyObject *py_obj = NULL; - - py_obj = pyglib_error_marshal(&error); - - if (arg_cache->transfer == GI_TRANSFER_EVERYTHING && error != NULL) { - g_error_free (error); - } - - if (py_obj != NULL) { - return py_obj; - } else { - Py_RETURN_NONE; - } -} - -PyObject * -_pygi_marshal_to_py_interface_callback (PyGIInvokeState *state, - PyGICallableCache *callable_cache, - PyGIArgCache *arg_cache, - GIArgument *arg) -{ - PyObject *py_obj = NULL; - - PyErr_Format (PyExc_NotImplementedError, - "Marshalling a callback to PyObject is not supported"); - return py_obj; -} - -PyObject * -_pygi_marshal_to_py_interface_enum (PyGIInvokeState *state, - PyGICallableCache *callable_cache, - PyGIArgCache *arg_cache, - GIArgument *arg) -{ - PyObject *py_obj = NULL; - PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache; - GIBaseInfo *interface; - long c_long; - - interface = g_type_info_get_interface (arg_cache->type_info); - g_assert (g_base_info_get_type (interface) == GI_INFO_TYPE_ENUM); - - if (!gi_argument_to_c_long(arg, &c_long, - g_enum_info_get_storage_type ((GIEnumInfo *)interface))) { - return NULL; - } - - if (iface_cache->g_type == G_TYPE_NONE) { - py_obj = PyObject_CallFunction (iface_cache->py_type, "l", c_long); - } else { - py_obj = pyg_enum_from_gtype (iface_cache->g_type, c_long); - } - g_base_info_unref (interface); - return py_obj; -} - -PyObject * -_pygi_marshal_to_py_interface_flags (PyGIInvokeState *state, - PyGICallableCache *callable_cache, - PyGIArgCache *arg_cache, - GIArgument *arg) -{ - PyObject *py_obj = NULL; - PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache; - GIBaseInfo *interface; - long c_long; - - interface = g_type_info_get_interface (arg_cache->type_info); - g_assert (g_base_info_get_type (interface) == GI_INFO_TYPE_FLAGS); - - if (!gi_argument_to_c_long(arg, &c_long, - g_enum_info_get_storage_type ((GIEnumInfo *)interface))) { - g_base_info_unref (interface); - return NULL; - } - - g_base_info_unref (interface); - if (iface_cache->g_type == G_TYPE_NONE) { - /* An enum with a GType of None is an enum without GType */ - - PyObject *py_type = _pygi_type_import_by_gi_info (iface_cache->interface_info); - PyObject *py_args = NULL; - - if (!py_type) - return NULL; - - py_args = PyTuple_New (1); - if (PyTuple_SetItem (py_args, 0, PyLong_FromLong (c_long)) != 0) { - Py_DECREF (py_args); - Py_DECREF (py_type); - return NULL; - } - - py_obj = PyObject_CallFunction (py_type, "l", c_long); - - Py_DECREF (py_args); - Py_DECREF (py_type); - } else { - py_obj = pyg_flags_from_gtype (iface_cache->g_type, c_long); - } - - return py_obj; -} - -PyObject * -_pygi_marshal_to_py_interface_struct_cache_adapter (PyGIInvokeState *state, - PyGICallableCache *callable_cache, - PyGIArgCache *arg_cache, - GIArgument *arg) -{ - PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache; - - return _pygi_marshal_to_py_interface_struct (arg, - iface_cache->interface_info, - iface_cache->g_type, - iface_cache->py_type, - arg_cache->transfer, - arg_cache->is_caller_allocates, - iface_cache->is_foreign); -} - -PyObject * -_pygi_marshal_to_py_interface_interface (PyGIInvokeState *state, - PyGICallableCache *callable_cache, - PyGIArgCache *arg_cache, - GIArgument *arg) -{ - PyObject *py_obj = NULL; - - PyErr_Format (PyExc_NotImplementedError, - "Marshalling for this type is not implemented yet"); - return py_obj; -} - -PyObject * -_pygi_marshal_to_py_interface_boxed (PyGIInvokeState *state, - PyGICallableCache *callable_cache, - PyGIArgCache *arg_cache, - GIArgument *arg) -{ - PyObject *py_obj = NULL; - - PyErr_Format (PyExc_NotImplementedError, - "Marshalling for this type is not implemented yet"); - return py_obj; -} - -PyObject * -_pygi_marshal_to_py_interface_object_cache_adapter (PyGIInvokeState *state, - PyGICallableCache *callable_cache, - PyGIArgCache *arg_cache, - GIArgument *arg) -{ - return _pygi_marshal_to_py_object(arg, arg_cache->transfer); -} - -PyObject * -_pygi_marshal_to_py_interface_union (PyGIInvokeState *state, - PyGICallableCache *callable_cache, - PyGIArgCache *arg_cache, - GIArgument *arg) -{ - PyObject *py_obj = NULL; - - PyErr_Format (PyExc_NotImplementedError, - "Marshalling for this type is not implemented yet"); - return py_obj; -} - -PyObject * -_pygi_marshal_to_py_object (GIArgument *arg, GITransfer transfer) { - PyObject *pyobj; - - if (arg->v_pointer == NULL) { - pyobj = Py_None; - Py_INCREF (pyobj); - - } else if (G_IS_PARAM_SPEC(arg->v_pointer)) { - pyobj = pyg_param_spec_new (arg->v_pointer); - if (transfer == GI_TRANSFER_EVERYTHING) - g_param_spec_unref (arg->v_pointer); - - } else { - pyobj = pygobject_new_full (arg->v_pointer, - /*steal=*/ transfer == GI_TRANSFER_EVERYTHING, - /*type=*/ NULL); - } - - return pyobj; -} - -PyObject * -_pygi_marshal_to_py_interface_struct (GIArgument *arg, - GIInterfaceInfo *interface_info, - GType g_type, - PyObject *py_type, - GITransfer transfer, - gboolean is_allocated, - gboolean is_foreign) -{ - PyObject *py_obj = NULL; - - if (arg->v_pointer == NULL) { - Py_RETURN_NONE; - } - - if (g_type_is_a (g_type, G_TYPE_VALUE)) { - py_obj = pyg_value_as_pyobject (arg->v_pointer, FALSE); - } else if (is_foreign) { - py_obj = pygi_struct_foreign_convert_from_g_argument (interface_info, - arg->v_pointer); - } else if (g_type_is_a (g_type, G_TYPE_BOXED)) { - if (py_type) { - py_obj = _pygi_boxed_new ((PyTypeObject *) py_type, - arg->v_pointer, - transfer == GI_TRANSFER_EVERYTHING || is_allocated, - is_allocated ? - g_struct_info_get_size(interface_info) : 0); - } - } else if (g_type_is_a (g_type, G_TYPE_POINTER)) { - if (py_type == NULL || - !PyType_IsSubtype ((PyTypeObject *) py_type, &PyGIStruct_Type)) { - g_warn_if_fail (transfer == GI_TRANSFER_NOTHING); - py_obj = pyg_pointer_new (g_type, arg->v_pointer); - } else { - py_obj = _pygi_struct_new ( (PyTypeObject *) py_type, - arg->v_pointer, - transfer == GI_TRANSFER_EVERYTHING); - } - } else if (g_type_is_a (g_type, G_TYPE_VARIANT)) { - /* Note we do not use transfer for the structs free_on_dealloc because - * GLib.Variant overrides __del__ to call "g_variant_unref". */ - if (py_type) { - g_variant_ref_sink (arg->v_pointer); - py_obj = _pygi_struct_new ((PyTypeObject *) py_type, - arg->v_pointer, - FALSE); - } - } else if (g_type == G_TYPE_NONE) { - if (py_type) { - py_obj = _pygi_struct_new ((PyTypeObject *) py_type, - arg->v_pointer, - transfer == GI_TRANSFER_EVERYTHING); - } - } else { - PyErr_Format (PyExc_NotImplementedError, - "structure type '%s' is not supported yet", - g_type_name (g_type)); - } - - return py_obj; -} diff --git a/gi/pygi-marshal-to-py.h b/gi/pygi-marshal-to-py.h deleted file mode 100644 index 1378630..0000000 --- a/gi/pygi-marshal-to-py.h +++ /dev/null @@ -1,104 +0,0 @@ -/* -*- Mode: C; c-basic-offset: 4 -*- - * vim: tabstop=4 shiftwidth=4 expandtab - * - * Copyright (C) 2011 John (J5) Palmieri <johnp@redhat.com>, Red Hat, Inc. - * - * 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 - */ - -#ifndef __PYGI_MARSHAL_TO_PY_H__ -#define __PYGI_MARSHAL_TO_PY_H__ - -PyObject *_pygi_marshal_to_py_basic_type (GIArgument *arg, - GITypeTag type_tag, - GITransfer transfer); -PyObject *_pygi_marshal_to_py_basic_type_cache_adapter (PyGIInvokeState *state, - PyGICallableCache *callable_cache, - PyGIArgCache *arg_cache, - GIArgument *arg); -PyObject *_pygi_marshal_to_py_void (PyGIInvokeState *state, - PyGICallableCache *callable_cache, - PyGIArgCache *arg_cache, - GIArgument *arg); -PyObject *_pygi_marshal_to_py_array (PyGIInvokeState *state, - PyGICallableCache *callable_cache, - PyGIArgCache *arg_cache, - GIArgument *arg); -PyObject *_pygi_marshal_to_py_glist (PyGIInvokeState *state, - PyGICallableCache *callable_cache, - PyGIArgCache *arg_cache, - GIArgument *arg); -PyObject *_pygi_marshal_to_py_gslist (PyGIInvokeState *state, - PyGICallableCache *callable_cache, - PyGIArgCache *arg_cache, - GIArgument *arg); -PyObject *_pygi_marshal_to_py_ghash (PyGIInvokeState *state, - PyGICallableCache *callable_cache, - PyGIArgCache *arg_cache, - GIArgument *arg); -PyObject *_pygi_marshal_to_py_gerror (PyGIInvokeState *state, - PyGICallableCache *callable_cache, - PyGIArgCache *arg_cache, - GIArgument *arg); -PyObject *_pygi_marshal_to_py_interface_callback(PyGIInvokeState *state, - PyGICallableCache *callable_cache, - PyGIArgCache *arg_cache, - GIArgument *arg); -PyObject *_pygi_marshal_to_py_interface_enum (PyGIInvokeState *state, - PyGICallableCache *callable_cache, - PyGIArgCache *arg_cache, - GIArgument *arg); -PyObject *_pygi_marshal_to_py_interface_flags (PyGIInvokeState *state, - PyGICallableCache *callable_cache, - PyGIArgCache *arg_cache, - GIArgument *arg); -PyObject *_pygi_marshal_to_py_interface_struct_cache_adapter (PyGIInvokeState *state, - PyGICallableCache *callable_cache, - PyGIArgCache *arg_cache, - GIArgument *arg); -PyObject *_pygi_marshal_to_py_interface_interface(PyGIInvokeState *state, - PyGICallableCache *callable_cache, - PyGIArgCache *arg_cache, - GIArgument *arg); -PyObject *_pygi_marshal_to_py_interface_boxed (PyGIInvokeState *state, - PyGICallableCache *callable_cache, - PyGIArgCache *arg_cache, - GIArgument *arg); -PyObject *_pygi_marshal_to_py_interface_object_cache_adapter (PyGIInvokeState *state, - PyGICallableCache *callable_cache, - PyGIArgCache *arg_cache, - GIArgument *arg); -PyObject *_pygi_marshal_to_py_interface_union (PyGIInvokeState *state, - PyGICallableCache *callable_cache, - PyGIArgCache *arg_cache, - GIArgument *arg); - -/* Simplified marshalers shared between vfunc/closure and direct function calls. */ - -PyObject *_pygi_marshal_to_py_object (GIArgument *arg, - GITransfer transfer); - -PyObject *_pygi_marshal_to_py_interface_struct (GIArgument *arg, - GIInterfaceInfo *interface_info, - GType g_type, - PyObject *py_type, - GITransfer transfer, - gboolean is_allocated, - gboolean is_foreign); - -G_END_DECLS - -#endif /* __PYGI_MARSHAL_TO_PY_H__ */ diff --git a/gi/pygi-object.c b/gi/pygi-object.c new file mode 100644 index 0000000..c97d2df --- /dev/null +++ b/gi/pygi-object.c @@ -0,0 +1,381 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- + * vim: tabstop=4 shiftwidth=4 expandtab + * + * Copyright (C) 2011 John (J5) Palmieri <johnp@redhat.com> + * Copyright (C) 2014 Simon Feltman <sfeltman@gnome.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <Python.h> +#include <glib.h> + +#include "pygi-object.h" +#include "pygobject-object.h" +#include "pygparamspec.h" + +/* + * GObject from Python + */ + +typedef gboolean (*PyGIObjectMarshalFromPyFunc) (PyObject *py_arg, + GIArgument *arg, + GITransfer transfer); + +/* _pygi_marshal_from_py_gobject: + * py_arg: (in): + * arg: (out): + */ +static gboolean +_pygi_marshal_from_py_gobject (PyObject *py_arg, /*in*/ + GIArgument *arg, /*out*/ + GITransfer transfer) { + GObject *gobj; + + if (py_arg == Py_None) { + arg->v_pointer = NULL; + return TRUE; + } + + if (!pygobject_check (py_arg, &PyGObject_Type)) { + PyObject *repr = PyObject_Repr (py_arg); + PyErr_Format(PyExc_TypeError, "expected GObject but got %s", + PyUnicode_AsUTF8 (repr)); + Py_DECREF (repr); + return FALSE; + } + + gobj = pygobject_get (py_arg); + if (gobj == NULL) { + PyErr_Format(PyExc_RuntimeError, "object at %p of type %s is not initialized", + py_arg, Py_TYPE(py_arg)->tp_name); + return FALSE; + } + + if (transfer == GI_TRANSFER_EVERYTHING) { + /* For transfer everything, add a new ref that the callee will take ownership of. + * Pythons existing ref to the GObject will be managed with the PyGObject wrapper. + */ + g_object_ref (gobj); + } + + arg->v_pointer = gobj; + return TRUE; +} + +/* pygi_arg_gobject_out_arg_from_py: + * py_arg: (in): + * arg: (out): + * + * A specialization for marshaling Python GObjects used for out/return values + * from a Python implemented vfuncs, signals, or an assignment to a GObject property. + */ +gboolean +pygi_arg_gobject_out_arg_from_py (PyObject *py_arg, /*in*/ + GIArgument *arg, /*out*/ + GITransfer transfer) { + GObject *gobj; + if (!_pygi_marshal_from_py_gobject (py_arg, arg, transfer)) { + return FALSE; + } + + /* HACK: At this point the basic marshaling of the GObject was successful + * but we add some special case hacks for vfunc returns due to buggy APIs: + * https://bugzilla.gnome.org/show_bug.cgi?id=693393 + */ + gobj = arg->v_pointer; + if (Py_REFCNT (py_arg) == 1 && gobj->ref_count == 1) { + /* If both object ref counts are only 1 at this point (the reference held + * in a return tuple), we assume the GObject will be free'd before reaching + * its target and become invalid. So instead of getting invalid object errors + * we add a new GObject ref. + */ + g_object_ref (gobj); + + if (((PyGObject *)py_arg)->private_flags.flags & PYGOBJECT_GOBJECT_WAS_FLOATING) { + /* + * We want to re-float instances that were floating and the Python + * wrapper assumed ownership. With the additional caveat that there + * are not any strong references beyond the return tuple. + */ + g_object_force_floating (gobj); + + } else { + PyObject *repr = PyObject_Repr (py_arg); + gchar *msg = g_strdup_printf ("Expecting to marshal a borrowed reference for %s, " + "but nothing in Python is holding a reference to this object. " + "See: https://bugzilla.gnome.org/show_bug.cgi?id=687522", + PyUnicode_AsUTF8 (repr)); + Py_DECREF (repr); + if (PyErr_WarnEx (PyExc_RuntimeWarning, msg, 2)) { + g_free (msg); + return FALSE; + } + g_free (msg); + } + } + + return TRUE; +} + +static gboolean +_pygi_marshal_from_py_interface_object (PyGIInvokeState *state, + PyGICallableCache *callable_cache, + PyGIArgCache *arg_cache, + PyObject *py_arg, + GIArgument *arg, + gpointer *cleanup_data, + PyGIObjectMarshalFromPyFunc func) +{ + PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache; + + if (py_arg == Py_None) { + arg->v_pointer = NULL; + return TRUE; + } + + if (PyObject_IsInstance (py_arg, iface_cache->py_type) || + (pygobject_check (py_arg, &PyGObject_Type) && + g_type_is_a (G_OBJECT_TYPE (pygobject_get (py_arg)), iface_cache->g_type))) { + + gboolean res; + res = func (py_arg, arg, arg_cache->transfer); + *cleanup_data = arg->v_pointer; + return res; + + } else { + PyObject *module = PyObject_GetAttrString(py_arg, "__module__"); + + PyErr_Format (PyExc_TypeError, "argument %s: Expected %s, but got %s%s%s", + arg_cache->arg_name ? arg_cache->arg_name : "self", + ( (PyGIInterfaceCache *)arg_cache)->type_name, + module ? PyUnicode_AsUTF8 (module) : "", + module ? "." : "", + Py_TYPE (py_arg)->tp_name); + if (module) + Py_DECREF (module); + return FALSE; + } +} + +static gboolean +_pygi_marshal_from_py_called_from_c_interface_object (PyGIInvokeState *state, + PyGICallableCache *callable_cache, + PyGIArgCache *arg_cache, + PyObject *py_arg, + GIArgument *arg, + gpointer *cleanup_data) +{ + return _pygi_marshal_from_py_interface_object (state, + callable_cache, + arg_cache, + py_arg, + arg, + cleanup_data, + pygi_arg_gobject_out_arg_from_py); +} + +static gboolean +_pygi_marshal_from_py_called_from_py_interface_object (PyGIInvokeState *state, + PyGICallableCache *callable_cache, + PyGIArgCache *arg_cache, + PyObject *py_arg, + GIArgument *arg, + gpointer *cleanup_data) +{ + return _pygi_marshal_from_py_interface_object (state, + callable_cache, + arg_cache, + py_arg, + arg, + cleanup_data, + _pygi_marshal_from_py_gobject); +} + +static void +_pygi_marshal_cleanup_from_py_interface_object (PyGIInvokeState *state, + PyGIArgCache *arg_cache, + PyObject *py_arg, + gpointer data, + gboolean was_processed) +{ + /* If we processed the parameter but fail before invoking the method, + we need to remove the ref we added */ + if (was_processed && state->failed && data != NULL && + arg_cache->transfer == GI_TRANSFER_EVERYTHING) + g_object_unref (G_OBJECT(data)); +} + + +/* + * GObject to Python + */ + +PyObject * +pygi_arg_gobject_to_py (GIArgument *arg, GITransfer transfer) { + PyObject *pyobj; + + if (arg->v_pointer == NULL) { + pyobj = Py_None; + Py_INCREF (pyobj); + + } else if (G_IS_PARAM_SPEC(arg->v_pointer)) { + pyobj = pyg_param_spec_new (arg->v_pointer); + if (transfer == GI_TRANSFER_EVERYTHING) + g_param_spec_unref (arg->v_pointer); + + } else if (G_IS_OBJECT(arg->v_pointer)) { + pyobj = pygobject_new_full (arg->v_pointer, + /*steal=*/ transfer == GI_TRANSFER_EVERYTHING, + /*type=*/ NULL); + } else { + PyErr_Format(PyExc_TypeError, + "No means to translate argument or return value for '%s'", + g_type_name_from_instance(arg->v_pointer)); + return NULL; + } + + return pyobj; +} + +PyObject * +pygi_arg_gobject_to_py_called_from_c (GIArgument *arg, + GITransfer transfer) +{ + PyObject *object; + + /* HACK: + * The following hack is to work around GTK sending signals which + * contain floating widgets in them. This assumes control of how + * references are added by the PyGObject wrapper and avoids the sink + * behavior by explicitly passing GI_TRANSFER_EVERYTHING as the transfer + * mode and then re-forcing the object as floating afterwards. + * + * See: https://bugzilla.gnome.org/show_bug.cgi?id=693400 + */ + if (arg->v_pointer != NULL && + transfer == GI_TRANSFER_NOTHING && + G_IS_OBJECT (arg->v_pointer) && + g_object_is_floating (arg->v_pointer)) { + + g_object_ref (arg->v_pointer); + object = pygi_arg_gobject_to_py (arg, GI_TRANSFER_EVERYTHING); + g_object_force_floating (arg->v_pointer); + } else { + object = pygi_arg_gobject_to_py (arg, transfer); + } + + return object; +} + +static PyObject * +_pygi_marshal_to_py_called_from_c_interface_object_cache_adapter (PyGIInvokeState *state, + PyGICallableCache *callable_cache, + PyGIArgCache *arg_cache, + GIArgument *arg, + gpointer *cleanup_data) +{ + return pygi_arg_gobject_to_py_called_from_c (arg, arg_cache->transfer); +} + +static PyObject * +_pygi_marshal_to_py_called_from_py_interface_object_cache_adapter (PyGIInvokeState *state, + PyGICallableCache *callable_cache, + PyGIArgCache *arg_cache, + GIArgument *arg, + gpointer *cleanup_data) +{ + return pygi_arg_gobject_to_py (arg, arg_cache->transfer); +} + +static void +_pygi_marshal_cleanup_to_py_interface_object (PyGIInvokeState *state, + PyGIArgCache *arg_cache, + gpointer cleanup_data, + gpointer data, + gboolean was_processed) +{ + /* If we error out and the object is not marshalled into a PyGObject + we must take care of removing the ref */ + if (!was_processed && arg_cache->transfer == GI_TRANSFER_EVERYTHING) + g_object_unref (G_OBJECT(data)); +} + +static gboolean +pygi_arg_gobject_setup_from_info (PyGIArgCache *arg_cache, + GITypeInfo *type_info, + GIArgInfo *arg_info, + GITransfer transfer, + PyGIDirection direction, + PyGICallableCache *callable_cache) +{ + /* NOTE: usage of pygi_arg_interface_new_from_info already calls + * pygi_arg_interface_setup so no need to do it here. + */ + + if (direction & PYGI_DIRECTION_FROM_PYTHON) { + if (callable_cache->calling_context == PYGI_CALLING_CONTEXT_IS_FROM_C) { + arg_cache->from_py_marshaller = _pygi_marshal_from_py_called_from_c_interface_object; + } else { + arg_cache->from_py_marshaller = _pygi_marshal_from_py_called_from_py_interface_object; + } + + arg_cache->from_py_cleanup = _pygi_marshal_cleanup_from_py_interface_object; + } + + if (direction & PYGI_DIRECTION_TO_PYTHON) { + if (callable_cache->calling_context == PYGI_CALLING_CONTEXT_IS_FROM_C) { + arg_cache->to_py_marshaller = _pygi_marshal_to_py_called_from_c_interface_object_cache_adapter; + } else { + arg_cache->to_py_marshaller = _pygi_marshal_to_py_called_from_py_interface_object_cache_adapter; + } + + arg_cache->to_py_cleanup = _pygi_marshal_cleanup_to_py_interface_object; + } + + return TRUE; +} + +PyGIArgCache * +pygi_arg_gobject_new_from_info (GITypeInfo *type_info, + GIArgInfo *arg_info, + GITransfer transfer, + PyGIDirection direction, + GIInterfaceInfo *iface_info, + PyGICallableCache *callable_cache) +{ + gboolean res = FALSE; + PyGIArgCache *cache = NULL; + + cache = pygi_arg_interface_new_from_info (type_info, + arg_info, + transfer, + direction, + iface_info); + if (cache == NULL) + return NULL; + + res = pygi_arg_gobject_setup_from_info (cache, + type_info, + arg_info, + transfer, + direction, + callable_cache); + if (res) { + return cache; + } else { + pygi_arg_cache_free (cache); + return NULL; + } +} diff --git a/gi/pygi-object.h b/gi/pygi-object.h new file mode 100644 index 0000000..360bce1 --- /dev/null +++ b/gi/pygi-object.h @@ -0,0 +1,52 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- + * vim: tabstop=4 shiftwidth=4 expandtab + * + * Copyright (C) 2014 Simon Feltman <sfeltman@gnome.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __PYGI_OBJECT_H__ +#define __PYGI_OBJECT_H__ + +#include <girepository.h> +#include "pygi-cache.h" + +G_BEGIN_DECLS + +gboolean +pygi_arg_gobject_out_arg_from_py (PyObject *py_arg, /* in */ + GIArgument *arg, /* out */ + GITransfer transfer); + +PyObject * +pygi_arg_gobject_to_py (GIArgument *arg, + GITransfer transfer); + +PyObject * +pygi_arg_gobject_to_py_called_from_c (GIArgument *arg, + GITransfer transfer); + + +PyGIArgCache * +pygi_arg_gobject_new_from_info (GITypeInfo *type_info, + GIArgInfo *arg_info, /* may be null */ + GITransfer transfer, + PyGIDirection direction, + GIInterfaceInfo *iface_info, + PyGICallableCache *callable_cache); + +G_END_DECLS + +#endif /*__PYGI_OBJECT_H__*/ diff --git a/gi/pygi-private.h b/gi/pygi-private.h deleted file mode 100644 index 97eced5..0000000 --- a/gi/pygi-private.h +++ /dev/null @@ -1,87 +0,0 @@ -/* -*- Mode: C; c-basic-offset: 4 -*- - * vim: tabstop=4 shiftwidth=4 expandtab - */ -#ifndef __PYGI_PRIVATE_H__ -#define __PYGI_PRIVATE_H__ - -#ifdef __PYGI_H__ -# error "Import pygi.h or pygi-private.h, but not both" -#endif - -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif - -#include <Python.h> - -#include "pygi.h" - -#include "pygobject-external.h" - -#include "pygi-repository.h" -#include "pygi-info.h" -#include "pygi-struct.h" -#include "pygi-boxed.h" -#include "pygi-argument.h" -#include "pygi-type.h" -#include "pygi-foreign.h" -#include "pygi-closure.h" -#include "pygi-ccallback.h" -#include "pygi-property.h" -#include "pygi-signal-closure.h" -#include "pygi-invoke.h" -#include "pygi-cache.h" -#include "pygi-source.h" - -G_BEGIN_DECLS -#if PY_VERSION_HEX >= 0x03000000 - -#define _PyGI_ERROR_PREFIX(format, ...) G_STMT_START { \ - PyObject *py_error_prefix; \ - py_error_prefix = PyUnicode_FromFormat(format, ## __VA_ARGS__); \ - if (py_error_prefix != NULL) { \ - PyObject *py_error_type, *py_error_value, *py_error_traceback; \ - PyErr_Fetch(&py_error_type, &py_error_value, &py_error_traceback); \ - if (PyUnicode_Check(py_error_value)) { \ - PyObject *new; \ - new = PyUnicode_Concat(py_error_prefix, py_error_value); \ - Py_DECREF(py_error_value); \ - if (new != NULL) { \ - py_error_value = new; \ - } \ - } \ - PyErr_Restore(py_error_type, py_error_value, py_error_traceback); \ - Py_DECREF(py_error_prefix); \ - } \ -} G_STMT_END - -#else - -#define _PyGI_ERROR_PREFIX(format, ...) G_STMT_START { \ - PyObject *py_error_prefix; \ - py_error_prefix = PyString_FromFormat(format, ## __VA_ARGS__); \ - if (py_error_prefix != NULL) { \ - PyObject *py_error_type, *py_error_value, *py_error_traceback; \ - PyErr_Fetch(&py_error_type, &py_error_value, &py_error_traceback); \ - if (PyString_Check(py_error_value)) { \ - PyString_ConcatAndDel(&py_error_prefix, py_error_value); \ - if (py_error_prefix != NULL) { \ - py_error_value = py_error_prefix; \ - } \ - } \ - PyErr_Restore(py_error_type, py_error_value, py_error_traceback); \ - } \ -} G_STMT_END - -#endif - -/* Redefine g_array_index because we want it to return the i-th element, casted - * to the type t, of the array a, and not the i-th element of the array a - * casted to the type t. */ -#define _g_array_index(a,t,i) \ - *(t *)((a)->data + g_array_get_element_size(a) * (i)) - - -G_END_DECLS - -#endif /* __PYGI_PRIVATE_H__ */ diff --git a/gi/pygi-property.c b/gi/pygi-property.c index 3f6d038..595167b 100644 --- a/gi/pygi-property.c +++ b/gi/pygi-property.c @@ -21,7 +21,11 @@ * IN THE SOFTWARE. */ -#include "pygi-private.h" +#include "pygi-property.h" +#include "pygi-value.h" +#include "pygi-argument.h" +#include "pygparamspec.h" +#include "pygi-type.h" #include <girepository.h> @@ -29,7 +33,7 @@ static GIPropertyInfo * lookup_property_from_object_info (GIObjectInfo *info, const gchar *attr_name) { gssize n_infos; - gssize i; + gint i; n_infos = g_object_info_get_n_properties (info); for (i = 0; i < n_infos; i++) { @@ -53,7 +57,7 @@ lookup_property_from_interface_info (GIInterfaceInfo *info, const gchar *attr_name) { gssize n_infos; - gssize i; + gint i; n_infos = g_interface_info_get_n_properties (info); for (i = 0; i < n_infos; i++) { @@ -95,185 +99,115 @@ _pygi_lookup_property_from_g_type (GType g_type, const gchar *attr_name) return ret; } -static inline gpointer -g_value_get_or_dup_boxed (const GValue *value, GITransfer transfer) +PyObject * +pygi_call_do_get_property (PyObject *instance, GParamSpec *pspec) { - if (transfer == GI_TRANSFER_EVERYTHING) - return g_value_dup_boxed (value); - else - return g_value_get_boxed (value); + PyObject *py_pspec; + PyObject *retval; + + py_pspec = pyg_param_spec_new (pspec); + retval = PyObject_CallMethod (instance, "do_get_property", "O", py_pspec); + Py_DECREF (py_pspec); + return retval; } PyObject * -pygi_get_property_value_real (PyGObject *instance, GParamSpec *pspec) +pygi_get_property_value (PyGObject *instance, GParamSpec *pspec) { GIPropertyInfo *property_info = NULL; GValue value = { 0, }; - GIArgument arg = { 0, }; PyObject *py_value = NULL; - GITypeInfo *type_info = NULL; - GITransfer transfer; - GITypeTag type_tag; + GType fundamental; + gboolean handled; - /* The owner_type of the pspec gives us the exact type that introduced the - * property, even if it is a parent class of the instance in question. */ - property_info = _pygi_lookup_property_from_g_type (pspec->owner_type, pspec->name); + if (!(pspec->flags & G_PARAM_READABLE)) { + PyErr_Format(PyExc_TypeError, "property %s is not readable", + g_param_spec_get_name (pspec)); + return NULL; + } - if (property_info == NULL) - goto out; + /* Fast path which calls the Python getter implementation directly. + * See: https://bugzilla.gnome.org/show_bug.cgi?id=723872 */ + if (pyg_gtype_is_custom (pspec->owner_type)) { + return pygi_call_do_get_property ((PyObject *)instance, pspec); + } + Py_BEGIN_ALLOW_THREADS; g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec)); g_object_get_property (instance->obj, pspec->name, &value); + fundamental = G_TYPE_FUNDAMENTAL (G_VALUE_TYPE (&value)); + Py_END_ALLOW_THREADS; - type_info = g_property_info_get_type (property_info); - transfer = g_property_info_get_ownership_transfer (property_info); - type_tag = g_type_info_get_tag (type_info); - switch (type_tag) { - case GI_TYPE_TAG_BOOLEAN: - arg.v_boolean = g_value_get_boolean (&value); - break; - case GI_TYPE_TAG_INT8: - arg.v_int8 = g_value_get_schar (&value); - break; - case GI_TYPE_TAG_INT16: - case GI_TYPE_TAG_INT32: - if (G_VALUE_HOLDS_LONG (&value)) - arg.v_long = g_value_get_long (&value); - else - arg.v_int = g_value_get_int (&value); - break; - case GI_TYPE_TAG_INT64: - if (G_VALUE_HOLDS_LONG (&value)) - arg.v_long = g_value_get_long (&value); - else - arg.v_int64 = g_value_get_int64 (&value); - break; - case GI_TYPE_TAG_UINT8: - arg.v_uint8 = g_value_get_uchar (&value); - break; - case GI_TYPE_TAG_UINT16: - case GI_TYPE_TAG_UINT32: - if (G_VALUE_HOLDS_ULONG (&value)) - arg.v_ulong = g_value_get_ulong (&value); - else - arg.v_uint = g_value_get_uint (&value); - break; - case GI_TYPE_TAG_UINT64: - if (G_VALUE_HOLDS_ULONG (&value)) - arg.v_ulong = g_value_get_ulong (&value); - else - arg.v_uint64 = g_value_get_uint64 (&value); - break; - case GI_TYPE_TAG_FLOAT: - arg.v_float = g_value_get_float (&value); - break; - case GI_TYPE_TAG_DOUBLE: - arg.v_double = g_value_get_double (&value); - break; - case GI_TYPE_TAG_GTYPE: - arg.v_size = g_value_get_gtype (&value); - break; - case GI_TYPE_TAG_UTF8: - case GI_TYPE_TAG_FILENAME: - arg.v_string = g_value_dup_string (&value); - break; - case GI_TYPE_TAG_INTERFACE: - { - GIBaseInfo *info; - GIInfoType info_type; - GType type; - - info = g_type_info_get_interface (type_info); - type = g_registered_type_info_get_g_type (info); - info_type = g_base_info_get_type (info); + /* Fast path basic types which don't need GI type info. */ + py_value = pygi_value_to_py_basic_type (&value, fundamental, &handled); + if (handled) { + goto out; + } - g_base_info_unref (info); + /* Attempt to marshal through GI. + * The owner_type of the pspec gives us the exact type that introduced the + * property, even if it is a parent class of the instance in question. */ + property_info = _pygi_lookup_property_from_g_type (pspec->owner_type, pspec->name); + if (property_info) { + GITypeInfo *type_info = NULL; + gboolean free_array = FALSE; + GIArgument arg = { 0, }; + GITransfer transfer = GI_TRANSFER_NOTHING; + + type_info = g_property_info_get_type (property_info); + arg = _pygi_argument_from_g_value (&value, type_info); + + /* Arrays are special cased, see note in _pygi_argument_to_array. */ + if (g_type_info_get_tag (type_info) == GI_TYPE_TAG_ARRAY) { + arg.v_pointer = _pygi_argument_to_array (&arg, NULL, NULL, NULL, + type_info, &free_array); + } else if (g_type_is_a (pspec->value_type, G_TYPE_BOXED)) { + arg.v_pointer = g_value_dup_boxed (&value); + transfer = GI_TRANSFER_EVERYTHING; + } - switch (info_type) { - case GI_INFO_TYPE_ENUM: - arg.v_int = g_value_get_enum (&value); - break; - case GI_INFO_TYPE_INTERFACE: - case GI_INFO_TYPE_OBJECT: - arg.v_pointer = g_value_get_object (&value); - break; - case GI_INFO_TYPE_BOXED: - case GI_INFO_TYPE_STRUCT: - case GI_INFO_TYPE_UNION: + py_value = _pygi_argument_to_object (&arg, type_info, transfer); - if (g_type_is_a (type, G_TYPE_BOXED)) { - arg.v_pointer = g_value_dup_boxed (&value); - } else if (g_type_is_a (type, G_TYPE_POINTER)) { - arg.v_pointer = g_value_get_pointer (&value); - } else if (g_type_is_a (type, G_TYPE_VARIANT)) { - arg.v_pointer = g_value_get_variant (&value); - } else { - PyErr_Format (PyExc_NotImplementedError, - "Retrieving properties of type '%s' is not implemented", - g_type_name (type)); - } - break; - default: - PyErr_Format (PyExc_NotImplementedError, - "Retrieving properties of type '%s' is not implemented", - g_type_name (type)); - goto out; - } - break; - } - case GI_TYPE_TAG_GHASH: - arg.v_pointer = g_value_get_or_dup_boxed (&value, transfer); - break; - case GI_TYPE_TAG_GLIST: - case GI_TYPE_TAG_GSLIST: - if (G_VALUE_HOLDS_BOXED(&value)) - arg.v_pointer = g_value_get_or_dup_boxed (&value, transfer); - else - arg.v_pointer = g_value_get_pointer (&value); - break; - case GI_TYPE_TAG_ARRAY: - { - gchar** strings; - GArray *arg_items; - int i; - - strings = g_value_get_or_dup_boxed (&value, transfer); - if (strings == NULL) - arg.v_pointer = NULL; - else { - arg_items = g_array_sized_new (TRUE, TRUE, sizeof (GIArgument), g_strv_length (strings)); - g_array_set_size (arg_items, g_strv_length (strings)); - for (i = 0; strings[i] != NULL; ++i) { - g_array_index (arg_items, GIArgument, i).v_string = strings[i]; - } - arg.v_pointer = arg_items; - } - break; + if (free_array) { + g_array_free (arg.v_pointer, FALSE); } - default: - PyErr_Format (PyExc_NotImplementedError, - "Retrieving properties of type %s is not implemented", - g_type_tag_to_string (g_type_info_get_tag (type_info))); - goto out; + + g_base_info_unref (type_info); + g_base_info_unref (property_info); } - py_value = _pygi_argument_to_object (&arg, type_info, transfer); - g_value_unset (&value); + /* Fallback to GValue marshalling. */ + if (py_value == NULL) { + py_value = pyg_param_gvalue_as_pyobject (&value, TRUE, pspec); + } out: - if (property_info != NULL) - g_base_info_unref (property_info); - if (type_info != NULL) - g_base_info_unref (type_info); - + g_value_unset (&value); return py_value; } +PyObject * +pygi_get_property_value_by_name (PyGObject *self, gchar *param_name) +{ + GParamSpec *pspec; + + pspec = g_object_class_find_property (G_OBJECT_GET_CLASS(self->obj), + param_name); + if (!pspec) { + PyErr_Format (PyExc_TypeError, + "object of type `%s' does not have property `%s'", + g_type_name (G_OBJECT_TYPE (self->obj)), param_name); + return NULL; + } + + return pygi_get_property_value (self, pspec); +} + gint -pygi_set_property_value_real (PyGObject *instance, - GParamSpec *pspec, - PyObject *py_value) +pygi_set_property_value (PyGObject *instance, + GParamSpec *pspec, + PyObject *py_value) { GIPropertyInfo *property_info = NULL; GITypeInfo *type_info = NULL; @@ -302,7 +236,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: @@ -321,6 +255,9 @@ pygi_set_property_value_real (PyGObject *instance, case GI_INFO_TYPE_ENUM: g_value_set_enum (&value, arg.v_int); break; + case GI_INFO_TYPE_FLAGS: + g_value_set_flags (&value, arg.v_uint); + break; case GI_INFO_TYPE_INTERFACE: case GI_INFO_TYPE_OBJECT: g_value_set_object (&value, arg.v_pointer); @@ -411,7 +348,7 @@ pygi_set_property_value_real (PyGObject *instance, */ GArray *arg_items = (GArray*) arg.v_pointer; gchar** strings; - int i; + guint i; if (arg_items == NULL) goto out; diff --git a/gi/pygi-property.h b/gi/pygi-property.h index 875d21e..d641b01 100644 --- a/gi/pygi-property.h +++ b/gi/pygi-property.h @@ -27,13 +27,22 @@ #include <Python.h> #include <girepository.h> -#include "pygi.h" +#include "pygobject-internal.h" -PyObject *pygi_get_property_value_real (PyGObject *instance, - GParamSpec *pspec); +PyObject * +pygi_get_property_value (PyGObject *instance, + GParamSpec *pspec); -gint pygi_set_property_value_real (PyGObject *instance, - GParamSpec *pspec, - PyObject *py_value); +PyObject * +pygi_get_property_value_by_name (PyGObject *self, + gchar *param_name); +PyObject * +pygi_call_do_get_property (PyObject *instance, + GParamSpec *pspec); + +gint +pygi_set_property_value (PyGObject *instance, + GParamSpec *pspec, + PyObject *py_value); #endif /* __PYGI_PROPERTY_H__ */ diff --git a/gi/pygi-repository.c b/gi/pygi-repository.c index d7c65f5..07fdc8f 100644 --- a/gi/pygi-repository.c +++ b/gi/pygi-repository.c @@ -16,18 +16,17 @@ * 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 + * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ -#include "pygi-private.h" - -#include <pyglib-python-compat.h> +#include "pygi-repository.h" +#include "pygi-info.h" +#include "pygi-basictype.h" +#include "pygi-util.h" PyObject *PyGIRepositoryError; -PYGLIB_DEFINE_TYPE("gi.Repository", PyGIRepository_Type, PyGIRepository); +PYGI_DEFINE_TYPE("gi.Repository", PyGIRepository_Type, PyGIRepository); static PyObject * _wrap_g_irepository_enumerate_versions (PyGIRepository *self, @@ -48,7 +47,7 @@ _wrap_g_irepository_enumerate_versions (PyGIRepository *self, ret = PyList_New(0); for (item = versions; item; item = item->next) { char *version = item->data; - PyObject *py_version = PYGLIB_PyUnicode_FromString (version); + PyObject *py_version = pygi_utf8_to_py (version); PyList_Append(ret, py_version); Py_DECREF(py_version); g_free (version); @@ -110,6 +109,24 @@ _wrap_g_irepository_require (PyGIRepository *self, } static PyObject * +_wrap_g_irepository_is_registered (PyGIRepository *self, + PyObject *args, + PyObject *kwargs) +{ + static char *kwlist[] = { "namespace", "version", NULL }; + const char *namespace_; + const char *version = NULL; + + if (!PyArg_ParseTupleAndKeywords (args, kwargs, "s|z:Repository.is_registered", + kwlist, &namespace_, &version)) { + return NULL; + } + + return pygi_gboolean_to_py (g_irepository_is_registered (self->repository, + namespace_, version)); +} + +static PyObject * _wrap_g_irepository_find_by_name (PyGIRepository *self, PyObject *args, PyObject *kwargs) @@ -164,7 +181,7 @@ _wrap_g_irepository_get_infos (PyGIRepository *self, const char *namespace_; gssize n_infos; PyObject *infos; - gssize i; + gint i; if (!PyArg_ParseTupleAndKeywords (args, kwargs, "s:Repository.get_infos", kwlist, &namespace_)) { @@ -221,7 +238,7 @@ _wrap_g_irepository_get_typelib_path (PyGIRepository *self, return NULL; } - return PYGLIB_PyBytes_FromString (typelib_path); + return pygi_filename_to_py (typelib_path); } static PyObject * @@ -244,7 +261,7 @@ _wrap_g_irepository_get_version (PyGIRepository *self, return NULL; } - return PYGLIB_PyUnicode_FromString (version); + return pygi_utf8_to_py (version); } static PyObject * @@ -258,7 +275,7 @@ _wrap_g_irepository_get_loaded_namespaces (PyGIRepository *self) py_namespaces = PyList_New (0); for (i = 0; namespaces[i] != NULL; i++) { - PyObject *py_namespace = PYGLIB_PyUnicode_FromString (namespaces[i]); + PyObject *py_namespace = pygi_utf8_to_py (namespaces[i]); PyList_Append (py_namespaces, py_namespace); Py_DECREF(py_namespace); g_free (namespaces[i]); @@ -269,6 +286,74 @@ _wrap_g_irepository_get_loaded_namespaces (PyGIRepository *self) return py_namespaces; } +static PyObject * +_wrap_g_irepository_get_dependencies (PyGIRepository *self, + PyObject *args, + PyObject *kwargs) +{ + static char *kwlist[] = { "namespace", NULL }; + const char *namespace_; + char **namespaces; + PyObject *py_namespaces; + gssize i; + + if (!PyArg_ParseTupleAndKeywords (args, kwargs, + "s:Repository.get_dependencies", kwlist, &namespace_)) { + return NULL; + } + + py_namespaces = PyList_New (0); + /* Returns NULL in case of no dependencies */ + namespaces = g_irepository_get_dependencies (self->repository, namespace_); + if (namespaces == NULL) { + return py_namespaces; + } + + for (i = 0; namespaces[i] != NULL; i++) { + PyObject *py_namespace = pygi_utf8_to_py (namespaces[i]); + PyList_Append (py_namespaces, py_namespace); + Py_DECREF(py_namespace); + } + + g_strfreev (namespaces); + + return py_namespaces; +} + + +static PyObject * +_wrap_g_irepository_get_immediate_dependencies (PyGIRepository *self, + PyObject *args, + PyObject *kwargs) +{ + static char *kwlist[] = { "namespace", NULL }; + const char *namespace_; + char **namespaces; + PyObject *py_namespaces; + gssize i; + + if (!PyArg_ParseTupleAndKeywords (args, kwargs, + "s:Repository.get_immediate_dependencies", + kwlist, &namespace_)) { + return NULL; + } + + py_namespaces = PyList_New (0); + namespaces = g_irepository_get_immediate_dependencies (self->repository, + namespace_); + + for (i = 0; namespaces[i] != NULL; i++) { + PyObject *py_namespace = pygi_utf8_to_py (namespaces[i]); + PyList_Append (py_namespaces, py_namespace); + Py_DECREF (py_namespace); + } + + g_strfreev (namespaces); + + return py_namespaces; +} + + static PyMethodDef _PyGIRepository_methods[] = { { "enumerate_versions", (PyCFunction) _wrap_g_irepository_enumerate_versions, METH_VARARGS | METH_KEYWORDS }, { "get_default", (PyCFunction) _wrap_g_irepository_get_default, METH_STATIC | METH_NOARGS }, @@ -278,28 +363,41 @@ static PyMethodDef _PyGIRepository_methods[] = { { "get_typelib_path", (PyCFunction) _wrap_g_irepository_get_typelib_path, METH_VARARGS | METH_KEYWORDS }, { "get_version", (PyCFunction) _wrap_g_irepository_get_version, METH_VARARGS | METH_KEYWORDS }, { "get_loaded_namespaces", (PyCFunction) _wrap_g_irepository_get_loaded_namespaces, METH_NOARGS }, + { "get_dependencies", (PyCFunction) _wrap_g_irepository_get_dependencies, METH_VARARGS | METH_KEYWORDS }, + { "get_immediate_dependencies", (PyCFunction) _wrap_g_irepository_get_immediate_dependencies, METH_VARARGS | METH_KEYWORDS }, + { "is_registered", (PyCFunction) _wrap_g_irepository_is_registered, METH_VARARGS | METH_KEYWORDS }, { NULL, NULL, 0 } }; -void -_pygi_repository_register_types (PyObject *m) +/** + * Returns 0 on success, or -1 and sets an exception. + */ +int +pygi_repository_register_types (PyObject *m) { - Py_TYPE(&PyGIRepository_Type) = &PyType_Type; + Py_SET_TYPE(&PyGIRepository_Type, &PyType_Type); PyGIRepository_Type.tp_flags = Py_TPFLAGS_DEFAULT; PyGIRepository_Type.tp_methods = _PyGIRepository_methods; - if (PyType_Ready (&PyGIRepository_Type)) { - return; - } + if (PyType_Ready (&PyGIRepository_Type) < 0) + return -1; - if (PyModule_AddObject (m, "Repository", (PyObject *) &PyGIRepository_Type)) { - return; + Py_INCREF ((PyObject *) &PyGIRepository_Type); + if (PyModule_AddObject (m, "Repository", (PyObject *) &PyGIRepository_Type) < 0) { + Py_DECREF ((PyObject *) &PyGIRepository_Type); + return -1; } PyGIRepositoryError = PyErr_NewException ("gi.RepositoryError", NULL, NULL); - if (PyModule_AddObject (m, "RepositoryError", PyGIRepositoryError)) { - return; + if (PyGIRepositoryError == NULL) + return -1; + + Py_INCREF (PyGIRepositoryError); + if (PyModule_AddObject (m, "RepositoryError", PyGIRepositoryError) < 0) { + Py_DECREF (PyGIRepositoryError); + return -1; } -} + return 0; +} diff --git a/gi/pygi-repository.h b/gi/pygi-repository.h index d8eb8cf..2207de3 100644 --- a/gi/pygi-repository.h +++ b/gi/pygi-repository.h @@ -14,25 +14,29 @@ * 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 + * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ #ifndef __PYGI_REPOSITORY_H__ #define __PYGI_REPOSITORY_H__ #include <Python.h> +#include <girepository.h> G_BEGIN_DECLS +typedef struct { + PyObject_HEAD + GIRepository *repository; +} PyGIRepository; + /* Private */ extern PyTypeObject PyGIRepository_Type; extern PyObject *PyGIRepositoryError; -void _pygi_repository_register_types (PyObject *m); +int pygi_repository_register_types (PyObject *m); G_END_DECLS diff --git a/gi/pygi-resulttuple.c b/gi/pygi-resulttuple.c new file mode 100644 index 0000000..93170ea --- /dev/null +++ b/gi/pygi-resulttuple.c @@ -0,0 +1,368 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- + * vim: tabstop=4 shiftwidth=4 expandtab + * + * Copyright (C) 2015 Christoph Reiter <reiter.christoph@gmail.com> + * + * 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, see <http://www.gnu.org/licenses/>. + */ + +#include <Python.h> +#include <glib.h> +#include "pygi-resulttuple.h" +#include "pygi-util.h" + +static char repr_format_key[] = "__repr_format"; +static char tuple_indices_key[] = "__tuple_indices"; + +#define PYGI_USE_FREELIST + +#ifdef PYPY_VERSION +#undef PYGI_USE_FREELIST +#endif + +#ifdef PYGI_USE_FREELIST +/* A free list similar to the one used for the CPython tuple. Difference + * is that zero length tuples aren't cached (as we don't need them) + * and that the freelist is smaller as we don't free it with the cyclic GC + * as CPython does. This wastes 21kB max. + */ +#define PyGIResultTuple_MAXSAVESIZE 10 +#define PyGIResultTuple_MAXFREELIST 100 +static PyObject *free_list[PyGIResultTuple_MAXSAVESIZE]; +static int numfree[PyGIResultTuple_MAXSAVESIZE]; +#endif + +PYGI_DEFINE_TYPE ("gi._gi.ResultTuple", PyGIResultTuple_Type, PyTupleObject) + +/** + * ResultTuple.__repr__() implementation. + * Takes the _ResultTuple.__repr_format format string and applies the tuple + * values to it. + */ +static PyObject* +resulttuple_repr(PyObject *self) { + PyObject *format, *repr, *format_attr; + + format_attr = PyUnicode_FromString (repr_format_key); + format = PyTuple_Type.tp_getattro (self, format_attr); + Py_DECREF (format_attr); + if (format == NULL) + return NULL; + repr = PyUnicode_Format (format, self); + Py_DECREF (format); + return repr; +} + +/** + * PyGIResultTuple_Type.tp_getattro implementation. + * Looks up the tuple index in _ResultTuple.__tuple_indices and returns the + * tuple item. + */ +static PyObject* +resulttuple_getattro(PyObject *self, PyObject *name) { + PyObject *mapping, *index, *mapping_attr, *item; + + mapping_attr = PyUnicode_FromString (tuple_indices_key); + mapping = PyTuple_Type.tp_getattro (self, mapping_attr); + Py_DECREF (mapping_attr); + if (mapping == NULL) + return NULL; + g_assert (PyDict_Check (mapping)); + index = PyDict_GetItem (mapping, name); + + if (index != NULL) { + item = PyTuple_GET_ITEM (self, PyLong_AsSsize_t (index)); + Py_INCREF (item); + } else { + item = PyTuple_Type.tp_getattro (self, name); + } + Py_DECREF (mapping); + + return item; +} + +/** + * ResultTuple.__reduce__() implementation. + * Always returns (tuple, tuple(self)) + * Needed so that pickling doesn't depend on our tuple subclass and unpickling + * works without it. As a result unpickle will give back in a normal tuple. + */ +static PyObject * +resulttuple_reduce(PyObject *self) +{ + PyObject *tuple = PySequence_Tuple (self); + if (tuple == NULL) + return NULL; + return Py_BuildValue ("(O, (N))", &PyTuple_Type, tuple); +} + +/** + * Extends __dir__ with the extra attributes accessible through + * resulttuple_getattro() + */ +static PyObject * +resulttuple_dir(PyObject *self) +{ + PyObject *mapping_attr; + PyObject *items = NULL; + PyObject *mapping = NULL; + PyObject *mapping_values = NULL; + PyObject *result = NULL; + + mapping_attr = PyUnicode_FromString (tuple_indices_key); + mapping = PyTuple_Type.tp_getattro (self, mapping_attr); + Py_DECREF (mapping_attr); + if (mapping == NULL) + goto error; + items = PyObject_Dir ((PyObject*)Py_TYPE (self)); + if (items == NULL) + goto error; + mapping_values = PyDict_Keys (mapping); + if (mapping_values == NULL) + goto error; + result = PySequence_InPlaceConcat (items, mapping_values); + +error: + Py_XDECREF (items); + Py_XDECREF (mapping); + Py_XDECREF (mapping_values); + + return result; +} + +/** + * resulttuple_new_type: + * @args: one list object containing tuple item names and None + * + * Exposes pygi_resulttuple_new_type() as ResultTuple._new_type() + * to allow creation of result types for unit tests. + * + * Returns: A new PyTypeObject which is a subclass of PyGIResultTuple_Type + * or %NULL in case of an error. + */ +static PyObject * +resulttuple_new_type(PyObject *self, PyObject *args) { + PyObject *tuple_names, *new_type; + + if (!PyArg_ParseTuple (args, "O:ResultTuple._new_type", &tuple_names)) + return NULL; + + if (!PyList_Check (tuple_names)) { + PyErr_SetString (PyExc_TypeError, "not a list"); + return NULL; + } + + new_type = (PyObject *)pygi_resulttuple_new_type (tuple_names); + return new_type; +} + +static PyMethodDef resulttuple_methods[] = { + {"__reduce__", (PyCFunction)resulttuple_reduce, METH_NOARGS}, + {"__dir__", (PyCFunction)resulttuple_dir, METH_NOARGS}, + {"_new_type", (PyCFunction)resulttuple_new_type, + METH_VARARGS | METH_STATIC}, + {NULL, NULL, 0}, +}; + +/** + * pygi_resulttuple_new_type: + * @tuple_names: A python list containing str or None items. + * + * Similar to namedtuple() creates a new tuple subclass which + * allows to access items by name and have a pretty __repr__. + * Each item in the passed name list corresponds to an item with + * the same index in the tuple class. If the name is None the item/index + * is unnamed. + * + * Returns: A new PyTypeObject which is a subclass of PyGIResultTuple_Type + * or %NULL in case of an error. + */ +PyTypeObject* +pygi_resulttuple_new_type(PyObject *tuple_names) { + PyTypeObject *new_type; + PyObject *class_dict, *format_string, *empty_format, *named_format, + *format_list, *sep, *index_dict, *slots, *paren_format, *new_type_args, + *paren_string; + Py_ssize_t len, i; + + g_assert (PyList_Check (tuple_names)); + + class_dict = PyDict_New (); + + /* To save some memory don't use an instance dict */ + slots = PyTuple_New (0); + PyDict_SetItemString (class_dict, "__slots__", slots); + Py_DECREF (slots); + + format_list = PyList_New (0); + index_dict = PyDict_New (); + + empty_format = PyUnicode_FromString ("%r"); + named_format = PyUnicode_FromString ("%s=%%r"); + len = PyList_Size (tuple_names); + for (i = 0; i < len; i++) { + PyObject *item, *named_args, *named_build, *index; + item = PyList_GET_ITEM (tuple_names, i); + if (item == Py_None) { + PyList_Append (format_list, empty_format); + } else { + named_args = Py_BuildValue ("(O)", item); + named_build = PyUnicode_Format (named_format, named_args); + Py_DECREF (named_args); + PyList_Append (format_list, named_build); + Py_DECREF (named_build); + index = PyLong_FromSsize_t (i); + PyDict_SetItem (index_dict, item, index); + Py_DECREF (index); + } + } + Py_DECREF (empty_format); + Py_DECREF (named_format); + + sep = PyUnicode_FromString (", "); + format_string = PyObject_CallMethod (sep, "join", "O", format_list); + Py_DECREF (sep); + Py_DECREF (format_list); + paren_format = PyUnicode_FromString ("(%s)"); + paren_string = PyUnicode_Format (paren_format, format_string); + Py_DECREF (paren_format); + Py_DECREF (format_string); + + PyDict_SetItemString (class_dict, repr_format_key, paren_string); + Py_DECREF (paren_string); + + PyDict_SetItemString (class_dict, tuple_indices_key, index_dict); + Py_DECREF (index_dict); + + new_type_args = Py_BuildValue ("s(O)O", "_ResultTuple", + &PyGIResultTuple_Type, class_dict); + new_type = (PyTypeObject *)PyType_Type.tp_new (&PyType_Type, + new_type_args, NULL); + Py_DECREF (new_type_args); + Py_DECREF (class_dict); + + if (new_type != NULL) { + /* disallow subclassing as that would break the free list caching + * since we assume that all subclasses use PyTupleObject */ + new_type->tp_flags &= ~Py_TPFLAGS_BASETYPE; + } + + return new_type; +} + + +/** + * pygi_resulttuple_new: + * @subclass: A PyGIResultTuple_Type subclass which will be the type of the + * returned instance. + * @len: Length of the returned tuple + * + * Like PyTuple_New(). Return an uninitialized tuple of the given @length. + * + * Returns: An instance of @subclass or %NULL on error. + */ +PyObject * +pygi_resulttuple_new(PyTypeObject *subclass, Py_ssize_t len) { +#ifdef PYGI_USE_FREELIST + PyObject *self; + Py_ssize_t i; + + /* Check the free list for a tuple object with the needed size; + * clear it and change the class to ours. + */ + if (len > 0 && len < PyGIResultTuple_MAXSAVESIZE) { + self = free_list[len]; + if (self != NULL) { + free_list[len] = PyTuple_GET_ITEM (self, 0); + numfree[len]--; + for (i=0; i < len; i++) { + PyTuple_SET_ITEM (self, i, NULL); + } + Py_SET_TYPE (self, subclass); + Py_INCREF (subclass); + _Py_NewReference (self); + PyObject_GC_Track (self); + return self; + } + } +#endif + + /* For zero length tuples and in case the free list is empty, alloc + * as usual. + */ + return subclass->tp_alloc (subclass, len); +} + +#ifdef PYGI_USE_FREELIST +static void resulttuple_dealloc(PyObject *self) { + Py_ssize_t i, len; + + PyObject_GC_UnTrack (self); + CPy_TRASHCAN_BEGIN (self, resulttuple_dealloc) + + /* Free the tuple items and, if there is space, save the tuple object + * pointer to the front of the free list for its size. Otherwise free it. + */ + len = Py_SIZE (self); + if (len > 0) { + for (i=0; i < len; i++) { + Py_XDECREF (PyTuple_GET_ITEM (self, i)); + } + + if (len < PyGIResultTuple_MAXSAVESIZE && numfree[len] < PyGIResultTuple_MAXFREELIST) { + PyTuple_SET_ITEM (self, 0, free_list[len]); + numfree[len]++; + free_list[len] = self; + goto done; + } + } + + Py_TYPE (self)->tp_free (self); + +done: + CPy_TRASHCAN_END (self) +} +#endif + +/** + * pygi_resulttuple_register_types: + * @module: A Python modules to which ResultTuple gets added to. + * + * Initializes the ResultTuple class and adds it to the passed @module. + * + * Returns: -1 on error, 0 on success. + */ +int pygi_resulttuple_register_types(PyObject *module) { + + PyGIResultTuple_Type.tp_base = &PyTuple_Type; + PyGIResultTuple_Type.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE; + PyGIResultTuple_Type.tp_repr = (reprfunc)resulttuple_repr; + PyGIResultTuple_Type.tp_getattro = (getattrofunc)resulttuple_getattro; + PyGIResultTuple_Type.tp_methods = resulttuple_methods; +#ifdef PYGI_USE_FREELIST + PyGIResultTuple_Type.tp_dealloc = (destructor)resulttuple_dealloc; +#endif + + if (PyType_Ready (&PyGIResultTuple_Type) < 0) + return -1; + + Py_INCREF (&PyGIResultTuple_Type); + if (PyModule_AddObject (module, "ResultTuple", + (PyObject *)&PyGIResultTuple_Type) < 0) { + Py_DECREF (&PyGIResultTuple_Type); + return -1; + } + + return 0; +} diff --git a/gi/_gobject/pygenum.h b/gi/pygi-resulttuple.h index 0558831..3f63ca0 100644 --- a/gi/_gobject/pygenum.h +++ b/gi/pygi-resulttuple.h @@ -1,7 +1,7 @@ /* -*- Mode: C; c-basic-offset: 4 -*- - * pygtk- Python bindings for the GTK toolkit. - * Copyright (C) 1998-2003 James Henstridge - * 2004-2008 Johan Dahlin + * vim: tabstop=4 shiftwidth=4 expandtab + * + * Copyright (C) 2015 Christoph Reiter <reiter.christoph@gmail.com> * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -14,14 +14,21 @@ * 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 + * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ -#ifndef __PYGOBJECT_ENUM_H__ -#define __PYGOBJECT_ENUM_H__ +#ifndef __PYGI_RESULTTUPLE_H__ +#define __PYGI_RESULTTUPLE_H__ + +#include "Python.h" + +int +pygi_resulttuple_register_types (PyObject *d); + +PyTypeObject * +pygi_resulttuple_new_type (PyObject *tuple_names); -void pygobject_enum_register_types(PyObject *d); +PyObject* +pygi_resulttuple_new (PyTypeObject *subclass, Py_ssize_t len); -#endif /* __PYGOBJECT_ENUM_H__ */ +#endif /* __PYGI_RESULTTUPLE_H__ */ diff --git a/gi/pygi-signal-closure.c b/gi/pygi-signal-closure.c index bcd1320..d553d76 100644 --- a/gi/pygi-signal-closure.c +++ b/gi/pygi-signal-closure.c @@ -13,12 +13,13 @@ * 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 + * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ -#include "pygi-private.h" +#include "pygi-signal-closure.h" +#include "pygi-value.h" +#include "pygi-argument.h" +#include "pygi-boxed.h" static GISignalInfo * _pygi_lookup_signal_from_g_type (GType g_type, @@ -80,11 +81,14 @@ pygi_signal_closure_marshal(GClosure *closure, GISignalInfo *signal_info; gint n_sig_info_args; gint sig_info_highest_arg; + GSList *list_item = NULL; + GSList *pass_by_ref_structs = NULL; state = PyGILState_Ensure(); signal_info = ((PyGISignalClosure *)closure)->signal_info; n_sig_info_args = g_callable_info_get_n_args(signal_info); + g_assert_cmpint (n_sig_info_args, >=, 0); /* the first argument to a signal callback is instance, but instance is not counted in the introspection data */ sig_info_highest_arg = n_sig_info_args + 1; @@ -107,34 +111,78 @@ pygi_signal_closure_marshal(GClosure *closure, } PyTuple_SetItem(params, i, item); - } else if (i < sig_info_highest_arg) { + } else if (i < (guint)sig_info_highest_arg) { GIArgInfo arg_info; GITypeInfo type_info; - GITransfer transfer; + GITypeTag type_tag; GIArgument arg = { 0, }; PyObject *item = NULL; gboolean free_array = FALSE; + gboolean pass_struct_by_ref = FALSE; g_callable_info_load_arg(signal_info, i - 1, &arg_info); g_arg_info_load_type(&arg_info, &type_info); - transfer = g_arg_info_get_ownership_transfer(&arg_info); arg = _pygi_argument_from_g_value(¶m_values[i], &type_info); - - if (g_type_info_get_tag (&type_info) == GI_TYPE_TAG_ARRAY) { + + type_tag = g_type_info_get_tag (&type_info); + if (type_tag == GI_TYPE_TAG_ARRAY) { /* Skip the self argument of param_values */ - arg.v_pointer = _pygi_argument_to_array (&arg, NULL, param_values + 1, signal_info, - &type_info, &free_array); + arg.v_pointer = _pygi_argument_to_array (&arg, + _pygi_argument_array_length_marshal, + (void *)(param_values + 1), + signal_info, + &type_info, + &free_array); + } + + /* Hack to ensure struct arguments are passed-by-reference allowing + * callback implementors to modify the struct values. This is needed + * for keeping backwards compatibility and should be removed in future + * versions which support signal output arguments as return values. + * See: https://bugzilla.gnome.org/show_bug.cgi?id=735486 + * + * Note the logic here must match the logic path taken in _pygi_argument_to_object. + */ + if (type_tag == GI_TYPE_TAG_INTERFACE) { + GIBaseInfo *info = g_type_info_get_interface (&type_info); + GIInfoType info_type = g_base_info_get_type (info); + + if (info_type == GI_INFO_TYPE_STRUCT || + info_type == GI_INFO_TYPE_BOXED || + info_type == GI_INFO_TYPE_UNION) { + + GType gtype = g_registered_type_info_get_g_type ((GIRegisteredTypeInfo *) info); + gboolean is_foreign = (info_type == GI_INFO_TYPE_STRUCT) && + (g_struct_info_is_foreign ((GIStructInfo *) info)); + + if (!is_foreign && !g_type_is_a (gtype, G_TYPE_VALUE) && + g_type_is_a (gtype, G_TYPE_BOXED)) { + pass_struct_by_ref = TRUE; + } + } + + g_base_info_unref (info); } - - item = _pygi_argument_to_object (&arg, &type_info, transfer); - + + if (pass_struct_by_ref) { + /* transfer everything will ensure the struct is not copied when wrapped. */ + item = _pygi_argument_to_object (&arg, &type_info, GI_TRANSFER_EVERYTHING); + if (item && PyObject_IsInstance (item, (PyObject *) &PyGIBoxed_Type)) { + ((PyGBoxed *)item)->free_on_dealloc = FALSE; + pass_by_ref_structs = g_slist_prepend (pass_by_ref_structs, item); + } + + } else { + item = _pygi_argument_to_object (&arg, &type_info, GI_TRANSFER_NOTHING); + } + if (free_array) { g_array_free (arg.v_pointer, FALSE); } - if (item == NULL) { + PyErr_Print (); goto out; } PyTuple_SetItem(params, i, item); @@ -166,18 +214,35 @@ pygi_signal_closure_marshal(GClosure *closure, } Py_DECREF(ret); + /* Run through the list of structs which have been passed by reference and + * check if they are being held longer than the duration of the callback + * execution. This is determined if the ref count is greater than 1. + * A single ref is held by the argument list and any more would mean the callback + * stored a ref somewhere else. In this case we make an internal copy of + * the boxed struct so Python can own the memory to it. + */ + list_item = pass_by_ref_structs; + while (list_item) { + PyObject *item = list_item->data; + if (Py_REFCNT (item) > 1) { + pygi_boxed_copy_in_place ((PyGIBoxed *)item); + } + list_item = g_slist_next (list_item); + } + out: + g_slist_free (pass_by_ref_structs); Py_DECREF(params); PyGILState_Release(state); } GClosure * -pygi_signal_closure_new_real (PyGObject *instance, - GType g_type, - const gchar *signal_name, - PyObject *callback, - PyObject *extra_args, - PyObject *swap_data) +pygi_signal_closure_new (PyGObject *instance, + GType g_type, + const gchar *signal_name, + PyObject *callback, + PyObject *extra_args, + PyObject *swap_data) { GClosure *closure = NULL; PyGISignalClosure *pygi_closure = NULL; diff --git a/gi/pygi-signal-closure.h b/gi/pygi-signal-closure.h index ffdd29c..9ba8d6d 100644 --- a/gi/pygi-signal-closure.h +++ b/gi/pygi-signal-closure.h @@ -24,7 +24,9 @@ #ifndef __PYGI_SIGNAL_CLOSURE_H__ #define __PYGI_SIGNAL_CLOSURE_H__ -#include "pygi.h" +#include <Python.h> +#include <girepository.h> +#include "pygobject-internal.h" G_BEGIN_DECLS @@ -35,12 +37,13 @@ typedef struct _PyGISignalClosure GISignalInfo *signal_info; } PyGISignalClosure; -GClosure * pygi_signal_closure_new_real (PyGObject *instance, - GType g_type, - const gchar *sig_name, - PyObject *callback, - PyObject *extra_args, - PyObject *swap_data); +GClosure * +pygi_signal_closure_new (PyGObject *instance, + GType g_type, + const gchar *sig_name, + PyObject *callback, + PyObject *extra_args, + PyObject *swap_data); G_END_DECLS diff --git a/gi/pygi-source.c b/gi/pygi-source.c index 66bbc3c..c85386d 100644 --- a/gi/pygi-source.c +++ b/gi/pygi-source.c @@ -23,12 +23,11 @@ * IN THE SOFTWARE. */ -#define NO_IMPORT -#include "pygobject.h" - -#include "pygi-private.h" -#include "pyglib.h" -#include "pyglib-private.h" +#include "pygi-info.h" +#include "pygi-boxed.h" +#include "pygi-type.h" +#include "pygi-basictype.h" +#include "pygboxed.h" #include "pygi-source.h" typedef struct @@ -38,7 +37,7 @@ typedef struct } PyGRealSource; static gboolean -pyg_source_prepare(GSource *source, gint *timeout) +source_prepare(GSource *source, gint *timeout) { PyGRealSource *pysource = (PyGRealSource *)source; PyObject *t; @@ -46,7 +45,7 @@ pyg_source_prepare(GSource *source, gint *timeout) gboolean got_err = TRUE; PyGILState_STATE state; - state = pyglib_gil_state_ensure(); + state = PyGILState_Ensure(); t = PyObject_CallMethod(pysource->obj, "prepare", NULL); @@ -66,13 +65,16 @@ pyg_source_prepare(GSource *source, gint *timeout) goto bail; } - ret = PyObject_IsTrue(PyTuple_GET_ITEM(t, 0)); - *timeout = PYGLIB_PyLong_AsLong(PyTuple_GET_ITEM(t, 1)); + if (!pygi_gboolean_from_py (PyTuple_GET_ITEM(t, 0), &ret)) { + ret = FALSE; + goto bail; + } - if (*timeout == -1 && PyErr_Occurred()) { - ret = FALSE; - goto bail; - } + if (!pygi_gint_from_py (PyTuple_GET_ITEM(t, 1), timeout)) + { + ret = FALSE; + goto bail; + } got_err = FALSE; @@ -82,20 +84,20 @@ bail: Py_XDECREF(t); - pyglib_gil_state_release(state); + PyGILState_Release(state); return ret; } static gboolean -pyg_source_check(GSource *source) +source_check(GSource *source) { PyGRealSource *pysource = (PyGRealSource *)source; PyObject *t; gboolean ret; PyGILState_STATE state; - state = pyglib_gil_state_ensure(); + state = PyGILState_Ensure(); t = PyObject_CallMethod(pysource->obj, "check", NULL); @@ -107,20 +109,20 @@ pyg_source_check(GSource *source) Py_DECREF(t); } - pyglib_gil_state_release(state); + PyGILState_Release(state); return ret; } static gboolean -pyg_source_dispatch(GSource *source, GSourceFunc callback, gpointer user_data) +source_dispatch(GSource *source, GSourceFunc callback, gpointer user_data) { PyGRealSource *pysource = (PyGRealSource *)source; PyObject *func, *args, *tuple, *t; gboolean ret; PyGILState_STATE state; - state = pyglib_gil_state_ensure(); + state = PyGILState_Ensure(); if (callback) { tuple = user_data; @@ -142,19 +144,19 @@ pyg_source_dispatch(GSource *source, GSourceFunc callback, gpointer user_data) Py_DECREF(t); } - pyglib_gil_state_release(state); + PyGILState_Release(state); return ret; } static void -pyg_source_finalize(GSource *source) +source_finalize(GSource *source) { PyGRealSource *pysource = (PyGRealSource *)source; PyObject *func, *t; PyGILState_STATE state; - state = pyglib_gil_state_ensure(); + state = PyGILState_Ensure(); func = PyObject_GetAttrString(pysource->obj, "finalize"); if (func) { @@ -166,24 +168,71 @@ pyg_source_finalize(GSource *source) } else { Py_DECREF(t); } + } else { + PyErr_Clear (); } - pyglib_gil_state_release(state); + PyGILState_Release(state); } static GSourceFuncs pyg_source_funcs = { - pyg_source_prepare, - pyg_source_check, - pyg_source_dispatch, - pyg_source_finalize + source_prepare, + source_check, + source_dispatch, + source_finalize }; +/** + * _pyglib_destroy_notify: + * @user_data: a PyObject pointer. + * + * A function that can be used as a GDestroyNotify callback that will + * call Py_DECREF on the data. + */ +static void +destroy_notify(gpointer user_data) +{ + PyObject *obj = (PyObject *)user_data; + PyGILState_STATE state; + + state = PyGILState_Ensure(); + Py_DECREF(obj); + PyGILState_Release(state); +} + +static gboolean +handler_marshal(gpointer user_data) +{ + PyObject *tuple, *ret; + gboolean res; + PyGILState_STATE state; + + g_return_val_if_fail(user_data != NULL, FALSE); + + state = PyGILState_Ensure(); + + tuple = (PyObject *)user_data; + ret = PyObject_CallObject(PyTuple_GetItem(tuple, 0), + PyTuple_GetItem(tuple, 1)); + if (!ret) { + PyErr_Print(); + res = FALSE; + } else { + res = PyObject_IsTrue(ret); + Py_DECREF(ret); + } + + PyGILState_Release(state); + + return res; +} + PyObject * -pyg_source_set_callback(PyGObject *self_module, PyObject *args) +pygi_source_set_callback (PyGObject *self_module, PyObject *args) { PyObject *self, *first, *callback, *cbargs = NULL, *data; - gint len; + Py_ssize_t len; len = PyTuple_Size (args); if (len < 2) { @@ -218,30 +267,42 @@ pyg_source_set_callback(PyGObject *self_module, PyObject *args) return NULL; g_source_set_callback(pyg_boxed_get (self, GSource), - _pyglib_handler_marshal, data, - _pyglib_destroy_notify); + handler_marshal, data, + destroy_notify); Py_INCREF(Py_None); return Py_None; } /** - * pyg_source_new: + * pygi_source_new: * * Wrap the un-bindable g_source_new() and provide wrapper callbacks in the * GSourceFuncs which call back to Python. + * + * Returns NULL on error and sets an exception. */ PyObject* -pyg_source_new (void) +pygi_source_new (PyObject *self, PyObject *args) { - PyGRealSource *source = NULL; - PyObject *py_type; + PyGRealSource *source; + PyObject *py_type, *boxed; - source = (PyGRealSource*) g_source_new (&pyg_source_funcs, sizeof (PyGRealSource)); + g_assert (args == NULL); + + py_type = pygi_type_import_by_name ("GLib", "Source"); + if (!py_type) + return NULL; - py_type = _pygi_type_import_by_name ("GLib", "Source"); + source = (PyGRealSource*) g_source_new (&pyg_source_funcs, sizeof (PyGRealSource)); /* g_source_new uses malloc, not slices */ - source->obj = _pygi_boxed_new ( (PyTypeObject *) py_type, source, FALSE, 0); + boxed = pygi_boxed_new ( (PyTypeObject *) py_type, source, TRUE, 0); + Py_DECREF (py_type); + if (!boxed) { + g_source_unref ((GSource *)source); + return NULL; + } + source->obj = boxed; return source->obj; } diff --git a/gi/pygi-source.h b/gi/pygi-source.h index a602767..5d60c63 100644 --- a/gi/pygi-source.h +++ b/gi/pygi-source.h @@ -24,8 +24,8 @@ #ifndef __PYGI_SOURCE_H__ #define __PYGI_SOURCE_H__ -PyObject *pyg_source_new (void); -PyObject *pyg_source_set_callback (PyGObject *self, PyObject *args); +PyObject *pygi_source_new (PyObject *self, PyObject *args); +PyObject *pygi_source_set_callback (PyGObject *self, PyObject *args); #endif /* __PYGI_SOURCE_H__ */ diff --git a/gi/pygi-struct-marshal.c b/gi/pygi-struct-marshal.c new file mode 100644 index 0000000..885f5d7 --- /dev/null +++ b/gi/pygi-struct-marshal.c @@ -0,0 +1,646 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- + * vim: tabstop=4 shiftwidth=4 expandtab + * + * Copyright (C) 2011 John (J5) Palmieri <johnp@redhat.com> + * Copyright (C) 2014 Simon Feltman <sfeltman@gnome.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#include <Python.h> +#include <glib.h> + +#include "pygi-struct-marshal.h" +#include "pygi-struct.h" +#include "pygi-foreign.h" +#include "pygi-value.h" +#include "pygi-type.h" +#include "pygi-boxed.h" +#include "pygi-info.h" +#include "pygpointer.h" +#include "pygboxed.h" +#include "pygi-type.h" + +/* + * _is_union_member - check to see if the py_arg is actually a member of the + * expected C union + */ +static gboolean +_is_union_member (GIInterfaceInfo *interface_info, PyObject *py_arg) { + gint i; + gint n_fields; + GIUnionInfo *union_info; + GIInfoType info_type; + gboolean is_member = FALSE; + + info_type = g_base_info_get_type (interface_info); + + if (info_type != GI_INFO_TYPE_UNION) + return FALSE; + + union_info = (GIUnionInfo *) interface_info; + n_fields = g_union_info_get_n_fields (union_info); + + for (i = 0; i < n_fields; i++) { + GIFieldInfo *field_info; + GITypeInfo *field_type_info; + + field_info = g_union_info_get_field (union_info, i); + field_type_info = g_field_info_get_type (field_info); + + /* we can only check if the members are interfaces */ + if (g_type_info_get_tag (field_type_info) == GI_TYPE_TAG_INTERFACE) { + GIInterfaceInfo *field_iface_info; + PyObject *py_type; + + field_iface_info = g_type_info_get_interface (field_type_info); + py_type = pygi_type_import_by_gi_info ((GIBaseInfo *) field_iface_info); + + if (py_type != NULL && PyObject_IsInstance (py_arg, py_type)) { + is_member = TRUE; + } + + Py_XDECREF (py_type); + g_base_info_unref ( ( GIBaseInfo *) field_iface_info); + } + + g_base_info_unref ( ( GIBaseInfo *) field_type_info); + g_base_info_unref ( ( GIBaseInfo *) field_info); + + if (is_member) + break; + } + + return is_member; +} + + +/* + * GValue from Python + */ + +/* pygi_arg_gvalue_from_py_marshal: + * py_arg: (in): + * arg: (out): + * transfer: + * copy_reference: TRUE if arg should use the pointer reference held by py_arg + * when it is already holding a GValue vs. copying the value. + */ +gboolean +pygi_arg_gvalue_from_py_marshal (PyObject *py_arg, + GIArgument *arg, + GITransfer transfer, + gboolean copy_reference) { + GValue *value; + GType object_type; + + object_type = pyg_type_from_object_strict ( (PyObject *) Py_TYPE (py_arg), FALSE); + if (object_type == G_TYPE_INVALID) { + PyErr_SetString (PyExc_RuntimeError, "unable to retrieve object's GType"); + return FALSE; + } + + /* if already a gvalue, use that, else marshal into gvalue */ + if (object_type == G_TYPE_VALUE) { + GValue *source_value = pyg_boxed_get (py_arg, GValue); + if (copy_reference) { + value = source_value; + } else { + value = g_slice_new0 (GValue); + g_value_init (value, G_VALUE_TYPE (source_value)); + g_value_copy (source_value, value); + } + } else { + value = g_slice_new0 (GValue); + g_value_init (value, object_type); + if (pyg_value_from_pyobject_with_error (value, py_arg) < 0) { + g_slice_free (GValue, value); + return FALSE; + } + } + + arg->v_pointer = value; + return TRUE; +} + +void +pygi_arg_gvalue_from_py_cleanup (PyGIInvokeState *state, + PyGIArgCache *arg_cache, + PyObject *py_arg, + gpointer data, + gboolean was_processed) +{ + /* Note py_arg can be NULL for hash table which is a bug. */ + if (was_processed && py_arg != NULL) { + GType py_object_type = + pyg_type_from_object_strict ( (PyObject *) Py_TYPE (py_arg), FALSE); + + /* When a GValue was not passed, it means the marshalers created a new + * one to pass in, clean this up. + */ + if (py_object_type != G_TYPE_VALUE) { + g_value_unset ((GValue *) data); + g_slice_free (GValue, data); + } + } +} + +/* pygi_arg_gclosure_from_py_marshal: + * py_arg: (in): + * arg: (out): + */ +static gboolean +pygi_arg_gclosure_from_py_marshal (PyObject *py_arg, + GIArgument *arg, + GITransfer transfer) +{ + GClosure *closure; + GType object_gtype = pyg_type_from_object_strict (py_arg, FALSE); + + if ( !(PyCallable_Check(py_arg) || + g_type_is_a (object_gtype, G_TYPE_CLOSURE))) { + PyErr_Format (PyExc_TypeError, "Must be callable, not %s", + Py_TYPE (py_arg)->tp_name); + return FALSE; + } + + if (g_type_is_a (object_gtype, G_TYPE_CLOSURE)) { + closure = (GClosure *)pyg_boxed_get (py_arg, void); + /* Make sure we own a ref which is held until cleanup. */ + if (closure != NULL) { + g_closure_ref (closure); + } + } else { + PyObject *functools; + PyObject *partial = NULL; + + functools = PyImport_ImportModule ("functools"); + if (functools) { + partial = PyObject_GetAttrString (functools, "partial"); + Py_DECREF (functools); + } + + if (partial && PyObject_IsInstance (py_arg, partial) > 0 && PyObject_HasAttrString (py_arg, "__gtk_template__")) { + PyObject *partial_func; + PyObject *partial_args; + PyObject *partial_keywords; + PyObject *swap_data; + + partial_func = PyObject_GetAttrString (py_arg, "func"); + partial_args = PyObject_GetAttrString (py_arg, "args"); + partial_keywords = PyObject_GetAttrString (py_arg, "keywords"); + swap_data = PyDict_GetItemString (partial_keywords, "swap_data"); + + closure = pyg_closure_new (partial_func, partial_args, swap_data); + + Py_DECREF (partial_func); + Py_DECREF (partial_args); + Py_DECREF (partial_keywords); + g_closure_ref (closure); + g_closure_sink (closure); + } else { + closure = pyg_closure_new (py_arg, NULL, NULL); + g_closure_ref (closure); + g_closure_sink (closure); + } + + if (partial) { + Py_DECREF (partial); + } + } + + if (closure == NULL) { + PyErr_SetString (PyExc_RuntimeError, "PyObject conversion to GClosure failed"); + return FALSE; + } + + /* Add an additional ref when transfering everything to the callee. */ + if (transfer == GI_TRANSFER_EVERYTHING) { + g_closure_ref (closure); + } + + arg->v_pointer = closure; + return TRUE; +} + +static void +arg_gclosure_from_py_cleanup (PyGIInvokeState *state, + PyGIArgCache *arg_cache, + PyObject *py_arg, + gpointer cleanup_data, + gboolean was_processed) +{ + if (cleanup_data != NULL) { + g_closure_unref (cleanup_data); + } +} + +/* pygi_arg_struct_from_py_marshal: + * + * Dispatcher to various sub marshalers + */ +gboolean +pygi_arg_struct_from_py_marshal (PyObject *py_arg, + GIArgument *arg, + const gchar *arg_name, + GIBaseInfo *interface_info, + GType g_type, + PyObject *py_type, + GITransfer transfer, + gboolean copy_reference, + gboolean is_foreign, + gboolean is_pointer) +{ + gboolean is_union = FALSE; + + if (py_arg == Py_None) { + arg->v_pointer = NULL; + return TRUE; + } + + /* FIXME: handle this large if statement in the cache + * and set the correct marshaller + */ + + if (g_type_is_a (g_type, G_TYPE_CLOSURE)) { + return pygi_arg_gclosure_from_py_marshal (py_arg, arg, transfer); + } else if (g_type_is_a (g_type, G_TYPE_VALUE)) { + return pygi_arg_gvalue_from_py_marshal(py_arg, + arg, + transfer, + copy_reference); + } else if (is_foreign) { + PyObject *success; + success = pygi_struct_foreign_convert_to_g_argument (py_arg, + interface_info, + transfer, + arg); + + return (success == Py_None); + } else if (!PyObject_IsInstance (py_arg, py_type)) { + /* first check to see if this is a member of the expected union */ + is_union = _is_union_member (interface_info, py_arg); + if (!is_union) { + goto type_error; + } + } + + if (g_type_is_a (g_type, G_TYPE_BOXED)) { + /* Additionally use pyg_type_from_object to pull the stashed __gtype__ + * attribute off of the input argument for type checking. This is needed + * to work around type discrepancies in cases with aliased (typedef) types. + * e.g. GtkAllocation, GdkRectangle. + * See: https://bugzilla.gnomethere are .org/show_bug.cgi?id=707140 + */ + if (is_union || pyg_boxed_check (py_arg, g_type) || + g_type_is_a (pyg_type_from_object (py_arg), g_type)) { + arg->v_pointer = pyg_boxed_get (py_arg, void); + if (transfer == GI_TRANSFER_EVERYTHING) { + arg->v_pointer = g_boxed_copy (g_type, arg->v_pointer); + } + } else { + goto type_error; + } + + } else if (g_type_is_a (g_type, G_TYPE_POINTER) || + g_type_is_a (g_type, G_TYPE_VARIANT) || + g_type == G_TYPE_NONE) { + g_warn_if_fail (g_type_is_a (g_type, G_TYPE_VARIANT) || !is_pointer || transfer == GI_TRANSFER_NOTHING); + + if (g_type_is_a (g_type, G_TYPE_VARIANT) && + pyg_type_from_object (py_arg) != G_TYPE_VARIANT) { + PyErr_SetString (PyExc_TypeError, "expected GLib.Variant"); + return FALSE; + } + arg->v_pointer = pyg_pointer_get (py_arg, void); + if (transfer == GI_TRANSFER_EVERYTHING) { + g_variant_ref ((GVariant *)arg->v_pointer); + } + + } else { + PyErr_Format (PyExc_NotImplementedError, + "structure type '%s' is not supported yet", + g_type_name(g_type)); + return FALSE; + } + return TRUE; + +type_error: + { + gchar *type_name = _pygi_g_base_info_get_fullname (interface_info); + PyObject *module = PyObject_GetAttrString(py_arg, "__module__"); + + PyErr_Format (PyExc_TypeError, "argument %s: Expected %s, but got %s%s%s", + arg_name ? arg_name : "self", + type_name, + module ? PyUnicode_AsUTF8(module) : "", + module ? "." : "", + Py_TYPE (py_arg)->tp_name); + if (module) + Py_DECREF (module); + g_free (type_name); + return FALSE; + } +} + +static gboolean +arg_struct_from_py_marshal_adapter (PyGIInvokeState *state, + PyGICallableCache *callable_cache, + PyGIArgCache *arg_cache, + PyObject *py_arg, + GIArgument *arg, + gpointer *cleanup_data) +{ + PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache; + + gboolean res = pygi_arg_struct_from_py_marshal (py_arg, + arg, + arg_cache->arg_name, + iface_cache->interface_info, + iface_cache->g_type, + iface_cache->py_type, + arg_cache->transfer, + TRUE, /*copy_reference*/ + iface_cache->is_foreign, + arg_cache->is_pointer); + + /* Assume struct marshaling is always a pointer and assign cleanup_data + * here rather than passing it further down the chain. + */ + *cleanup_data = arg->v_pointer; + return res; +} + +static void +arg_foreign_from_py_cleanup (PyGIInvokeState *state, + PyGIArgCache *arg_cache, + PyObject *py_arg, + gpointer data, + gboolean was_processed) +{ + if (state->failed && was_processed) { + pygi_struct_foreign_release ( + ( (PyGIInterfaceCache *)arg_cache)->interface_info, + data); + } +} + +static PyObject * +pygi_arg_struct_to_py_marshaller (GIArgument *arg, + GIInterfaceInfo *interface_info, + GType g_type, + PyObject *py_type, + GITransfer transfer, + gboolean is_allocated, + gboolean is_foreign) +{ + PyObject *py_obj = NULL; + + if (arg->v_pointer == NULL) { + Py_RETURN_NONE; + } + + if (g_type_is_a (g_type, G_TYPE_VALUE)) { + py_obj = pyg_value_as_pyobject (arg->v_pointer, is_allocated); + } else if (is_foreign) { + py_obj = pygi_struct_foreign_convert_from_g_argument (interface_info, + transfer, + arg->v_pointer); + } else if (g_type_is_a (g_type, G_TYPE_BOXED)) { + if (py_type) { + py_obj = pygi_boxed_new ((PyTypeObject *) py_type, + arg->v_pointer, + transfer == GI_TRANSFER_EVERYTHING || is_allocated, + is_allocated ? + g_struct_info_get_size(interface_info) : 0); + } + } else if (g_type_is_a (g_type, G_TYPE_POINTER)) { + if (py_type == NULL || + !PyType_IsSubtype ((PyTypeObject *) py_type, &PyGIStruct_Type)) { + g_warn_if_fail (transfer == GI_TRANSFER_NOTHING); + py_obj = pyg_pointer_new (g_type, arg->v_pointer); + } else { + py_obj = pygi_struct_new ( (PyTypeObject *) py_type, + arg->v_pointer, + transfer == GI_TRANSFER_EVERYTHING); + } + } else if (g_type_is_a (g_type, G_TYPE_VARIANT)) { + /* Note: sink the variant (add a ref) only if we are not transfered ownership. + * GLib.Variant overrides __del__ which will then call "g_variant_unref" for + * cleanup in either case. */ + if (py_type) { + if (transfer == GI_TRANSFER_NOTHING) { + g_variant_ref_sink (arg->v_pointer); + } + py_obj = pygi_struct_new ((PyTypeObject *) py_type, + arg->v_pointer, + FALSE); + } + } else if (g_type == G_TYPE_NONE) { + if (py_type) { + py_obj = pygi_struct_new ((PyTypeObject *) py_type, + arg->v_pointer, + transfer == GI_TRANSFER_EVERYTHING || is_allocated); + } + } else { + PyErr_Format (PyExc_NotImplementedError, + "structure type '%s' is not supported yet", + g_type_name (g_type)); + } + + return py_obj; +} + +PyObject * +pygi_arg_struct_to_py_marshal (GIArgument *arg, + GIInterfaceInfo *interface_info, + GType g_type, + PyObject *py_type, + GITransfer transfer, + gboolean is_allocated, + gboolean is_foreign) +{ + PyObject *ret = pygi_arg_struct_to_py_marshaller (arg, interface_info, g_type, py_type, transfer, is_allocated, is_foreign); + + if (ret && PyObject_IsInstance (ret, (PyObject *) &PyGIBoxed_Type) && transfer == GI_TRANSFER_NOTHING) + pygi_boxed_copy_in_place ((PyGIBoxed *) ret); + + return ret; +}; + +static PyObject * +arg_struct_to_py_marshal_adapter (PyGIInvokeState *state, + PyGICallableCache *callable_cache, + PyGIArgCache *arg_cache, + GIArgument *arg, + gpointer *cleanup_data) +{ + PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache; + PyObject *ret; + + ret = pygi_arg_struct_to_py_marshaller (arg, + iface_cache->interface_info, + iface_cache->g_type, + iface_cache->py_type, + arg_cache->transfer, + arg_cache->is_caller_allocates, + iface_cache->is_foreign); + + *cleanup_data = ret; + + return ret; +} + +static void +arg_foreign_to_py_cleanup (PyGIInvokeState *state, + PyGIArgCache *arg_cache, + gpointer cleanup_data, + gpointer data, + gboolean was_processed) +{ + if (!was_processed && arg_cache->transfer == GI_TRANSFER_EVERYTHING) { + pygi_struct_foreign_release ( + ( (PyGIInterfaceCache *)arg_cache)->interface_info, + data); + } +} + +static void +arg_boxed_to_py_cleanup (PyGIInvokeState *state, + PyGIArgCache *arg_cache, + gpointer cleanup_data, + gpointer data, + gboolean was_processed) +{ + if (arg_cache->transfer == GI_TRANSFER_NOTHING) + pygi_boxed_copy_in_place ((PyGIBoxed *) cleanup_data); +} + +static gboolean +arg_type_class_from_py_marshal (PyGIInvokeState *state, + PyGICallableCache *callable_cache, + PyGIArgCache *arg_cache, + PyObject *py_arg, + GIArgument *arg, + gpointer *cleanup_data) +{ + GType gtype = pyg_type_from_object (py_arg); + + if (G_TYPE_IS_CLASSED (gtype)) { + arg->v_pointer = g_type_class_ref (gtype); + *cleanup_data = arg->v_pointer; + return TRUE; + } else { + PyErr_Format (PyExc_TypeError, + "Unable to retrieve a GObject type class from \"%s\".", + Py_TYPE(py_arg)->tp_name); + return FALSE; + } +} + +static void +arg_type_class_from_py_cleanup (PyGIInvokeState *state, + PyGIArgCache *arg_cache, + PyObject *py_arg, + gpointer data, + gboolean was_processed) +{ + if (was_processed) { + g_type_class_unref (data); + } +} + +static void +arg_struct_from_py_setup (PyGIArgCache *arg_cache, + GIInterfaceInfo *iface_info, + GITransfer transfer) +{ + PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache; + + if (g_struct_info_is_gtype_struct ((GIStructInfo*)iface_info)) { + arg_cache->from_py_marshaller = arg_type_class_from_py_marshal; + /* Since we always add a ref in the marshalling, only unref the + * GTypeClass when we don't transfer ownership. */ + if (transfer == GI_TRANSFER_NOTHING) { + arg_cache->from_py_cleanup = arg_type_class_from_py_cleanup; + } + + } else { + arg_cache->from_py_marshaller = arg_struct_from_py_marshal_adapter; + + if (g_type_is_a (iface_cache->g_type, G_TYPE_CLOSURE)) { + arg_cache->from_py_cleanup = arg_gclosure_from_py_cleanup; + + } else if (iface_cache->g_type == G_TYPE_VALUE) { + arg_cache->from_py_cleanup = pygi_arg_gvalue_from_py_cleanup; + + } else if (iface_cache->is_foreign) { + arg_cache->from_py_cleanup = arg_foreign_from_py_cleanup; + } + } +} + +static void +arg_struct_to_py_setup (PyGIArgCache *arg_cache, + GIInterfaceInfo *iface_info, + GITransfer transfer) +{ + PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache; + + if (arg_cache->to_py_marshaller == NULL) { + arg_cache->to_py_marshaller = arg_struct_to_py_marshal_adapter; + } + + iface_cache->is_foreign = g_struct_info_is_foreign ( (GIStructInfo*)iface_info); + + if (iface_cache->is_foreign) + arg_cache->to_py_cleanup = arg_foreign_to_py_cleanup; + else if (!g_type_is_a (iface_cache->g_type, G_TYPE_VALUE) && + iface_cache->py_type && + g_type_is_a (iface_cache->g_type, G_TYPE_BOXED)) + arg_cache->to_py_cleanup = arg_boxed_to_py_cleanup; +} + +PyGIArgCache * +pygi_arg_struct_new_from_info (GITypeInfo *type_info, + GIArgInfo *arg_info, + GITransfer transfer, + PyGIDirection direction, + GIInterfaceInfo *iface_info) +{ + PyGIArgCache *cache = NULL; + PyGIInterfaceCache *iface_cache; + + cache = pygi_arg_interface_new_from_info (type_info, + arg_info, + transfer, + direction, + iface_info); + if (cache == NULL) + return NULL; + + iface_cache = (PyGIInterfaceCache *)cache; + iface_cache->is_foreign = (g_base_info_get_type ((GIBaseInfo *) iface_info) == GI_INFO_TYPE_STRUCT) && + (g_struct_info_is_foreign ((GIStructInfo*) iface_info)); + + if (direction & PYGI_DIRECTION_FROM_PYTHON) { + arg_struct_from_py_setup (cache, iface_info, transfer); + } + + if (direction & PYGI_DIRECTION_TO_PYTHON) { + arg_struct_to_py_setup (cache, iface_info, transfer); + } + + return cache; +} diff --git a/gi/pygi-struct-marshal.h b/gi/pygi-struct-marshal.h new file mode 100644 index 0000000..b2846df --- /dev/null +++ b/gi/pygi-struct-marshal.h @@ -0,0 +1,69 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- + * vim: tabstop=4 shiftwidth=4 expandtab + * + * Copyright (C) 2011 John (J5) Palmieri <johnp@redhat.com> + * Copyright (C) 2014 Simon Feltman <sfeltman@gnome.org> + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __PYGI_STRUCT_MARSHAL_H__ +#define __PYGI_STRUCT_MARSHAL_H__ + +#include <girepository.h> +#include "pygi-cache.h" + +G_BEGIN_DECLS + +PyGIArgCache *pygi_arg_struct_new_from_info (GITypeInfo *type_info, + GIArgInfo *arg_info, /* may be null */ + GITransfer transfer, + PyGIDirection direction, + GIInterfaceInfo *iface_info); + + +gboolean pygi_arg_gvalue_from_py_marshal (PyObject *py_arg, /*in*/ + GIArgument *arg, /*out*/ + GITransfer transfer, + gboolean is_allocated); + +gboolean pygi_arg_struct_from_py_marshal (PyObject *py_arg, + GIArgument *arg, + const gchar *arg_name, + GIBaseInfo *interface_info, + GType g_type, + PyObject *py_type, + GITransfer transfer, + gboolean is_allocated, + gboolean is_foreign, + gboolean is_pointer); + +PyObject *pygi_arg_struct_to_py_marshal (GIArgument *arg, + GIInterfaceInfo *interface_info, + GType g_type, + PyObject *py_type, + GITransfer transfer, + gboolean is_allocated, + gboolean is_foreign); + +/* Needed for hack in pygi-arg-garray.c */ +void pygi_arg_gvalue_from_py_cleanup (PyGIInvokeState *state, + PyGIArgCache *arg_cache, + PyObject *py_arg, + gpointer data, + gboolean was_processed); + +G_END_DECLS + +#endif /*__PYGI_STRUCT_MARSHAL_H__*/ diff --git a/gi/pygi-struct.c b/gi/pygi-struct.c index 29ea38e..f6e75e3 100644 --- a/gi/pygi-struct.c +++ b/gi/pygi-struct.c @@ -16,39 +16,80 @@ * 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 + * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ -#include "pygi-private.h" +#include "pygi-struct.h" +#include "pygi-foreign.h" +#include "pygi-info.h" +#include "pygi-type.h" +#include "pygi-type.h" +#include "pygpointer.h" +#include "pygi-util.h" -#include <pygobject.h> #include <girepository.h> -#include <pyglib-python-compat.h> + + +static GIBaseInfo * +struct_get_info (PyTypeObject *type) +{ + PyObject *py_info; + GIBaseInfo *info = NULL; + + py_info = PyObject_GetAttrString ((PyObject *)type, "__info__"); + if (py_info == NULL) { + return NULL; + } + if (!PyObject_TypeCheck (py_info, &PyGIStructInfo_Type) && + !PyObject_TypeCheck (py_info, &PyGIUnionInfo_Type)) { + PyErr_Format (PyExc_TypeError, "attribute '__info__' must be %s or %s, not %s", + PyGIStructInfo_Type.tp_name, + PyGIUnionInfo_Type.tp_name, + Py_TYPE(py_info)->tp_name); + goto out; + } + + info = ( (PyGIBaseInfo *) py_info)->info; + g_base_info_ref (info); + +out: + Py_DECREF (py_info); + + return info; +} static void -_struct_dealloc (PyGIStruct *self) +struct_dealloc (PyGIStruct *self) { - GIBaseInfo *info = _pygi_object_get_gi_info ( - (PyObject *) self, - &PyGIStructInfo_Type); + GIBaseInfo *info; + PyObject *error_type, *error_value, *error_traceback; + gboolean have_error = !!PyErr_Occurred (); + + if (have_error) + PyErr_Fetch (&error_type, &error_value, &error_traceback); + + info = struct_get_info (Py_TYPE (self)); if (info != NULL && g_struct_info_is_foreign ( (GIStructInfo *) info)) { - pygi_struct_foreign_release (info, ( (PyGPointer *) self)->pointer); + pygi_struct_foreign_release (info, pyg_pointer_get_ptr (self)); } else if (self->free_on_dealloc) { - g_free ( ( (PyGPointer *) self)->pointer); + g_free (pyg_pointer_get_ptr (self)); } - g_base_info_unref (info); + if (info != NULL) { + g_base_info_unref (info); + } + + if (have_error) + PyErr_Restore (error_type, error_value, error_traceback); - Py_TYPE( (PyGPointer *) self )->tp_free ( (PyObject *) self); + Py_TYPE (self)->tp_free ((PyObject *)self); } static PyObject * -_struct_new (PyTypeObject *type, - PyObject *args, - PyObject *kwargs) +struct_new (PyTypeObject *type, + PyObject *args, + PyObject *kwargs) { static char *kwlist[] = { NULL }; @@ -61,7 +102,7 @@ _struct_new (PyTypeObject *type, return NULL; } - info = _pygi_object_get_gi_info ( (PyObject *) type, &PyGIStructInfo_Type); + info = struct_get_info ( type ); if (info == NULL) { if (PyErr_ExceptionMatches (PyExc_AttributeError)) { PyErr_Format (PyExc_TypeError, "missing introspection information"); @@ -72,7 +113,7 @@ _struct_new (PyTypeObject *type, size = g_struct_info_get_size ( (GIStructInfo *) info); if (size == 0) { PyErr_Format (PyExc_TypeError, - "cannot allocate disguised struct %s.%s; consider adding a constructor to the library or to the overrides", + "struct cannot be created directly; try using a constructor, see: help(%s.%s)", g_base_info_get_namespace (info), g_base_info_get_name (info)); goto out; @@ -83,7 +124,7 @@ _struct_new (PyTypeObject *type, goto out; } - self = _pygi_struct_new (type, pointer, TRUE); + self = pygi_struct_new (type, pointer, TRUE); if (self == NULL) { g_free (pointer); } @@ -95,7 +136,7 @@ out: } static int -_struct_init (PyObject *self, +struct_init (PyObject *self, PyObject *args, PyObject *kwargs) { @@ -103,12 +144,44 @@ _struct_init (PyObject *self, return 0; } -PYGLIB_DEFINE_TYPE("gi.Struct", PyGIStruct_Type, PyGIStruct); +PYGI_DEFINE_TYPE("gi.Struct", PyGIStruct_Type, PyGIStruct); + PyObject * -_pygi_struct_new (PyTypeObject *type, - gpointer pointer, - gboolean free_on_dealloc) +pygi_struct_new_from_g_type (GType g_type, + gpointer pointer, + gboolean free_on_dealloc) +{ + PyGIStruct *self; + PyTypeObject *type; + + type = (PyTypeObject *)pygi_type_import_by_g_type (g_type); + + if (!type) + type = (PyTypeObject *)&PyGIStruct_Type; /* fallback */ + + if (!PyType_IsSubtype (type, &PyGIStruct_Type)) { + PyErr_SetString (PyExc_TypeError, "must be a subtype of gi.Struct"); + return NULL; + } + + self = (PyGIStruct *) type->tp_alloc (type, 0); + if (self == NULL) { + return NULL; + } + + pyg_pointer_set_ptr (self, pointer); + ( (PyGPointer *) self)->gtype = g_type; + self->free_on_dealloc = free_on_dealloc; + + return (PyObject *) self; +} + + +PyObject * +pygi_struct_new (PyTypeObject *type, + gpointer pointer, + gboolean free_on_dealloc) { PyGIStruct *self; GType g_type; @@ -125,25 +198,57 @@ _pygi_struct_new (PyTypeObject *type, g_type = pyg_type_from_object ( (PyObject *) type); + pyg_pointer_set_ptr (self, pointer); ( (PyGPointer *) self)->gtype = g_type; - ( (PyGPointer *) self)->pointer = pointer; self->free_on_dealloc = free_on_dealloc; return (PyObject *) self; } -void -_pygi_struct_register_types (PyObject *m) +static PyObject * +struct_repr(PyGIStruct *self) +{ + PyObject* repr; + GIBaseInfo *info; + PyGPointer *pointer = (PyGPointer *)self; + + info = struct_get_info (Py_TYPE (self)); + if (info == NULL) + return NULL; + + repr = PyUnicode_FromFormat ("<%s.%s object at %p (%s at %p)>", + g_base_info_get_namespace (info), + g_base_info_get_name (info), + self, g_type_name (pointer->gtype), + pointer->pointer); + + g_base_info_unref (info); + + return repr; +} + +/** + * Returns 0 on success, or -1 and sets an exception. + */ +int +pygi_struct_register_types (PyObject *m) { - Py_TYPE(&PyGIStruct_Type) = &PyType_Type; + Py_SET_TYPE(&PyGIStruct_Type, &PyType_Type); + g_assert (Py_TYPE (&PyGPointer_Type) != NULL); PyGIStruct_Type.tp_base = &PyGPointer_Type; - PyGIStruct_Type.tp_new = (newfunc) _struct_new; - PyGIStruct_Type.tp_init = (initproc) _struct_init; - PyGIStruct_Type.tp_dealloc = (destructor) _struct_dealloc; + PyGIStruct_Type.tp_new = (newfunc) struct_new; + PyGIStruct_Type.tp_init = (initproc) struct_init; + PyGIStruct_Type.tp_dealloc = (destructor) struct_dealloc; PyGIStruct_Type.tp_flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE); + PyGIStruct_Type.tp_repr = (reprfunc)struct_repr; + + if (PyType_Ready (&PyGIStruct_Type) < 0) + return -1; + Py_INCREF ((PyObject *) &PyGIStruct_Type); + if (PyModule_AddObject (m, "Struct", (PyObject *) &PyGIStruct_Type) < 0) { + Py_DECREF ((PyObject *) &PyGIStruct_Type); + return -1; + } - if (PyType_Ready (&PyGIStruct_Type)) - return; - if (PyModule_AddObject (m, "Struct", (PyObject *) &PyGIStruct_Type)) - return; + return 0; } diff --git a/gi/pygi-struct.h b/gi/pygi-struct.h index 963d05a..27230a9 100644 --- a/gi/pygi-struct.h +++ b/gi/pygi-struct.h @@ -14,26 +14,35 @@ * 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 + * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ #ifndef __PYGI_STRUCT_H__ #define __PYGI_STRUCT_H__ #include <Python.h> +#include <pygobject-internal.h> G_BEGIN_DECLS +typedef struct { + PyGPointer base; + gboolean free_on_dealloc; +} PyGIStruct; + extern PyTypeObject PyGIStruct_Type; PyObject * -_pygi_struct_new (PyTypeObject *type, - gpointer pointer, - gboolean free_on_dealloc); +pygi_struct_new (PyTypeObject *type, + gpointer pointer, + gboolean free_on_dealloc); + +PyObject * +pygi_struct_new_from_g_type (GType g_type, + gpointer pointer, + gboolean free_on_dealloc); -void _pygi_struct_register_types (PyObject *m); +int pygi_struct_register_types (PyObject *m); G_END_DECLS diff --git a/gi/pygi-type.c b/gi/pygi-type.c index dfaadb0..619c6a2 100644 --- a/gi/pygi-type.c +++ b/gi/pygi-type.c @@ -1,9 +1,6 @@ /* -*- Mode: C; c-basic-offset: 4 -*- - * vim: tabstop=4 shiftwidth=4 expandtab - * - * Copyright (C) 2009 Simon van der Linden <svdlinden@src.gnome.org> - * - * pygi-type.c: helpers to lookup Python wrappers from GType and GIBaseInfo. + * pygtk- Python bindings for the GTK toolkit. + * Copyright (C) 1998-2003 James Henstridge * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -16,19 +13,27 @@ * 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 + * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ -#include "pygi-private.h" +#include <config.h> -#include <pyglib-python-compat.h> +#include "pygobject-object.h" +#include "pygboxed.h" +#include "pygenum.h" +#include "pygflags.h" +#include "pygparamspec.h" +#include "pygi-util.h" +#include "pygpointer.h" +#include "pyginterface.h" +#include "pygi-type.h" +#include "pygi-value.h" +#include "pygi-basictype.h" PyObject * -_pygi_type_import_by_name (const char *namespace_, - const char *name) +pygi_type_import_by_name (const char *namespace_, + const char *name) { gchar *module_name; PyObject *py_module; @@ -52,7 +57,7 @@ _pygi_type_import_by_name (const char *namespace_, } PyObject * -pygi_type_import_by_g_type_real (GType g_type) +pygi_type_import_by_g_type (GType g_type) { GIRepository *repository; GIBaseInfo *info; @@ -65,21 +70,21 @@ pygi_type_import_by_g_type_real (GType g_type) return NULL; } - type = _pygi_type_import_by_gi_info (info); + type = pygi_type_import_by_gi_info (info); g_base_info_unref (info); return type; } PyObject * -_pygi_type_import_by_gi_info (GIBaseInfo *info) +pygi_type_import_by_gi_info (GIBaseInfo *info) { - return _pygi_type_import_by_name (g_base_info_get_namespace (info), - g_base_info_get_name (info)); + return pygi_type_import_by_name (g_base_info_get_namespace (info), + g_base_info_get_name (info)); } PyObject * -_pygi_type_get_from_g_type (GType g_type) +pygi_type_get_from_g_type (GType g_type) { PyObject *py_g_type; PyObject *py_type; @@ -91,7 +96,7 @@ _pygi_type_get_from_g_type (GType g_type) py_type = PyObject_GetAttrString (py_g_type, "pytype"); if (py_type == Py_None) { - py_type = pygi_type_import_by_g_type_real (g_type); + py_type = pygi_type_import_by_g_type (g_type); } Py_DECREF (py_g_type); @@ -99,61 +104,1279 @@ _pygi_type_get_from_g_type (GType g_type) return py_type; } -/* _pygi_get_py_type_hint +/* -------------- __gtype__ objects ---------------------------- */ + +typedef struct { + PyObject_HEAD + GType type; +} PyGTypeWrapper; + +PYGI_DEFINE_TYPE("gobject.GType", PyGTypeWrapper_Type, PyGTypeWrapper); + +static PyObject* +generic_gsize_richcompare(gsize a, gsize b, int op) +{ + PyObject *res; + + switch (op) { + + case Py_EQ: + res = (a == b) ? Py_True : Py_False; + Py_INCREF(res); + break; + + case Py_NE: + res = (a != b) ? Py_True : Py_False; + Py_INCREF(res); + break; + + + case Py_LT: + res = (a < b) ? Py_True : Py_False; + Py_INCREF(res); + break; + + case Py_LE: + res = (a <= b) ? Py_True : Py_False; + Py_INCREF(res); + break; + + case Py_GT: + res = (a > b) ? Py_True : Py_False; + Py_INCREF(res); + break; + + case Py_GE: + res = (a >= b) ? Py_True : Py_False; + Py_INCREF(res); + break; + + default: + res = Py_NotImplemented; + Py_INCREF(res); + break; + } + + return res; +} + +static PyObject* +pyg_type_wrapper_richcompare(PyObject *self, PyObject *other, int op) +{ + if (Py_TYPE(self) == Py_TYPE(other) && Py_TYPE(self) == &PyGTypeWrapper_Type) + return generic_gsize_richcompare(((PyGTypeWrapper*)self)->type, + ((PyGTypeWrapper*)other)->type, + op); + else { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } +} + +static long +pyg_type_wrapper_hash(PyGTypeWrapper *self) +{ + return (long)self->type; +} + +static PyObject * +pyg_type_wrapper_repr(PyGTypeWrapper *self) +{ + char buf[80]; + const gchar *name = g_type_name(self->type); + + g_snprintf(buf, sizeof(buf), "<GType %s (%lu)>", + name?name:"invalid", (unsigned long int) self->type); + return PyUnicode_FromString (buf); +} + +static void +pyg_type_wrapper_dealloc(PyGTypeWrapper *self) +{ + PyObject_DEL(self); +} + +static GQuark +_pyg_type_key(GType type) { + GQuark key; + + if (g_type_is_a(type, G_TYPE_INTERFACE)) { + key = pyginterface_type_key; + } else if (g_type_is_a(type, G_TYPE_ENUM)) { + key = pygenum_class_key; + } else if (g_type_is_a(type, G_TYPE_FLAGS)) { + key = pygflags_class_key; + } else if (g_type_is_a(type, G_TYPE_POINTER)) { + key = pygpointer_class_key; + } else if (g_type_is_a(type, G_TYPE_BOXED)) { + key = pygboxed_type_key; + } else { + key = pygobject_class_key; + } + + return key; +} + +static PyObject * +_wrap_g_type_wrapper__get_pytype(PyGTypeWrapper *self, void *closure) +{ + GQuark key; + PyObject *py_type; + + key = _pyg_type_key(self->type); + + py_type = g_type_get_qdata(self->type, key); + if (!py_type) + py_type = Py_None; + + Py_INCREF(py_type); + return py_type; +} + +static int +_wrap_g_type_wrapper__set_pytype(PyGTypeWrapper *self, PyObject* value, void *closure) +{ + GQuark key; + PyObject *py_type; + + key = _pyg_type_key(self->type); + + py_type = g_type_get_qdata(self->type, key); + Py_CLEAR(py_type); + if (value == Py_None) + g_type_set_qdata(self->type, key, NULL); + else if (PyType_Check(value)) { + Py_INCREF(value); + g_type_set_qdata(self->type, key, value); + } else { + PyErr_SetString(PyExc_TypeError, "Value must be None or a type object"); + return -1; + } + + return 0; +} + +static PyObject * +_wrap_g_type_wrapper__get_name(PyGTypeWrapper *self, void *closure) +{ + const char *name = g_type_name(self->type); + return PyUnicode_FromString (name ? name : "invalid"); +} + +static PyObject * +_wrap_g_type_wrapper__get_parent(PyGTypeWrapper *self, void *closure) +{ + return pyg_type_wrapper_new(g_type_parent(self->type)); +} + +static PyObject * +_wrap_g_type_wrapper__get_fundamental(PyGTypeWrapper *self, void *closure) +{ + return pyg_type_wrapper_new(g_type_fundamental(self->type)); +} + +static PyObject * +_wrap_g_type_wrapper__get_children(PyGTypeWrapper *self, void *closure) +{ + guint n_children, i; + GType *children; + PyObject *retval; + + children = g_type_children(self->type, &n_children); + + retval = PyList_New(n_children); + for (i = 0; i < n_children; i++) + PyList_SetItem(retval, i, pyg_type_wrapper_new(children[i])); + g_free(children); + + return retval; +} + +static PyObject * +_wrap_g_type_wrapper__get_interfaces(PyGTypeWrapper *self, void *closure) +{ + guint n_interfaces, i; + GType *interfaces; + PyObject *retval; + + interfaces = g_type_interfaces(self->type, &n_interfaces); + + retval = PyList_New(n_interfaces); + for (i = 0; i < n_interfaces; i++) + PyList_SetItem(retval, i, pyg_type_wrapper_new(interfaces[i])); + g_free(interfaces); + + return retval; +} + +static PyObject * +_wrap_g_type_wrapper__get_depth(PyGTypeWrapper *self, void *closure) +{ + return pygi_guint_to_py (g_type_depth (self->type)); +} + +static PyGetSetDef _PyGTypeWrapper_getsets[] = { + { "pytype", (getter)_wrap_g_type_wrapper__get_pytype, (setter)_wrap_g_type_wrapper__set_pytype }, + { "name", (getter)_wrap_g_type_wrapper__get_name, (setter)0 }, + { "fundamental", (getter)_wrap_g_type_wrapper__get_fundamental, (setter)0 }, + { "parent", (getter)_wrap_g_type_wrapper__get_parent, (setter)0 }, + { "children", (getter)_wrap_g_type_wrapper__get_children, (setter)0 }, + { "interfaces", (getter)_wrap_g_type_wrapper__get_interfaces, (setter)0 }, + { "depth", (getter)_wrap_g_type_wrapper__get_depth, (setter)0 }, + { NULL, (getter)0, (setter)0 } +}; + +static PyObject* +_wrap_g_type_is_interface(PyGTypeWrapper *self) +{ + return pygi_gboolean_to_py (G_TYPE_IS_INTERFACE (self->type)); +} + +static PyObject* +_wrap_g_type_is_classed(PyGTypeWrapper *self) +{ + return pygi_gboolean_to_py (G_TYPE_IS_CLASSED (self->type)); +} + +static PyObject* +_wrap_g_type_is_instantiatable(PyGTypeWrapper *self) +{ + return pygi_gboolean_to_py (G_TYPE_IS_INSTANTIATABLE(self->type)); +} + +static PyObject* +_wrap_g_type_is_derivable(PyGTypeWrapper *self) +{ + return pygi_gboolean_to_py (G_TYPE_IS_DERIVABLE (self->type)); +} + +static PyObject* +_wrap_g_type_is_deep_derivable(PyGTypeWrapper *self) +{ + return pygi_gboolean_to_py (G_TYPE_IS_DEEP_DERIVABLE (self->type)); +} + +static PyObject* +_wrap_g_type_is_abstract(PyGTypeWrapper *self) +{ + return pygi_gboolean_to_py (G_TYPE_IS_ABSTRACT (self->type)); +} + +static PyObject* +_wrap_g_type_is_value_abstract(PyGTypeWrapper *self) +{ + return pygi_gboolean_to_py (G_TYPE_IS_VALUE_ABSTRACT (self->type)); +} + +static PyObject* +_wrap_g_type_is_value_type(PyGTypeWrapper *self) +{ + return pygi_gboolean_to_py (G_TYPE_IS_VALUE_TYPE (self->type)); +} + +static PyObject* +_wrap_g_type_has_value_table(PyGTypeWrapper *self) +{ + return pygi_gboolean_to_py (G_TYPE_HAS_VALUE_TABLE (self->type)); +} + +static PyObject* +_wrap_g_type_from_name(PyGTypeWrapper *_, PyObject *args) +{ + char *type_name; + GType type; + + if (!PyArg_ParseTuple(args, "s:GType.from_name", &type_name)) + return NULL; + + type = g_type_from_name(type_name); + if (type == 0) { + PyErr_SetString(PyExc_RuntimeError, "unknown type name"); + return NULL; + } + + return pyg_type_wrapper_new(type); +} + +static PyObject* +_wrap_g_type_is_a(PyGTypeWrapper *self, PyObject *args) +{ + PyObject *gparent; + GType parent; + + if (!PyArg_ParseTuple(args, "O:GType.is_a", &gparent)) + return NULL; + else if ((parent = pyg_type_from_object(gparent)) == 0) + return NULL; + + return pygi_gboolean_to_py (g_type_is_a (self->type, parent)); +} + +static PyMethodDef _PyGTypeWrapper_methods[] = { + { "is_interface", (PyCFunction)_wrap_g_type_is_interface, METH_NOARGS }, + { "is_classed", (PyCFunction)_wrap_g_type_is_classed, METH_NOARGS }, + { "is_instantiatable", (PyCFunction)_wrap_g_type_is_instantiatable, METH_NOARGS }, + { "is_derivable", (PyCFunction)_wrap_g_type_is_derivable, METH_NOARGS }, + { "is_deep_derivable", (PyCFunction)_wrap_g_type_is_deep_derivable, METH_NOARGS }, + { "is_abstract", (PyCFunction)_wrap_g_type_is_abstract, METH_NOARGS }, + { "is_value_abstract", (PyCFunction)_wrap_g_type_is_value_abstract, METH_NOARGS }, + { "is_value_type", (PyCFunction)_wrap_g_type_is_value_type, METH_NOARGS }, + { "has_value_table", (PyCFunction)_wrap_g_type_has_value_table, METH_NOARGS }, + { "from_name", (PyCFunction)_wrap_g_type_from_name, METH_VARARGS | METH_STATIC }, + { "is_a", (PyCFunction)_wrap_g_type_is_a, METH_VARARGS }, + { NULL, 0, 0 } +}; + +static int +pyg_type_wrapper_init(PyGTypeWrapper *self, PyObject *args, PyObject *kwargs) +{ + static char *kwlist[] = { "object", NULL }; + PyObject *py_object; + GType type; + + if (!PyArg_ParseTupleAndKeywords(args, kwargs, + "O:GType.__init__", + kwlist, &py_object)) + return -1; + + if (!(type = pyg_type_from_object(py_object))) + return -1; + + self->type = type; + + return 0; +} + +/** + * pyg_type_wrapper_new: + * type: a GType + * + * Creates a Python wrapper for a GType. * - * This gives a hint to what python type might be used as - * a particular gi type. + * Returns: the Python wrapper. */ PyObject * -_pygi_get_py_type_hint(GITypeTag type_tag) -{ - PyObject *type = Py_None; - - switch (type_tag) { - case GI_TYPE_TAG_BOOLEAN: - type = (PyObject *) &PyBool_Type; - break; - - case GI_TYPE_TAG_INT8: - case GI_TYPE_TAG_UINT8: - case GI_TYPE_TAG_INT16: - case GI_TYPE_TAG_UINT16: - case GI_TYPE_TAG_INT32: - case GI_TYPE_TAG_UINT32: - case GI_TYPE_TAG_INT64: - case GI_TYPE_TAG_UINT64: - type = (PyObject *) &PYGLIB_PyLong_Type; - break; - - case GI_TYPE_TAG_FLOAT: - case GI_TYPE_TAG_DOUBLE: - type = (PyObject *) &PyFloat_Type; - break; - - case GI_TYPE_TAG_GLIST: - case GI_TYPE_TAG_GSLIST: - case GI_TYPE_TAG_ARRAY: - type = (PyObject *) &PyList_Type; - break; - - case GI_TYPE_TAG_GHASH: - type = (PyObject *) &PyDict_Type; - break; - - case GI_TYPE_TAG_UTF8: - case GI_TYPE_TAG_FILENAME: - case GI_TYPE_TAG_UNICHAR: - type = (PyObject *) &PYGLIB_PyUnicode_Type; - break; - - case GI_TYPE_TAG_INTERFACE: - case GI_TYPE_TAG_GTYPE: - case GI_TYPE_TAG_ERROR: - case GI_TYPE_TAG_VOID: - break; - } - - Py_INCREF(type); - return type; +pyg_type_wrapper_new(GType type) +{ + PyGTypeWrapper *self; + + g_assert (Py_TYPE (&PyGTypeWrapper_Type) != NULL); + self = (PyGTypeWrapper *)PyObject_NEW(PyGTypeWrapper, + &PyGTypeWrapper_Type); + if (self == NULL) + return NULL; + + self->type = type; + return (PyObject *)self; +} + +/** + * pyg_type_from_object_strict: + * obj: a Python object + * strict: if set to TRUE, raises an exception if it can't perform the + * conversion + * + * converts a python object to a GType. If strict is set, raises an + * exception if it can't perform the conversion, otherwise returns + * PY_TYPE_OBJECT. + * + * Returns: the corresponding GType, or 0 on error. + */ + +GType +pyg_type_from_object_strict(PyObject *obj, gboolean strict) +{ + PyObject *gtype; + GType type; + + /* NULL check */ + if (!obj) { + PyErr_SetString(PyExc_TypeError, "can't get type from NULL object"); + return 0; + } + + /* map some standard types to primitive GTypes ... */ + if (obj == Py_None) + return G_TYPE_NONE; + if (PyType_Check(obj)) { + PyTypeObject *tp = (PyTypeObject *)obj; + + if (tp == &PyLong_Type) + return G_TYPE_INT; + else if (tp == &PyBool_Type) + return G_TYPE_BOOLEAN; + else if (tp == &PyFloat_Type) + return G_TYPE_DOUBLE; + else if (tp == &PyUnicode_Type) + return G_TYPE_STRING; + else if (tp == &PyBaseObject_Type) + return PY_TYPE_OBJECT; + } + + if (Py_TYPE(obj) == &PyGTypeWrapper_Type) { + return ((PyGTypeWrapper *)obj)->type; + } + + /* handle strings */ + if (PyUnicode_Check (obj)) { + gchar *name = PyUnicode_AsUTF8(obj); + + type = g_type_from_name(name); + if (type != 0) { + return type; + } + } + + /* finally, look for a __gtype__ attribute on the object */ + gtype = PyObject_GetAttrString(obj, "__gtype__"); + + if (gtype) { + if (Py_TYPE(gtype) == &PyGTypeWrapper_Type) { + type = ((PyGTypeWrapper *)gtype)->type; + Py_DECREF(gtype); + return type; + } + Py_DECREF(gtype); + } + + PyErr_Clear(); + + /* Some API like those that take GValues can hold a python object as + * a pointer. This is potentially dangerous becuase everything is + * passed in as a PyObject so we can't actually type check it. Only + * fallback to PY_TYPE_OBJECT if strict checking is disabled + */ + if (!strict) + return PY_TYPE_OBJECT; + + PyErr_SetString(PyExc_TypeError, "could not get typecode from object"); + return 0; } +/** + * pyg_type_from_object: + * obj: a Python object + * + * converts a python object to a GType. Raises an exception if it + * can't perform the conversion. + * + * Returns: the corresponding GType, or 0 on error. + */ +GType +pyg_type_from_object(PyObject *obj) +{ + /* Legacy call always defaults to strict type checking */ + return pyg_type_from_object_strict(obj, TRUE); +} + +/** + * pyg_enum_get_value: + * @enum_type: the GType of the flag. + * @obj: a Python object representing the flag value + * @val: a pointer to the location to store the integer representation of the flag. + * + * Converts a Python object to the integer equivalent. The conversion + * will depend on the type of the Python object. If the object is an + * integer, it is passed through directly. If it is a string, it will + * be treated as a full or short enum name as defined in the GType. + * + * Returns: 0 on success or -1 on failure + */ +gint +pyg_enum_get_value(GType enum_type, PyObject *obj, gint *val) +{ + GEnumClass *eclass = NULL; + gint res = -1; + + g_return_val_if_fail(val != NULL, -1); + if (!obj) { + *val = 0; + res = 0; + } else if (PyLong_Check (obj)) { + if (!pygi_gint_from_py (obj, val)) + res = -1; + else + res = 0; + + if (PyObject_TypeCheck(obj, &PyGEnum_Type) && ((PyGEnum *) obj)->gtype != enum_type) { + g_warning("expected enumeration type %s, but got %s instead", + g_type_name(enum_type), + g_type_name(((PyGEnum *) obj)->gtype)); + } + } else if (PyUnicode_Check (obj)) { + GEnumValue *info; + char *str = PyUnicode_AsUTF8 (obj); + + if (enum_type != G_TYPE_NONE) + eclass = G_ENUM_CLASS(g_type_class_ref(enum_type)); + else { + PyErr_SetString(PyExc_TypeError, "could not convert string to enum because there is no GType associated to look up the value"); + res = -1; + } + info = g_enum_get_value_by_name(eclass, str); + g_type_class_unref(eclass); + + if (!info) + info = g_enum_get_value_by_nick(eclass, str); + if (info) { + *val = info->value; + res = 0; + } else { + PyErr_SetString(PyExc_TypeError, "could not convert string"); + res = -1; + } + } else { + PyErr_SetString(PyExc_TypeError,"enum values must be strings or ints"); + res = -1; + } + return res; +} + +/** + * pyg_flags_get_value: + * @flag_type: the GType of the flag. + * @obj: a Python object representing the flag value + * @val: a pointer to the location to store the integer representation of the flag. + * + * Converts a Python object to the integer equivalent. The conversion + * will depend on the type of the Python object. If the object is an + * integer, it is passed through directly. If it is a string, it will + * be treated as a full or short flag name as defined in the GType. + * If it is a tuple, then the items are treated as strings and ORed + * together. + * + * Returns: 0 on success or -1 on failure + */ +gint +pyg_flags_get_value(GType flag_type, PyObject *obj, guint *val) +{ + GFlagsClass *fclass = NULL; + gint res = -1; + + g_return_val_if_fail(val != NULL, -1); + if (!obj) { + *val = 0; + res = 0; + } else if (PyLong_Check (obj)) { + if (pygi_guint_from_py (obj, val)) + res = 0; + } else if (PyUnicode_Check (obj)) { + GFlagsValue *info; + char *str = PyUnicode_AsUTF8 (obj); + + if (flag_type != G_TYPE_NONE) + fclass = G_FLAGS_CLASS(g_type_class_ref(flag_type)); + else { + PyErr_SetString(PyExc_TypeError, "could not convert string to flag because there is no GType associated to look up the value"); + res = -1; + } + info = g_flags_get_value_by_name(fclass, str); + g_type_class_unref(fclass); + + if (!info) + info = g_flags_get_value_by_nick(fclass, str); + if (info) { + *val = info->value; + res = 0; + } else { + PyErr_SetString(PyExc_TypeError, "could not convert string"); + res = -1; + } + } else if (PyTuple_Check(obj)) { + Py_ssize_t i, len; + + len = PyTuple_Size(obj); + *val = 0; + res = 0; + + if (flag_type != G_TYPE_NONE) + fclass = G_FLAGS_CLASS(g_type_class_ref(flag_type)); + else { + PyErr_SetString(PyExc_TypeError, "could not convert string to flag because there is no GType associated to look up the value"); + res = -1; + } + + for (i = 0; i < len; i++) { + PyObject *item = PyTuple_GetItem(obj, i); + char *str = PyUnicode_AsUTF8 (item); + GFlagsValue *info = g_flags_get_value_by_name(fclass, str); + + if (!info) + info = g_flags_get_value_by_nick(fclass, str); + if (info) { + *val |= info->value; + } else { + PyErr_SetString(PyExc_TypeError, "could not convert string"); + res = -1; + break; + } + } + g_type_class_unref(fclass); + } else { + PyErr_SetString(PyExc_TypeError, + "flag values must be strings, ints, longs, or tuples"); + res = -1; + } + return res; +} + +static GQuark pyg_type_marshal_key = 0; +static GQuark pyg_type_marshal_helper_key = 0; + +typedef enum _marshal_helper_data_e marshal_helper_data_e; +enum _marshal_helper_data_e { + MARSHAL_HELPER_NONE = 0, + MARSHAL_HELPER_RETURN_NULL, + MARSHAL_HELPER_IMPORT_DONE, +}; + +PyGTypeMarshal * +pyg_type_lookup(GType type) +{ + GType ptype = type; + PyGTypeMarshal *tm = NULL; + marshal_helper_data_e marshal_helper; + + if (type == G_TYPE_INVALID) + return NULL; + + marshal_helper = GPOINTER_TO_INT ( + g_type_get_qdata(type, pyg_type_marshal_helper_key)); + + /* If we called this function before with @type and nothing was found, + * return NULL early to not spend time in the loop below */ + if (marshal_helper == MARSHAL_HELPER_RETURN_NULL) + return NULL; + + /* Otherwise do recursive type lookup */ + do { + if (marshal_helper == MARSHAL_HELPER_IMPORT_DONE) + pygi_type_import_by_g_type (ptype); + + if ((tm = g_type_get_qdata(ptype, pyg_type_marshal_key)) != NULL) + break; + ptype = g_type_parent(ptype); + } while (ptype); + + if (marshal_helper == MARSHAL_HELPER_NONE) { + marshal_helper = (tm == NULL) ? + MARSHAL_HELPER_RETURN_NULL: + MARSHAL_HELPER_IMPORT_DONE; + g_type_set_qdata(type, pyg_type_marshal_helper_key, + GINT_TO_POINTER(marshal_helper)); + } + return tm; +} + +/** + * pyg_register_gtype_custom: + * @gtype: the GType for the new type + * @from_func: a function to convert GValues to Python objects + * @to_func: a function to convert Python objects to GValues + * + * In order to handle specific conversion of gboxed types or new + * fundamental types, you may use this function to register conversion + * handlers. + */ + +void +pyg_register_gtype_custom(GType gtype, + fromvaluefunc from_func, + tovaluefunc to_func) +{ + PyGTypeMarshal *tm; + + if (!pyg_type_marshal_key) { + pyg_type_marshal_key = g_quark_from_static_string("PyGType::marshal"); + pyg_type_marshal_helper_key = g_quark_from_static_string("PyGType::marshal-helper"); + } + + tm = g_new(PyGTypeMarshal, 1); + tm->fromvalue = from_func; + tm->tovalue = to_func; + g_type_set_qdata(gtype, pyg_type_marshal_key, tm); +} + +/* -------------- PyGClosure ----------------- */ + +static void +pyg_closure_invalidate(gpointer data, GClosure *closure) +{ + PyGClosure *pc = (PyGClosure *)closure; + PyGILState_STATE state; + + state = PyGILState_Ensure(); + Py_XDECREF(pc->callback); + Py_XDECREF(pc->extra_args); + Py_XDECREF(pc->swap_data); + PyGILState_Release(state); + + pc->callback = NULL; + pc->extra_args = NULL; + pc->swap_data = NULL; +} + +static void +pyg_closure_marshal(GClosure *closure, + GValue *return_value, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint, + gpointer marshal_data) +{ + PyGILState_STATE state; + PyGClosure *pc = (PyGClosure *)closure; + PyObject *params, *ret; + guint i; + + state = PyGILState_Ensure(); + + /* construct Python tuple for the parameter values */ + params = PyTuple_New(n_param_values); + for (i = 0; i < n_param_values; i++) { + /* swap in a different initial data for connect_object() */ + if (i == 0 && G_CCLOSURE_SWAP_DATA(closure)) { + g_return_if_fail(pc->swap_data != NULL); + Py_INCREF(pc->swap_data); + PyTuple_SetItem(params, 0, pc->swap_data); + } else { + PyObject *item = pyg_value_as_pyobject(¶m_values[i], FALSE); + + /* error condition */ + if (!item) { + if (!PyErr_Occurred ()) + PyErr_SetString (PyExc_TypeError, + "can't convert parameter to desired type"); + + if (pc->exception_handler) + pc->exception_handler (return_value, n_param_values, param_values); + else + PyErr_Print(); + + goto out; + } + PyTuple_SetItem(params, i, item); + } + } + /* 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 == NULL) { + if (pc->exception_handler) + pc->exception_handler(return_value, n_param_values, param_values); + else + PyErr_Print(); + goto out; + } + + 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); + else + PyErr_Print(); + } + Py_DECREF(ret); + + out: + Py_DECREF(params); + PyGILState_Release(state); +} + +/** + * pyg_closure_new: + * callback: a Python callable object + * extra_args: a tuple of extra arguments, or None/NULL. + * swap_data: an alternative python object to pass first. + * + * Creates a GClosure wrapping a Python callable and optionally a set + * of additional function arguments. This is needed to attach python + * handlers to signals, for instance. + * + * Returns: the new closure. + */ +GClosure * +pyg_closure_new(PyObject *callback, PyObject *extra_args, PyObject *swap_data) +{ + 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, pyg_closure_invalidate); + g_closure_set_marshal(closure, pyg_closure_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; + } + if (swap_data) { + Py_INCREF(swap_data); + ((PyGClosure *)closure)->swap_data = swap_data; + closure->derivative_flag = TRUE; + } + return closure; +} + +/** + * pyg_closure_set_exception_handler: + * @closure: a closure created with pyg_closure_new() + * @handler: the handler to call when an exception occurs or NULL for none + * + * Sets the handler to call when an exception occurs during closure invocation. + * The handler is responsible for providing a proper return value to the + * closure invocation. If @handler is %NULL, the default handler will be used. + * The default handler prints the exception to stderr and doesn't touch the + * closure's return value. + */ +void +pyg_closure_set_exception_handler(GClosure *closure, + PyClosureExceptionHandler handler) +{ + PyGClosure *pygclosure; + + g_return_if_fail(closure != NULL); + + pygclosure = (PyGClosure *)closure; + pygclosure->exception_handler = handler; +} +/* -------------- PySignalClassClosure ----------------- */ +/* a closure used for the `class closure' of a signal. As this gets + * all the info from the first argument to the closure and the + * invocation hint, we can have a single closure that handles all + * class closure cases. We call a method by the name of the signal + * with "do_" prepended. + * + * We also remove the first argument from the * param list, as it is + * the instance object, which is passed * implicitly to the method + * object. */ + +static void +pyg_signal_class_closure_marshal(GClosure *closure, + GValue *return_value, + guint n_param_values, + const GValue *param_values, + gpointer invocation_hint, + gpointer marshal_data) +{ + PyGILState_STATE state; + GObject *object; + PyObject *object_wrapper; + GSignalInvocationHint *hint = (GSignalInvocationHint *)invocation_hint; + gchar *method_name, *tmp; + PyObject *method; + PyObject *params, *ret; + Py_ssize_t py_len; + guint i, len; + + state = PyGILState_Ensure(); + + g_return_if_fail(invocation_hint != NULL); + /* get the object passed as the first argument to the closure */ + object = g_value_get_object(¶m_values[0]); + g_return_if_fail(object != NULL && G_IS_OBJECT(object)); + + /* get the wrapper for this object */ + object_wrapper = pygobject_new(object); + g_return_if_fail(object_wrapper != NULL); + + /* construct method name for this class closure */ + method_name = g_strconcat("do_", g_signal_name(hint->signal_id), NULL); + + /* convert dashes to underscores. For some reason, g_signal_name + * seems to convert all the underscores in the signal name to + dashes??? */ + for (tmp = method_name; *tmp != '\0'; tmp++) + if (*tmp == '-') *tmp = '_'; + + method = PyObject_GetAttrString(object_wrapper, method_name); + g_free(method_name); + + if (!method) { + PyErr_Clear(); + Py_DECREF(object_wrapper); + PyGILState_Release(state); + return; + } + Py_DECREF(object_wrapper); + + /* construct Python tuple for the parameter values; don't copy boxed values + initially because we'll check after the call to see if a copy is needed. */ + params = PyTuple_New(n_param_values - 1); + for (i = 1; i < n_param_values; i++) { + PyObject *item = pyg_value_as_pyobject(¶m_values[i], FALSE); + + /* error condition */ + if (!item) { + Py_DECREF(params); + PyGILState_Release(state); + return; + } + PyTuple_SetItem(params, i - 1, item); + } + + ret = PyObject_CallObject(method, params); + + /* Copy boxed values if others ref them, this needs to be done regardless of + exception status. */ + py_len = PyTuple_Size(params); + len = (guint)py_len; + for (i = 0; i < len; i++) { + PyObject *item = PyTuple_GetItem(params, i); + if (item != NULL && PyObject_TypeCheck(item, &PyGBoxed_Type) + && Py_REFCNT (item) != 1) { + PyGBoxed* boxed_item = (PyGBoxed*)item; + if (!boxed_item->free_on_dealloc) { + gpointer boxed_ptr = pyg_boxed_get_ptr (boxed_item); + pyg_boxed_set_ptr (boxed_item, g_boxed_copy (boxed_item->gtype, boxed_ptr)); + boxed_item->free_on_dealloc = TRUE; + } + } + } + + if (ret == NULL) { + PyErr_Print(); + Py_DECREF(method); + Py_DECREF(params); + PyGILState_Release(state); + return; + } + Py_DECREF(method); + Py_DECREF(params); + if (G_IS_VALUE(return_value)) + pyg_value_from_pyobject(return_value, ret); + Py_DECREF(ret); + PyGILState_Release(state); +} + +/** + * pyg_signal_class_closure_get: + * + * Returns the GClosure used for the class closure of signals. When + * called, it will invoke the method do_signalname (for the signal + * "signalname"). + * + * Returns: the closure. + */ +GClosure * +pyg_signal_class_closure_get(void) +{ + static GClosure *closure; + + if (closure == NULL) { + closure = g_closure_new_simple(sizeof(GClosure), NULL); + g_closure_set_marshal(closure, pyg_signal_class_closure_marshal); + + g_closure_ref(closure); + g_closure_sink(closure); + } + return closure; +} + +/* ----- __doc__ descriptor for GObject and GInterface ----- */ + +static void +object_doc_dealloc(PyObject *self) +{ + PyObject_FREE(self); +} + +/* append information about signals of a particular gtype */ +static void +add_signal_docs(GType gtype, GString *string) +{ + GTypeClass *class = NULL; + guint *signal_ids, n_ids = 0, i; + + if (G_TYPE_IS_CLASSED(gtype)) + class = g_type_class_ref(gtype); + signal_ids = g_signal_list_ids(gtype, &n_ids); + + if (n_ids > 0) { + g_string_append_printf(string, "Signals from %s:\n", + g_type_name(gtype)); + + for (i = 0; i < n_ids; i++) { + GSignalQuery query; + guint j; + + g_signal_query(signal_ids[i], &query); + + g_string_append(string, " "); + g_string_append(string, query.signal_name); + g_string_append(string, " ("); + for (j = 0; j < query.n_params; j++) { + g_string_append(string, g_type_name(query.param_types[j])); + if (j != query.n_params - 1) + g_string_append(string, ", "); + } + g_string_append(string, ")"); + if (query.return_type && query.return_type != G_TYPE_NONE) { + g_string_append(string, " -> "); + g_string_append(string, g_type_name(query.return_type)); + } + g_string_append(string, "\n"); + } + g_free(signal_ids); + g_string_append(string, "\n"); + } + if (class) + g_type_class_unref(class); +} + +static void +add_property_docs(GType gtype, GString *string) +{ + GObjectClass *class; + GParamSpec **props; + guint n_props = 0, i; + gboolean has_prop = FALSE; + const gchar *blurb=NULL; + + class = g_type_class_ref(gtype); + props = g_object_class_list_properties(class, &n_props); + + for (i = 0; i < n_props; i++) { + if (props[i]->owner_type != gtype) + continue; /* these are from a parent type */ + + /* print out the heading first */ + if (!has_prop) { + g_string_append_printf(string, "Properties from %s:\n", + g_type_name(gtype)); + has_prop = TRUE; + } + g_string_append_printf(string, " %s -> %s: %s\n", + g_param_spec_get_name(props[i]), + g_type_name(props[i]->value_type), + g_param_spec_get_nick(props[i])); + + /* g_string_append_printf crashes on win32 if the third + argument is NULL. */ + blurb=g_param_spec_get_blurb(props[i]); + if (blurb) + g_string_append_printf(string, " %s\n",blurb); + } + g_free(props); + if (has_prop) + g_string_append(string, "\n"); + g_type_class_unref(class); +} + +static PyObject * +object_doc_descr_get(PyObject *self, PyObject *obj, PyObject *type) +{ + GType gtype = 0; + GString *string; + PyObject *pystring; + + if (obj && pygobject_check(obj, &PyGObject_Type)) { + gtype = G_OBJECT_TYPE(pygobject_get(obj)); + if (!gtype) + PyErr_SetString(PyExc_RuntimeError, "could not get object type"); + } else { + gtype = pyg_type_from_object(type); + } + if (!gtype) + return NULL; + + string = g_string_new_len(NULL, 512); + + if (g_type_is_a(gtype, G_TYPE_INTERFACE)) + g_string_append_printf(string, "Interface %s\n\n", g_type_name(gtype)); + else if (g_type_is_a(gtype, G_TYPE_OBJECT)) + g_string_append_printf(string, "Object %s\n\n", g_type_name(gtype)); + else + g_string_append_printf(string, "%s\n\n", g_type_name(gtype)); + + if (((PyTypeObject *) type)->tp_doc) + g_string_append_printf(string, "%s\n\n", ((PyTypeObject *) type)->tp_doc); + + if (g_type_is_a(gtype, G_TYPE_OBJECT)) { + GType parent = G_TYPE_OBJECT; + GArray *parents = g_array_new(FALSE, FALSE, sizeof(GType)); + int iparent; + + while (parent) { + g_array_append_val(parents, parent); + parent = g_type_next_base(gtype, parent); + } + + for (iparent = parents->len - 1; iparent >= 0; --iparent) { + GType *interfaces; + guint n_interfaces, i; + + parent = g_array_index(parents, GType, iparent); + add_signal_docs(parent, string); + add_property_docs(parent, string); + + /* add docs for implemented interfaces */ + interfaces = g_type_interfaces(parent, &n_interfaces); + for (i = 0; i < n_interfaces; i++) + add_signal_docs(interfaces[i], string); + g_free(interfaces); + } + g_array_free(parents, TRUE); + } + + pystring = PyUnicode_FromStringAndSize (string->str, string->len); + g_string_free(string, TRUE); + return pystring; +} + +PYGI_DEFINE_TYPE("gobject.GObject.__doc__", PyGObjectDoc_Type, PyObject); + +/** + * pyg_object_descr_doc_get: + * + * Returns an object intended to be the __doc__ attribute of GObject + * wrappers. When read in the context of the object it will return + * some documentation about the signals and properties of the object. + * + * Returns: the descriptor. + */ +PyObject * +pyg_object_descr_doc_get(void) +{ + static PyObject *doc_descr = NULL; + + if (!doc_descr) { + Py_SET_TYPE(&PyGObjectDoc_Type, &PyType_Type); + if (PyType_Ready(&PyGObjectDoc_Type)) + return NULL; + + doc_descr = PyObject_NEW(PyObject, &PyGObjectDoc_Type); + if (doc_descr == NULL) + return NULL; + } + return doc_descr; +} + + +/** + * pyg_pyobj_to_unichar_conv: + * + * Converts PyObject value to a unichar and write result to memory + * pointed to by ptr. Follows the calling convention of a ParseArgs + * converter (O& format specifier) so it may be used to convert function + * arguments. + * + * Returns: 1 if the conversion succeeds and 0 otherwise. If the conversion + * did not succeesd, a Python exception is raised + */ +int pyg_pyobj_to_unichar_conv(PyObject* py_obj, void* ptr) +{ + if (!pygi_gunichar_from_py (py_obj, ptr)) + return 0; + return 1; +} + +gboolean +pyg_gtype_is_custom(GType gtype) +{ + return g_type_get_qdata (gtype, pygobject_custom_key) != NULL; +} + +static PyObject * +strv_from_gvalue(const GValue *value) +{ + gchar **argv; + PyObject *py_argv; + gsize i; + + argv = (gchar **) g_value_get_boxed (value); + py_argv = PyList_New (0); + + for (i = 0; argv && argv[i]; i++) { + int res; + PyObject *item = pygi_utf8_to_py (argv[i]); + if (item == NULL) { + Py_DECREF (py_argv); + return NULL; + } + res = PyList_Append (py_argv, item); + Py_DECREF (item); + if (res == -1) { + Py_DECREF (py_argv); + return NULL; + } + } + + return py_argv; +} + +static int +strv_to_gvalue(GValue *value, PyObject *obj) +{ + Py_ssize_t argc, i; + gchar **argv; + + if (!(PyTuple_Check (obj) || PyList_Check (obj))) + return -1; + + argc = PySequence_Length (obj); + argv = g_new (gchar *, argc + 1); + for (i = 0; i < argc; ++i) { + PyObject* item = PySequence_Fast_GET_ITEM (obj, i); + if (!pygi_utf8_from_py (item, &(argv[i]))) + goto error; + } + + argv[i] = NULL; + g_value_take_boxed (value, argv); + return 0; + +error: + for (i = i - 1; i >= 0; i--) { + g_free (argv[i]); + } + g_free (argv); + return -1; +} + +/** + * Returns 0 on success, or -1 and sets an exception. + */ +int +pygi_type_register_types(PyObject *d) +{ + PyGTypeWrapper_Type.tp_dealloc = (destructor)pyg_type_wrapper_dealloc; + PyGTypeWrapper_Type.tp_richcompare = pyg_type_wrapper_richcompare; + PyGTypeWrapper_Type.tp_repr = (reprfunc)pyg_type_wrapper_repr; + PyGTypeWrapper_Type.tp_hash = (hashfunc)pyg_type_wrapper_hash; + PyGTypeWrapper_Type.tp_flags = Py_TPFLAGS_DEFAULT; + PyGTypeWrapper_Type.tp_methods = _PyGTypeWrapper_methods; + PyGTypeWrapper_Type.tp_getset = _PyGTypeWrapper_getsets; + PyGTypeWrapper_Type.tp_init = (initproc)pyg_type_wrapper_init; + PyGTypeWrapper_Type.tp_alloc = PyType_GenericAlloc; + PyGTypeWrapper_Type.tp_new = PyType_GenericNew; + if (PyType_Ready(&PyGTypeWrapper_Type)) + return -1; + + PyDict_SetItemString(d, "GType", (PyObject *)&PyGTypeWrapper_Type); + + /* This type lazily registered in pyg_object_descr_doc_get */ + PyGObjectDoc_Type.tp_dealloc = (destructor)object_doc_dealloc; + PyGObjectDoc_Type.tp_flags = Py_TPFLAGS_DEFAULT; + PyGObjectDoc_Type.tp_descr_get = (descrgetfunc)object_doc_descr_get; + + pyg_register_gtype_custom (G_TYPE_STRV, + strv_from_gvalue, + strv_to_gvalue); + + return 0; +} diff --git a/gi/pygi-type.h b/gi/pygi-type.h index 01b5994..c7e1a45 100644 --- a/gi/pygi-type.h +++ b/gi/pygi-type.h @@ -1,7 +1,8 @@ /* -*- Mode: C; c-basic-offset: 4 -*- - * vim: tabstop=4 shiftwidth=4 expandtab - * - * Copyright (C) 2009 Simon van der Linden <svdlinden@src.gnome.org> + * pygtk- Python bindings for the GTK toolkit. + * Copyright (C) 1998-2003 James Henstridge + * 2004-2008 Johan Dahlin + * pyginterface.c: wrapper for the gobject library. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -14,33 +15,52 @@ * 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 + * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ -#ifndef __PYGI_TYPE_H__ +#ifndef __PYGI_TYPE_H__ #define __PYGI_TYPE_H__ #include <Python.h> +#include <glib-object.h> +#include <girepository.h> +#include "pygobject-internal.h" + +extern PyTypeObject PyGTypeWrapper_Type; -G_BEGIN_DECLS +typedef PyObject *(* fromvaluefunc)(const GValue *value); +typedef int (*tovaluefunc)(GValue *value, PyObject *obj); -/* Public */ +typedef struct { + fromvaluefunc fromvalue; + tovaluefunc tovalue; +} PyGTypeMarshal; -PyObject *pygi_type_import_by_g_type_real (GType g_type); +PyGTypeMarshal *pyg_type_lookup(GType type); +gboolean pyg_gtype_is_custom (GType gtype); -/* Private */ +void pyg_register_gtype_custom(GType gtype, + fromvaluefunc from_func, + tovaluefunc to_func); -PyObject *_pygi_type_import_by_name (const char *namespace_, const char *name); +int pygi_type_register_types(PyObject *d); -PyObject *_pygi_type_import_by_gi_info (GIBaseInfo *info); +PyObject *pyg_object_descr_doc_get(void); +PyObject *pyg_type_wrapper_new (GType type); +GType pyg_type_from_object_strict (PyObject *obj, gboolean strict); +GType pyg_type_from_object (PyObject *obj); -PyObject *_pygi_type_get_from_g_type (GType g_type); +int pyg_pyobj_to_unichar_conv (PyObject* py_obj, void* ptr); -PyObject *_pygi_get_py_type_hint (GITypeTag type_tag); +GClosure *pyg_closure_new(PyObject *callback, PyObject *extra_args, PyObject *swap_data); +GClosure *pyg_signal_class_closure_get(void); +void pyg_closure_set_exception_handler(GClosure *closure, + PyClosureExceptionHandler handler); -G_END_DECLS +PyObject *pygi_type_import_by_g_type (GType g_type); +PyObject *pygi_type_import_by_name (const char *namespace_, const char *name); +PyObject *pygi_type_import_by_gi_info (GIBaseInfo *info); +PyObject *pygi_type_get_from_g_type (GType g_type); #endif /* __PYGI_TYPE_H__ */ diff --git a/gi/pygi-util.c b/gi/pygi-util.c new file mode 100644 index 0000000..3a297f4 --- /dev/null +++ b/gi/pygi-util.c @@ -0,0 +1,126 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- + * pygtk- Python bindings for the GTK toolkit. + * Copyright (C) 1998-2003 James Henstridge + * + * 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, see <http://www.gnu.org/licenses/>. + */ + +#include "pygi-util.h" + +gboolean +pygi_guint_from_pyssize (Py_ssize_t pyval, guint *result) +{ + if (pyval < 0) { + PyErr_SetString (PyExc_ValueError, "< 0"); + return FALSE; + } else if (G_MAXUINT < PY_SSIZE_T_MAX && pyval > (Py_ssize_t)G_MAXUINT) { + PyErr_SetString (PyExc_ValueError, "too large"); + return FALSE; + } + *result = (guint)pyval; + return TRUE; +} + +PyObject * +pyg_integer_richcompare(PyObject *v, PyObject *w, int op) +{ + PyObject *result; + gboolean t; + + switch (op) { + case Py_EQ: t = PyLong_AS_LONG (v) == PyLong_AS_LONG (w); break; + case Py_NE: t = PyLong_AS_LONG (v) != PyLong_AS_LONG (w); break; + case Py_LE: t = PyLong_AS_LONG (v) <= PyLong_AS_LONG (w); break; + case Py_GE: t = PyLong_AS_LONG (v) >= PyLong_AS_LONG (w); break; + case Py_LT: t = PyLong_AS_LONG (v) < PyLong_AS_LONG (w); break; + case Py_GT: t = PyLong_AS_LONG (v) > PyLong_AS_LONG (w); break; + default: g_assert_not_reached(); + } + + result = t ? Py_True : Py_False; + Py_INCREF(result); + return result; +} + +PyObject* +pyg_ptr_richcompare(void* a, void *b, int op) +{ + PyObject *res; + + switch (op) { + case Py_EQ: + res = (a == b) ? Py_True : Py_False; + break; + case Py_NE: + res = (a != b) ? Py_True : Py_False; + break; + case Py_LT: + res = (a < b) ? Py_True : Py_False; + break; + case Py_LE: + res = (a <= b) ? Py_True : Py_False; + break; + case Py_GT: + res = (a > b) ? Py_True : Py_False; + break; + case Py_GE: + res = (a >= b) ? Py_True : Py_False; + break; + default: + res = Py_NotImplemented; + break; + } + + Py_INCREF(res); + return res; +} + +/** + * pyg_constant_strip_prefix: + * @name: the constant name. + * @strip_prefix: the prefix to strip. + * + * Advances the pointer @name by strlen(@strip_prefix) characters. If + * the resulting name does not start with a letter or underscore, the + * @name pointer will be rewound. This is to ensure that the + * resulting name is a valid identifier. Hence the returned string is + * a pointer into the string @name. + * + * Returns: the stripped constant name. + */ +const gchar * +pyg_constant_strip_prefix(const gchar *name, const gchar *strip_prefix) +{ + size_t prefix_len, i; + + prefix_len = strlen(strip_prefix); + + /* Check so name starts with strip_prefix, if it doesn't: + * return the rest of the part which doesn't match + */ + for (i = 0; i < prefix_len; i++) { + if (name[i] != strip_prefix[i] && name[i] != '_') { + return &name[i]; + } + } + + /* strip off prefix from value name, while keeping it a valid + * identifier */ + for (i = prefix_len + 1; i > 0; i--) { + if (g_ascii_isalpha(name[i - 1]) || name[i - 1] == '_') { + return &name[i - 1]; + } + } + return name; +} diff --git a/gi/pygi-util.h b/gi/pygi-util.h new file mode 100644 index 0000000..a223730 --- /dev/null +++ b/gi/pygi-util.h @@ -0,0 +1,56 @@ +#ifndef __PYGI_UTIL_H__ +#define __PYGI_UTIL_H__ + +#include <Python.h> +#include <glib.h> + +G_BEGIN_DECLS + +PyObject * pyg_integer_richcompare(PyObject *v, PyObject *w, int op); +PyObject * pyg_ptr_richcompare(void* a, void *b, int op); +const gchar * pyg_constant_strip_prefix(const gchar *name, const gchar *strip_prefix); + +gboolean pygi_guint_from_pyssize (Py_ssize_t pyval, guint *result); + +#if PY_VERSION_HEX < 0x030900A4 +# define Py_SET_TYPE(obj, type) ((Py_TYPE(obj) = (type)), (void)0) +#endif + +#if PY_VERSION_HEX >= 0x03080000 +# define CPy_TRASHCAN_BEGIN(op, dealloc) Py_TRASHCAN_BEGIN(op, dealloc) +# define CPy_TRASHCAN_END(op) Py_TRASHCAN_END +#else +# define CPy_TRASHCAN_BEGIN(op, dealloc) Py_TRASHCAN_SAFE_BEGIN(op) +# define CPy_TRASHCAN_END(op) Py_TRASHCAN_SAFE_END(op) +#endif + +#define PYGI_DEFINE_TYPE(typename, symbol, csymbol) \ +PyTypeObject symbol = { \ + PyVarObject_HEAD_INIT(NULL, 0) \ + typename, \ + sizeof(csymbol) \ +}; + +#define _PyGI_ERROR_PREFIX(format, ...) G_STMT_START { \ + PyObject *py_error_prefix; \ + py_error_prefix = PyUnicode_FromFormat(format, ## __VA_ARGS__); \ + if (py_error_prefix != NULL) { \ + PyObject *py_error_type, *py_error_value, *py_error_traceback; \ + PyErr_Fetch(&py_error_type, &py_error_value, &py_error_traceback); \ + if (PyUnicode_Check(py_error_value)) { \ + PyObject *new; \ + new = PyUnicode_Concat(py_error_prefix, py_error_value); \ + Py_DECREF(py_error_value); \ + if (new != NULL) { \ + py_error_value = new; \ + } \ + } \ + PyErr_Restore(py_error_type, py_error_value, py_error_traceback); \ + Py_DECREF(py_error_prefix); \ + } \ +} G_STMT_END + + +G_END_DECLS + +#endif /* __PYGI_UTIL_H__ */ diff --git a/gi/pygi-value.c b/gi/pygi-value.c new file mode 100644 index 0000000..e7ee1e0 --- /dev/null +++ b/gi/pygi-value.c @@ -0,0 +1,933 @@ + +/* -*- Mode: C; c-basic-offset: 4 -*- + * vim: tabstop=4 shiftwidth=4 expandtab + * + * 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, see <http://www.gnu.org/licenses/>. + */ + +#include <Python.h> +#include "pygi-value.h" +#include "pygi-struct.h" +#include "pygi-basictype.h" +#include "pygobject-object.h" +#include "pygi-type.h" +#include "pygenum.h" +#include "pygpointer.h" +#include "pygboxed.h" +#include "pygflags.h" +#include "pygparamspec.h" + + +/* glib 2.62 has started to print warnings for these which can't be disabled selectively, so just copy them here */ +#define PYGI_TYPE_VALUE_ARRAY (g_value_array_get_type()) +#define PYGI_IS_PARAM_SPEC_VALUE_ARRAY(pspec) (G_TYPE_CHECK_INSTANCE_TYPE ((pspec), PYGI_TYPE_VALUE_ARRAY)) +#define PYGI_PARAM_SPEC_VALUE_ARRAY(pspec) (G_TYPE_CHECK_INSTANCE_CAST ((pspec), g_param_spec_types[18], GParamSpecValueArray)) + +GIArgument +_pygi_argument_from_g_value(const GValue *value, + GITypeInfo *type_info) +{ + GIArgument arg = { 0, }; + + GITypeTag type_tag = g_type_info_get_tag (type_info); + + /* For the long handling: long can be equivalent to + int32 or int64, depending on the architecture, but + gi doesn't tell us (and same for ulong) + */ + switch (type_tag) { + case GI_TYPE_TAG_BOOLEAN: + arg.v_boolean = g_value_get_boolean (value); + break; + case GI_TYPE_TAG_INT8: + arg.v_int8 = g_value_get_schar (value); + break; + case GI_TYPE_TAG_INT16: + case GI_TYPE_TAG_INT32: + if (g_type_is_a (G_VALUE_TYPE (value), G_TYPE_LONG)) + arg.v_int32 = (gint32)g_value_get_long (value); + else + arg.v_int32 = (gint32)g_value_get_int (value); + break; + case GI_TYPE_TAG_INT64: + if (g_type_is_a (G_VALUE_TYPE (value), G_TYPE_LONG)) + arg.v_int64 = g_value_get_long (value); + else + arg.v_int64 = g_value_get_int64 (value); + break; + case GI_TYPE_TAG_UINT8: + arg.v_uint8 = g_value_get_uchar (value); + break; + case GI_TYPE_TAG_UINT16: + case GI_TYPE_TAG_UINT32: + if (g_type_is_a (G_VALUE_TYPE (value), G_TYPE_ULONG)) + arg.v_uint32 = (guint32)g_value_get_ulong (value); + else + arg.v_uint32 = (guint32)g_value_get_uint (value); + break; + case GI_TYPE_TAG_UINT64: + if (g_type_is_a (G_VALUE_TYPE (value), G_TYPE_ULONG)) + arg.v_uint64 = g_value_get_ulong (value); + else + arg.v_uint64 = g_value_get_uint64 (value); + break; + case GI_TYPE_TAG_UNICHAR: + arg.v_uint32 = g_value_get_schar (value); + break; + case GI_TYPE_TAG_FLOAT: + arg.v_float = g_value_get_float (value); + break; + case GI_TYPE_TAG_DOUBLE: + arg.v_double = g_value_get_double (value); + break; + case GI_TYPE_TAG_GTYPE: + arg.v_size = g_value_get_gtype (value); + break; + case GI_TYPE_TAG_UTF8: + case GI_TYPE_TAG_FILENAME: + /* Callers are responsible for ensuring the GValue stays alive + * long enough for the string to be copied. */ + arg.v_string = (char *)g_value_get_string (value); + break; + case GI_TYPE_TAG_GLIST: + case GI_TYPE_TAG_GSLIST: + case GI_TYPE_TAG_ARRAY: + case GI_TYPE_TAG_GHASH: + if (G_VALUE_HOLDS_BOXED (value)) + arg.v_pointer = g_value_get_boxed (value); + else + /* e. g. GSettings::change-event */ + arg.v_pointer = g_value_get_pointer (value); + break; + case GI_TYPE_TAG_INTERFACE: + { + GIBaseInfo *info; + GIInfoType info_type; + + info = g_type_info_get_interface (type_info); + info_type = g_base_info_get_type (info); + + g_base_info_unref (info); + + switch (info_type) { + case GI_INFO_TYPE_FLAGS: + arg.v_uint = g_value_get_flags (value); + break; + case GI_INFO_TYPE_ENUM: + arg.v_int = g_value_get_enum (value); + break; + case GI_INFO_TYPE_INTERFACE: + case GI_INFO_TYPE_OBJECT: + if (G_VALUE_HOLDS_PARAM (value)) + arg.v_pointer = g_value_get_param (value); + else + arg.v_pointer = g_value_get_object (value); + break; + case GI_INFO_TYPE_BOXED: + case GI_INFO_TYPE_STRUCT: + case GI_INFO_TYPE_UNION: + if (G_VALUE_HOLDS (value, G_TYPE_BOXED)) { + arg.v_pointer = g_value_get_boxed (value); + } else if (G_VALUE_HOLDS (value, G_TYPE_VARIANT)) { + arg.v_pointer = g_value_get_variant (value); + } else if (G_VALUE_HOLDS (value, G_TYPE_POINTER)) { + arg.v_pointer = g_value_get_pointer (value); + } else { + PyErr_Format (PyExc_NotImplementedError, + "Converting GValue's of type '%s' is not implemented.", + g_type_name (G_VALUE_TYPE (value))); + } + break; + default: + PyErr_Format (PyExc_NotImplementedError, + "Converting GValue's of type '%s' is not implemented.", + g_info_type_to_string (info_type)); + break; + } + break; + } + case GI_TYPE_TAG_ERROR: + arg.v_pointer = g_value_get_boxed (value); + break; + case GI_TYPE_TAG_VOID: + arg.v_pointer = g_value_get_pointer (value); + break; + default: + break; + } + + return arg; +} + + +/* Ignore g_value_array deprecations. Although they are deprecated, + * we still need to support the marshaling of them in PyGObject. + */ +G_GNUC_BEGIN_IGNORE_DEPRECATIONS + +static int +pyg_value_array_from_pyobject(GValue *value, + PyObject *obj, + const GParamSpecValueArray *pspec) +{ + Py_ssize_t seq_len; + GValueArray *value_array; + guint len, i; + + seq_len = PySequence_Length(obj); + if (seq_len == -1) { + PyErr_Clear(); + return -1; + } + len = (guint)seq_len; + + if (pspec && pspec->fixed_n_elements > 0 && len != pspec->fixed_n_elements) + return -1; + + value_array = g_value_array_new(len); + + for (i = 0; i < len; ++i) { + PyObject *item = PySequence_GetItem(obj, i); + GType type; + + 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 (type == G_TYPE_VALUE) { + const GValue * item_value = pyg_boxed_get(item, GValue); + g_value_array_append(value_array, item_value); + } else { + GValue item_value = { 0, }; + int status; + + 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; + } + g_value_array_append(value_array, &item_value); + g_value_unset(&item_value); + } + } + + g_value_take_boxed(value, value_array); + return 0; +} + +G_GNUC_END_IGNORE_DEPRECATIONS + +static int +pyg_array_from_pyobject(GValue *value, + PyObject *obj) +{ + Py_ssize_t len, i; + GArray *array; + + 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_with_error: + * @value: the GValue object to store the converted value in. + * @obj: the Python object to convert. + * + * This function converts a Python object and stores the result in a + * GValue. The GValue must be initialised in advance with + * g_value_init(). If the Python object can't be converted to the + * type of the GValue, then an error is returned. + * + * Returns: 0 on success, -1 on error. + */ +int +pyg_value_from_pyobject_with_error(GValue *value, PyObject *obj) +{ + 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)) { + 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: + { + gint8 temp; + if (pygi_gschar_from_py (obj, &temp)) { + g_value_set_schar (value, temp); + return 0; + } else + return -1; + } + case G_TYPE_UCHAR: + { + guchar temp; + if (pygi_guchar_from_py (obj, &temp)) { + g_value_set_uchar (value, temp); + return 0; + } else + return -1; + } + case G_TYPE_BOOLEAN: + { + gboolean temp; + if (pygi_gboolean_from_py (obj, &temp)) { + g_value_set_boolean (value, temp); + return 0; + } else + return -1; + } + case G_TYPE_INT: + { + gint temp; + if (pygi_gint_from_py (obj, &temp)) { + g_value_set_int (value, temp); + return 0; + } else + return -1; + } + case G_TYPE_UINT: + { + guint temp; + if (pygi_guint_from_py (obj, &temp)) { + g_value_set_uint (value, temp); + return 0; + } else + return -1; + } + case G_TYPE_LONG: + { + glong temp; + if (pygi_glong_from_py (obj, &temp)) { + g_value_set_long (value, temp); + return 0; + } else + return -1; + } + case G_TYPE_ULONG: + { + gulong temp; + if (pygi_gulong_from_py (obj, &temp)) { + g_value_set_ulong (value, temp); + return 0; + } else + return -1; + } + case G_TYPE_INT64: + { + gint64 temp; + if (pygi_gint64_from_py (obj, &temp)) { + g_value_set_int64 (value, temp); + return 0; + } else + return -1; + } + case G_TYPE_UINT64: + { + guint64 temp; + if (pygi_guint64_from_py (obj, &temp)) { + g_value_set_uint64 (value, temp); + return 0; + } else + return -1; + } + case G_TYPE_ENUM: + { + 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: + { + guint val = 0; + if (pyg_flags_get_value(G_VALUE_TYPE(value), obj, &val) < 0) { + return -1; + } + g_value_set_flags(value, val); + return 0; + } + break; + case G_TYPE_FLOAT: + { + gfloat temp; + if (pygi_gfloat_from_py (obj, &temp)) { + g_value_set_float (value, temp); + return 0; + } else + return -1; + } + case G_TYPE_DOUBLE: + { + gdouble temp; + if (pygi_gdouble_from_py (obj, &temp)) { + g_value_set_double (value, temp); + return 0; + } else + return -1; + } + case G_TYPE_STRING: + { + gchar *temp; + if (pygi_utf8_from_py (obj, &temp)) { + g_value_take_string (value, temp); + return 0; + } else { + /* also allows setting anything implementing __str__ */ + PyObject* str; + PyErr_Clear (); + str = PyObject_Str (obj); + if (str == NULL) + return -1; + if (pygi_utf8_from_py (str, &temp)) { + Py_DECREF (str); + g_value_take_string (value, temp); + return 0; + } + Py_DECREF (str); + return -1; + } + } + 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 (PyCapsule_CheckExact (obj)) + g_value_set_pointer(value, PyCapsule_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; + gboolean holds_value_array; + + G_GNUC_BEGIN_IGNORE_DEPRECATIONS + holds_value_array = G_VALUE_HOLDS(value, PYGI_TYPE_VALUE_ARRAY); + G_GNUC_END_IGNORE_DEPRECATIONS + + 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)) { + 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_with_error (n_value, obj); + } + else if (PySequence_Check(obj) && holds_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 (PyUnicode_Check (obj) && + G_VALUE_HOLDS(value, G_TYPE_GSTRING)) { + GString *string; + char *buffer; + Py_ssize_t len; + buffer = PyUnicode_AsUTF8AndSize (obj, &len); + if (buffer == NULL) + return -1; + string = g_string_new_len(buffer, len); + 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 (PyCapsule_CheckExact (obj)) + g_value_set_boxed(value, PyCapsule_GetPointer (obj, NULL)); + else { + PyErr_SetString(PyExc_TypeError, "Expected Boxed"); + return -1; + } + break; + } + case G_TYPE_PARAM: + /* we need to support both the wrapped _gi.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 (pyg_param_spec_check (obj)) + g_value_set_param(value, PyCapsule_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 { + 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); + } 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); + 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; +} + +/** + * pygi_value_to_py_basic_type: + * @value: the GValue object. + * @handled: (out): TRUE if the return value is defined + * + * This function creates/returns a Python wrapper object that + * represents the GValue passed as an argument limited to supporting basic types + * like ints, bools, and strings. + * + * Returns: a PyObject representing the value. + */ +PyObject * +pygi_value_to_py_basic_type (const GValue *value, GType fundamental, gboolean *handled) +{ + *handled = TRUE; + switch (fundamental) { + case G_TYPE_CHAR: + return PyLong_FromLong (g_value_get_schar (value)); + case G_TYPE_UCHAR: + return PyLong_FromLong (g_value_get_uchar (value)); + case G_TYPE_BOOLEAN: + return pygi_gboolean_to_py (g_value_get_boolean (value)); + case G_TYPE_INT: + return pygi_gint_to_py (g_value_get_int (value)); + case G_TYPE_UINT: + return pygi_guint_to_py (g_value_get_uint (value)); + case G_TYPE_LONG: + return pygi_glong_to_py (g_value_get_long(value)); + case G_TYPE_ULONG: + return pygi_gulong_to_py (g_value_get_ulong (value)); + case G_TYPE_INT64: + return pygi_gint64_to_py (g_value_get_int64 (value)); + case G_TYPE_UINT64: + return pygi_guint64_to_py (g_value_get_uint64 (value)); + case G_TYPE_ENUM: + 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)); + case G_TYPE_FLOAT: + return pygi_gfloat_to_py (g_value_get_float (value)); + case G_TYPE_DOUBLE: + return pygi_gdouble_to_py (g_value_get_double (value)); + case G_TYPE_STRING: + return pygi_utf8_to_py (g_value_get_string (value)); + default: + *handled = FALSE; + return NULL; + } +} + +/** + * value_to_py_structured_type: + * @value: the GValue object. + * @copy_boxed: true if boxed values should be copied. + * + * This function creates/returns a Python wrapper object that + * represents the GValue passed as an argument. + * + * Returns: a PyObject representing the value or NULL and sets an error; + */ +static PyObject * +value_to_py_structured_type (const GValue *value, GType fundamental, gboolean copy_boxed) +{ + const gchar *type_name; + + switch (fundamental) { + 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; + + case G_TYPE_POINTER: + 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; + gboolean holds_value_array; + + G_GNUC_BEGIN_IGNORE_DEPRECATIONS + holds_value_array = G_VALUE_HOLDS(value, PYGI_TYPE_VALUE_ARRAY); + G_GNUC_END_IGNORE_DEPRECATIONS + + 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 (holds_value_array) { + GValueArray *array = (GValueArray *) g_value_get_boxed(value); + Py_ssize_t n_values = array ? array->n_values : 0; + PyObject *ret = PyList_New(n_values); + int i; + for (i = 0; i < 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 = 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 pygi_gboxed_new(G_VALUE_TYPE(value), + g_value_get_boxed(value), TRUE, TRUE); + else + return pygi_gboxed_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)); + case G_TYPE_OBJECT: + 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 pygi_struct_new_from_g_type (G_TYPE_VARIANT, g_variant_ref(v), FALSE); + } + default: + { + PyGTypeMarshal *bm; + if ((bm = pyg_type_lookup(G_VALUE_TYPE(value)))) + return bm->fromvalue(value); + break; + } + } + + type_name = g_type_name (G_VALUE_TYPE (value)); + if (type_name == NULL) { + type_name = "(null)"; + } + PyErr_Format (PyExc_TypeError, "unknown type %s", type_name); + return NULL; +} + + +/** + * pyg_value_as_pyobject: + * @value: the GValue object. + * @copy_boxed: true if boxed values should be copied. + * + * This function creates/returns a Python wrapper object that + * represents the GValue passed as an argument. + * + * Returns: a PyObject representing the value or %NULL and sets an exception. + */ +PyObject * +pyg_value_as_pyobject (const GValue *value, gboolean copy_boxed) +{ + PyObject *pyobj; + gboolean handled; + GType fundamental = G_TYPE_FUNDAMENTAL (G_VALUE_TYPE (value)); + + /* HACK: special case char and uchar to return PyBytes intstead of integers + * in the general case. Property access will skip this by calling + * pygi_value_to_py_basic_type() directly. + * See: https://bugzilla.gnome.org/show_bug.cgi?id=733893 */ + if (fundamental == G_TYPE_CHAR) { + gint8 val = g_value_get_schar(value); + return PyUnicode_FromStringAndSize ((char *)&val, 1); + } else if (fundamental == G_TYPE_UCHAR) { + guint8 val = g_value_get_uchar(value); + return PyBytes_FromStringAndSize ((char *)&val, 1); + } + + pyobj = pygi_value_to_py_basic_type (value, fundamental, &handled); + if (handled) + return pyobj; + + pyobj = value_to_py_structured_type (value, fundamental, copy_boxed); + return pyobj; +} + + +G_GNUC_BEGIN_IGNORE_DEPRECATIONS +int +pyg_param_gvalue_from_pyobject(GValue* value, + PyObject* py_obj, + const GParamSpec* pspec) +{ + if (G_IS_PARAM_SPEC_UNICHAR(pspec)) { + gunichar u; + + if (!pyg_pyobj_to_unichar_conv(py_obj, &u)) { + PyErr_Clear(); + return -1; + } + g_value_set_uint(value, u); + return 0; + } + else if (PYGI_IS_PARAM_SPEC_VALUE_ARRAY(pspec)) + return pyg_value_array_from_pyobject(value, py_obj, + PYGI_PARAM_SPEC_VALUE_ARRAY(pspec)); + else { + return pyg_value_from_pyobject(value, py_obj); + } +} + +G_GNUC_END_IGNORE_DEPRECATIONS + +PyObject* +pyg_param_gvalue_as_pyobject(const GValue* gvalue, + gboolean copy_boxed, + const GParamSpec* pspec) +{ + if (G_IS_PARAM_SPEC_UNICHAR(pspec)) { + gunichar u; + gchar *encoded; + PyObject *retval; + + u = g_value_get_uint (gvalue); + encoded = g_ucs4_to_utf8 (&u, 1, NULL, NULL, NULL); + if (encoded == NULL) { + PyErr_SetString (PyExc_ValueError, "Failed to decode"); + return NULL; + } + retval = PyUnicode_FromString (encoded); + g_free (encoded); + return retval; + } + else { + return pyg_value_as_pyobject(gvalue, copy_boxed); + } +} + +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; + } + + return pyg_value_as_pyobject (pyg_boxed_get(pygvalue, GValue), + /*copy_boxed=*/ TRUE); +} + +PyObject * +pyg__gvalue_get_type(PyObject *module, PyObject *pygvalue) +{ + GValue *value; + GType type; + + if (!pyg_boxed_check (pygvalue, G_TYPE_VALUE)) { + PyErr_SetString (PyExc_TypeError, "Expected GValue argument."); + return NULL; + } + + value = pyg_boxed_get (pygvalue, GValue); + type = G_VALUE_TYPE (value); + return pyg_type_wrapper_new (type); +} + +PyObject * +pyg__gvalue_set(PyObject *module, PyObject *args) +{ + PyObject *pygvalue; + PyObject *pyobject; + + if (!PyArg_ParseTuple (args, "OO:_gi._gvalue_set", + &pygvalue, &pyobject)) + return NULL; + + 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; +} diff --git a/gi/pygi-value.h b/gi/pygi-value.h new file mode 100644 index 0000000..5778a22 --- /dev/null +++ b/gi/pygi-value.h @@ -0,0 +1,52 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- + * vim: tabstop=4 shiftwidth=4 expandtab + * + * 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, see <http://www.gnu.org/licenses/>. + */ + +#ifndef __PYGI_VALUE_H__ +#define __PYGI_VALUE_H__ + +#include <Python.h> +#include <glib-object.h> +#include <girepository.h> + +G_BEGIN_DECLS + +GIArgument _pygi_argument_from_g_value(const GValue *value, + GITypeInfo *type_info); + +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, + const GParamSpec* pspec); +PyObject *pyg_param_gvalue_as_pyobject(const GValue* gvalue, + gboolean copy_boxed, + const GParamSpec* pspec); +PyObject *pyg_strv_from_gvalue(const GValue *value); +int pyg_strv_to_gvalue(GValue *value, PyObject *obj); + +PyObject *pygi_value_to_py_basic_type (const GValue *value, + GType fundamental, + gboolean *handled); + +PyObject *pyg__gvalue_get(PyObject *module, PyObject *pygvalue); +PyObject *pyg__gvalue_set(PyObject *module, PyObject *args); +PyObject *pyg__gvalue_get_type(PyObject *module, PyObject *pygvalue); + +G_END_DECLS + +#endif /* __PYGI_VALUE_H__ */ diff --git a/gi/pygi.h b/gi/pygi.h deleted file mode 100644 index 3bf40bb..0000000 --- a/gi/pygi.h +++ /dev/null @@ -1,190 +0,0 @@ -/* -*- Mode: C; c-basic-offset: 4 -*- - * vim: tabstop=4 shiftwidth=4 expandtab - * - * Copyright (C) 2005-2009 Johan Dahlin <johan@gnome.org> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 - * USA - */ - -#ifndef __PYGI_H__ -#define __PYGI_H__ - -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif - -#define NO_IMPORT_PYGOBJECT -#include <pygobject.h> - -#include <girepository.h> -#include "pygi-cache.h" - -extern PyObject *PyGIDeprecationWarning; - -typedef struct { - PyObject_HEAD - GIRepository *repository; -} PyGIRepository; - -typedef struct { - PyObject_HEAD - GIBaseInfo *info; - PyObject *inst_weakreflist; - PyGICallableCache *cache; -} PyGIBaseInfo; - -typedef struct { - PyGIBaseInfo base; - - /* Reference the unbound version of this struct. - * We use this for the actual call to invoke because it manages the cache. - */ - struct PyGICallableInfo *py_unbound_info; - - /* Holds bound argument for instance, class, and vfunc methods. */ - PyObject *py_bound_arg; - -} PyGICallableInfo; - -typedef struct { - PyGPointer base; - gboolean free_on_dealloc; -} PyGIStruct; - -typedef struct { - PyGBoxed base; - gboolean slice_allocated; - gsize size; -} PyGIBoxed; - -typedef struct { - PyObject_HEAD - GCallback callback; - GIFunctionInfo *info; - gpointer user_data; - GIScopeType scope; - GDestroyNotify destroy_notify_func; - PyGICallableCache *cache; -} PyGICCallback; - -typedef PyObject * (*PyGIArgOverrideToGIArgumentFunc) (PyObject *value, - GIInterfaceInfo *interface_info, - GITransfer transfer, - GIArgument *arg); -typedef PyObject * (*PyGIArgOverrideFromGIArgumentFunc) (GIInterfaceInfo *interface_info, - gpointer data); -typedef PyObject * (*PyGIArgOverrideReleaseFunc) (GITypeInfo *type_info, - gpointer struct_); - -struct PyGI_API { - PyObject* (*type_import_by_g_type) (GType g_type); - PyObject* (*get_property_value) (PyGObject *instance, - GParamSpec *pspec); - gint (*set_property_value) (PyGObject *instance, - GParamSpec *pspec, - PyObject *value); - GClosure * (*signal_closure_new) (PyGObject *instance, - GType g_type, - const gchar *sig_name, - PyObject *callback, - PyObject *extra_args, - PyObject *swap_data); - void (*register_foreign_struct) (const char* namespace_, - const char* name, - PyGIArgOverrideToGIArgumentFunc to_func, - PyGIArgOverrideFromGIArgumentFunc from_func, - PyGIArgOverrideReleaseFunc release_func); -}; - -static struct PyGI_API *PyGI_API = NULL; - -static int -_pygi_import (void) -{ - if (PyGI_API != NULL) { - return 1; - } - PyGI_API = (struct PyGI_API*) PyCapsule_Import("gi._API", FALSE); - if (PyGI_API == NULL) { - return -1; - } - - return 0; -} - -static inline PyObject * -pygi_type_import_by_g_type (GType g_type) -{ - if (_pygi_import() < 0) { - return NULL; - } - return PyGI_API->type_import_by_g_type(g_type); -} - -static inline PyObject * -pygi_get_property_value (PyGObject *instance, - GParamSpec *pspec) -{ - if (_pygi_import() < 0) { - return NULL; - } - return PyGI_API->get_property_value(instance, pspec); -} - -static inline gint -pygi_set_property_value (PyGObject *instance, - GParamSpec *pspec, - PyObject *value) -{ - if (_pygi_import() < 0) { - return -1; - } - return PyGI_API->set_property_value(instance, pspec, value); -} - -static inline GClosure * -pygi_signal_closure_new (PyGObject *instance, - GType g_type, - const gchar *sig_name, - PyObject *callback, - PyObject *extra_args, - PyObject *swap_data) -{ - if (_pygi_import() < 0) { - return NULL; - } - return PyGI_API->signal_closure_new(instance, g_type, sig_name, callback, extra_args, swap_data); -} - -static inline PyObject * -pygi_register_foreign_struct (const char* namespace_, - const char* name, - PyGIArgOverrideToGIArgumentFunc to_func, - PyGIArgOverrideFromGIArgumentFunc from_func, - PyGIArgOverrideReleaseFunc release_func) -{ - if (_pygi_import() < 0) { - return NULL; - } - PyGI_API->register_foreign_struct(namespace_, - name, - to_func, - from_func, - release_func); - Py_RETURN_NONE; -} - -#endif /* __PYGI_H__ */ diff --git a/gi/_gobject/pyginterface.c b/gi/pyginterface.c index eb76ba0..288fbb2 100644 --- a/gi/_gobject/pyginterface.c +++ b/gi/pyginterface.c @@ -15,25 +15,22 @@ * 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 + * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif +#include <config.h> #include <Python.h> -#include "pyglib.h" -#include "pygobject-private.h" +#include <glib-object.h> +#include "pygi-util.h" #include "pyginterface.h" +#include "pygi-type.h" GQuark pyginterface_type_key; GQuark pyginterface_info_key; -PYGLIB_DEFINE_TYPE("gobject.GInterface", PyGInterface_Type, PyObject) +PYGI_DEFINE_TYPE("gobject.GInterface", PyGInterface_Type, PyObject) static int pyg_interface_init(PyObject *self, PyObject *args, PyObject *kwargs) @@ -72,7 +69,8 @@ pyg_register_interface(PyObject *dict, const gchar *class_name, { PyObject *o; - Py_TYPE(type) = &PyType_Type; + Py_SET_TYPE(type, &PyType_Type); + g_assert (Py_TYPE (&PyGInterface_Type) != NULL); type->tp_base = &PyGInterface_Type; if (PyType_Ready(type) < 0) { @@ -87,15 +85,21 @@ pyg_register_interface(PyObject *dict, const gchar *class_name, } g_type_set_qdata(gtype, pyginterface_type_key, type); - + PyDict_SetItemString(dict, (char *)class_name, (PyObject *)type); - + } void pyg_register_interface_info(GType gtype, const GInterfaceInfo *info) { - g_type_set_qdata(gtype, pyginterface_info_key, (gpointer) info); + GInterfaceInfo *prev_info = pyg_lookup_interface_info (gtype); + + if (prev_info) { + g_free (prev_info); + } + + g_type_set_qdata(gtype, pyginterface_info_key, g_memdup2 (info, sizeof(GInterfaceInfo))); } const GInterfaceInfo * @@ -104,21 +108,35 @@ pyg_lookup_interface_info(GType gtype) return g_type_get_qdata(gtype, pyginterface_info_key); } -void -pygobject_interface_register_types(PyObject *d) +/** + * Returns 0 on success, or -1 and sets an exception. + */ +int +pygi_interface_register_types(PyObject *d) { - pyginterface_type_key = g_quark_from_static_string("PyGInterface::type"); - pyginterface_info_key = g_quark_from_static_string("PyGInterface::info"); + PyObject *pygtype; + + pyginterface_type_key = g_quark_from_static_string("PyGInterface::type"); + pyginterface_info_key = g_quark_from_static_string("PyGInterface::info"); + + PyGInterface_Type.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE; + PyGInterface_Type.tp_init = (initproc)pyg_interface_init; + PyGInterface_Type.tp_free = (freefunc)pyg_interface_free; + PyGInterface_Type.tp_alloc = PyType_GenericAlloc; + PyGInterface_Type.tp_new = PyType_GenericNew; + if (PyType_Ready(&PyGInterface_Type)) + return -1; + + pygtype = pyg_type_wrapper_new (G_TYPE_INTERFACE); + PyDict_SetItemString (PyGInterface_Type.tp_dict, "__gtype__", pygtype); + Py_DECREF (pygtype); - PyGInterface_Type.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE; - PyGInterface_Type.tp_init = (initproc)pyg_interface_init; - PyGInterface_Type.tp_free = (freefunc)pyg_interface_free; + PyDict_SetItemString(PyGInterface_Type.tp_dict, "__doc__", + pyg_object_descr_doc_get()); + PyDict_SetItemString(PyGInterface_Type.tp_dict, "__gdoc__", + pyg_object_descr_doc_get()); - PYGOBJECT_REGISTER_GTYPE(d, PyGInterface_Type, "GInterface", G_TYPE_INTERFACE) + PyDict_SetItemString(d, "GInterface", (PyObject *)&PyGInterface_Type); - PyDict_SetItemString(PyGInterface_Type.tp_dict, "__doc__", - pyg_object_descr_doc_get()); - PyDict_SetItemString(PyGInterface_Type.tp_dict, "__gdoc__", - pyg_object_descr_doc_get()); - + return 0; } diff --git a/gi/_gobject/pyginterface.h b/gi/pyginterface.h index 0f390c2..d5819ce 100644 --- a/gi/_gobject/pyginterface.h +++ b/gi/pyginterface.h @@ -15,9 +15,7 @@ * 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 + * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ #ifndef __PYGOBJECT_INTERFACE_H__ @@ -35,6 +33,6 @@ void pyg_register_interface(PyObject *dict, const GInterfaceInfo * pyg_lookup_interface_info(GType gtype); void pyg_register_interface_info(GType gtype, const GInterfaceInfo *info); -void pygobject_interface_register_types(PyObject *d); +int pygi_interface_register_types(PyObject *d); #endif /* __PYGOBJECT_INTERFACE_H__ */ diff --git a/gi/pygobject-external.h b/gi/pygobject-external.h deleted file mode 100644 index 8299864..0000000 --- a/gi/pygobject-external.h +++ /dev/null @@ -1,75 +0,0 @@ -/* -*- Mode: C; c-basic-offset: 4 -*- - * vim: tabstop=4 shiftwidth=4 expandtab - * - * Copyright (C) 2009 Simon van der Linden <svdlinden@src.gnome.org> - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 - * USA - */ - -#ifndef __PYGOBJECT_EXTERN_H__ -#define __PYGOBJECT_EXTERN_H__ - -#include <Python.h> - -G_BEGIN_DECLS - -static PyTypeObject *_PyGTypeWrapper_Type; - -#define PyGTypeWrapper_Type (*_PyGTypeWrapper_Type) - -G_GNUC_UNUSED -static int -_pygobject_import (void) -{ - static gboolean imported = FALSE; - PyObject *from_list; - PyObject *module; - int retval = 0; - - if (imported) { - return 1; - } - - from_list = Py_BuildValue ("(s)", "GType"); - if (from_list == NULL) { - return -1; - } - - module = PyImport_ImportModuleEx ("gi._gobject", NULL, NULL, from_list); - - Py_DECREF (from_list); - - if (module == NULL) { - return -1; - } - - _PyGTypeWrapper_Type = (PyTypeObject *) PyObject_GetAttrString (module, "GType"); - if (_PyGTypeWrapper_Type == NULL) { - retval = -1; - goto out; - } - - imported = TRUE; - -out: - Py_DECREF (module); - - return retval; -} - -G_END_DECLS - -#endif /* __PYGOBJECT_EXTERN_H__ */ diff --git a/gi/pygobject-internal.h b/gi/pygobject-internal.h new file mode 100644 index 0000000..2cd82c5 --- /dev/null +++ b/gi/pygobject-internal.h @@ -0,0 +1,7 @@ +#ifndef _PYGOBJECT_INTERNAL_H_ +#define _PYGOBJECT_INTERNAL_H_ + +#define _INSIDE_PYGOBJECT_ +#include "pygobject.h" + +#endif /*_PYGOBJECT_INTERNAL_H_*/ diff --git a/gi/_gobject/pygobject.c b/gi/pygobject-object.c index 126c80e..961f6dd 100644 --- a/gi/_gobject/pygobject.c +++ b/gi/pygobject-object.c @@ -15,31 +15,32 @@ * 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 + * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif +#include <config.h> -#include <pyglib.h> -#include "pygobject-private.h" +#include "pygobject-object.h" #include "pyginterface.h" #include "pygparamspec.h" +#include "pygi-type.h" +#include "pygboxed.h" +#include "gimodule.h" -#include "pygi.h" +#include "pygi-util.h" +#include "pygi-value.h" +#include "pygi-type.h" +#include "pygi-property.h" +#include "pygi-signal-closure.h" +#include "pygi-basictype.h" +extern PyObject *PyGIDeprecationWarning; static void pygobject_dealloc(PyGObject *self); static int pygobject_traverse(PyGObject *self, visitproc visit, void *arg); -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 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, @@ -52,6 +53,31 @@ GQuark pygobject_wrapper_key; GQuark pygobject_has_updated_constructor_key; GQuark pygobject_instance_data_key; +/* PyPy doesn't support tp_dictoffset, so we have to work around it */ +#ifndef PYPY_VERSION +#define PYGI_OBJECT_USE_CUSTOM_DICT +#endif + +GClosure * +gclosure_from_pyfunc(PyGObject *object, PyObject *func) +{ + GSList *l; + PyGObjectData *inst_data; + inst_data = pyg_object_peek_inst_data(object->obj); + if (inst_data) { + for (l = inst_data->closures; l; l = l->next) { + PyGClosure *pyclosure = l->data; + int res = PyObject_RichCompareBool(pyclosure->callback, func, Py_EQ); + if (res == -1) { + PyErr_Clear(); /* Is there anything else to do? */ + } else if (res) { + return (GClosure*)pyclosure; + } + } + } + return NULL; +} + /* 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. */ @@ -74,19 +100,20 @@ canonicalize_key (gchar *key) /* -------------- class <-> wrapper manipulation --------------- */ -void +static void pygobject_data_free(PyGObjectData *data) { /* 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; + PyGILState_STATE state = 0; PyThreadState *_save = NULL; - + gboolean state_saved; GSList *closures, *tmp; - if (Py_IsInitialized()) { - state = pyglib_gil_state_ensure(); + state_saved = Py_IsInitialized(); + if (state_saved) { + state = PyGILState_Ensure(); Py_DECREF(data->type); /* We cannot use Py_BEGIN_ALLOW_THREADS here because this is inside * a branch. */ @@ -112,9 +139,9 @@ pygobject_data_free(PyGObjectData *data) g_free(data); - if (Py_IsInitialized()) { + if (state_saved && Py_IsInitialized ()) { Py_BLOCK_THREADS; /* Restores _save */ - pyglib_gil_state_release(state); + PyGILState_Release(state); } } @@ -180,7 +207,7 @@ typedef struct { guint index; } PyGPropsIter; -PYGLIB_DEFINE_TYPE("gi._gobject.GPropsIter", PyGPropsIter_Type, PyGPropsIter); +PYGI_DEFINE_TYPE("gi._gi.GPropsIter", PyGPropsIter_Type, PyGPropsIter); static void pyg_props_iter_dealloc(PyGPropsIter *self) @@ -236,14 +263,12 @@ build_parameter_list(GObjectClass *class) name = g_strdup(g_param_spec_get_name(props[i])); /* hyphens cannot belong in identifiers */ g_strdelimit(name, "-", '_'); - prop_str = PYGLIB_PyUnicode_FromString(name); + prop_str = PyUnicode_FromString (name); PyList_SetItem(props_list, i, prop_str); g_free(name); } - g_type_class_unref(class); - if (props) g_free(props); @@ -256,22 +281,14 @@ PyGProps_getattro(PyGProps *self, PyObject *attr) char *attr_name, *property_name; GObjectClass *class; GParamSpec *pspec; - GValue value = { 0, }; - PyObject *ret; - attr_name = PYGLIB_PyUnicode_AsString(attr); + attr_name = PyUnicode_AsUTF8 (attr); if (!attr_name) { PyErr_Clear(); return PyObject_GenericGetAttr((PyObject *)self, attr); } class = g_type_class_ref(self->gtype); - - if (!strcmp(attr_name, "__members__")) { - 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 @@ -286,36 +303,12 @@ PyGProps_getattro(PyGProps *self, PyObject *attr) return PyObject_GenericGetAttr((PyObject *)self, attr); } - if (!(pspec->flags & G_PARAM_READABLE)) { - PyErr_Format(PyExc_TypeError, - "property '%s' is not readable", attr_name); - return NULL; - } - 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)); - 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); - - return ret; + return pygi_get_property_value (self->pygobject, pspec); } static gboolean @@ -340,10 +333,10 @@ set_property_from_pspec(GObject *obj, g_value_init(&value, G_PARAM_SPEC_VALUE_TYPE(pspec)); if (pyg_param_gvalue_from_pyobject(&value, pvalue, pspec) < 0) { - PyObject *pvalue_str = PyObject_Str(pvalue); + PyObject *pvalue_str = PyObject_Repr(pvalue); PyErr_Format(PyExc_TypeError, - "could not convert '%s' to type '%s' when setting property '%s.%s'", - PYGLIB_PyUnicode_AsString(pvalue_str), + "could not convert %s to type '%s' when setting property '%s.%s'", + PyUnicode_AsUTF8 (pvalue_str), g_type_name(G_PARAM_SPEC_VALUE_TYPE(pspec)), G_OBJECT_TYPE_NAME(obj), pspec->name); @@ -359,7 +352,7 @@ set_property_from_pspec(GObject *obj, return TRUE; } -PYGLIB_DEFINE_TYPE("gi._gobject.GProps", PyGProps_Type, PyGProps); +PYGI_DEFINE_TYPE("gi._gi.GProps", PyGProps_Type, PyGProps); static int PyGProps_setattro(PyGProps *self, PyObject *attr, PyObject *pvalue) @@ -375,7 +368,7 @@ PyGProps_setattro(PyGProps *self, PyObject *attr, PyObject *pvalue) return -1; } - attr_name = PYGLIB_PyUnicode_AsString(attr); + attr_name = PyUnicode_AsUTF8 (attr); if (!attr_name) { PyErr_Clear(); return PyObject_GenericSetAttr((PyObject *)self, attr, pvalue); @@ -441,6 +434,25 @@ pygobject_props_get_iter(PyGProps *self) return (PyObject *) iter; } +static PyObject* +pygobject_props_dir(PyGProps *self) +{ + PyObject *ret; + GObjectClass *class; + + class = g_type_class_ref (self->gtype); + ret = build_parameter_list (class); + g_type_class_unref (class); + + return ret; +} + +static PyMethodDef pygobject_props_methods[] = { + { "__dir__", (PyCFunction)pygobject_props_dir, METH_NOARGS}, + { NULL, NULL, 0} +}; + + static Py_ssize_t PyGProps_length(PyGProps *self) { @@ -466,7 +478,7 @@ static PySequenceMethods _PyGProps_as_sequence = { 0 }; -PYGLIB_DEFINE_TYPE("gi._gobject.GPropsDescr", PyGPropsDescr_Type, PyObject); +PYGI_DEFINE_TYPE("gi._gi.GPropsDescr", PyGPropsDescr_Type, PyObject); static PyObject * pyg_props_descr_descr_get(PyObject *self, PyObject *obj, PyObject *type) @@ -548,7 +560,7 @@ pygobject_register_class(PyObject *dict, const gchar *type_name, } else bases = runtime_bases; - Py_TYPE(type) = PyGObject_MetaType; + Py_SET_TYPE(type, PyGObject_MetaType); type->tp_bases = bases; if (G_LIKELY(bases)) { type->tp_base = (PyTypeObject *)PyTuple_GetItem(bases, 0); @@ -567,7 +579,7 @@ pygobject_register_class(PyObject *dict, const gchar *type_name, */ s = strrchr(type->tp_name, '.'); if (s != NULL) { - mod_name = PYGLIB_PyUnicode_FromStringAndSize(type->tp_name, (int)(s - type->tp_name)); + mod_name = PyUnicode_FromStringAndSize (type->tp_name, (int)(s - type->tp_name)); PyDict_SetItemString(type->tp_dict, "__module__", mod_name); Py_DECREF(mod_name); } @@ -592,17 +604,49 @@ pygobject_register_class(PyObject *dict, const gchar *type_name, static void pyg_toggle_notify (gpointer data, GObject *object, gboolean is_last_ref) { - PyGObject *self = (PyGObject*) data; + PyGObject *self; PyGILState_STATE state; - state = pyglib_gil_state_ensure(); + state = PyGILState_Ensure(); - if (is_last_ref) - Py_DECREF(self); - else - Py_INCREF(self); + /* Avoid thread safety problems by using qdata for wrapper retrieval + * instead of the user data argument. + * See: https://bugzilla.gnome.org/show_bug.cgi?id=709223 + */ + self = (PyGObject *)g_object_get_qdata (object, pygobject_wrapper_key); + if (self) { + if (is_last_ref) + Py_DECREF(self); + else + Py_INCREF(self); + } - pyglib_gil_state_release(state); + PyGILState_Release(state); +} + +static inline gboolean +pygobject_toggle_ref_is_required (PyGObject *self) +{ +#ifdef PYGI_OBJECT_USE_CUSTOM_DICT + return self->inst_dict != NULL; +#else + PyObject *dict; + gboolean result; + dict = PyObject_GetAttrString ((PyObject *)self, "__dict__"); + if (!dict) { + PyErr_Clear (); + return FALSE; + } + result = PyDict_Size (dict) != 0; + Py_DECREF (dict); + return result; +#endif +} + +static inline gboolean +pygobject_toggle_ref_is_active (PyGObject *self) +{ + return self->private_flags.flags & PYGOBJECT_USING_TOGGLE_REF; } /* Called when the inst_dict is first created; switches the @@ -611,17 +655,23 @@ pyg_toggle_notify (gpointer data, GObject *object, gboolean is_last_ref) inst_dict was NULL the python wrapper is allowed to die at will and is recreated on demand. */ static inline void -pygobject_switch_to_toggle_ref(PyGObject *self) +pygobject_toggle_ref_ensure (PyGObject *self) { - g_assert(self->obj->ref_count >= 1); + if (pygobject_toggle_ref_is_active (self)) + return; - if (self->private_flags.flags & PYGOBJECT_USING_TOGGLE_REF) - return; /* already using toggle ref */ + if (!pygobject_toggle_ref_is_required (self)) + return; + + if (self->obj == NULL) + return; + + g_assert(self->obj->ref_count >= 1); self->private_flags.flags |= PYGOBJECT_USING_TOGGLE_REF; /* Note that add_toggle_ref will never immediately call back into pyg_toggle_notify */ Py_INCREF((PyObject *) self); - g_object_add_toggle_ref(self->obj, pyg_toggle_notify, self); + g_object_add_toggle_ref(self->obj, pyg_toggle_notify, NULL); g_object_unref(self->obj); } @@ -672,8 +722,8 @@ pygobject_register_wrapper(PyObject *self) g_assert(gself->obj->ref_count >= 1); /* save wrapper pointer so we can access it later */ g_object_set_qdata_full(gself->obj, pygobject_wrapper_key, gself, NULL); - if (gself->inst_dict) - pygobject_switch_to_toggle_ref(gself); + + pygobject_toggle_ref_ensure (gself); } static PyObject * @@ -683,7 +733,7 @@ pyg_type_get_bases(GType gtype) guint n_interfaces; PyTypeObject *py_parent_type, *py_interface_type; PyObject *bases; - int i; + guint i; if (G_UNLIKELY(gtype == G_TYPE_OBJECT)) return NULL; @@ -728,10 +778,8 @@ pygobject_new_with_interfaces(GType gtype) PyObject *dict; PyTypeObject *py_parent_type; PyObject *bases; - PyObject *modules, *module; - gchar *type_name, *mod_name, *gtype_name; - state = pyglib_gil_state_ensure(); + state = PyGILState_Ensure(); bases = pyg_type_get_bases(gtype); py_parent_type = (PyTypeObject *) PyTuple_GetItem(bases, 0); @@ -745,36 +793,18 @@ pygobject_new_with_interfaces(GType gtype) /* set up __doc__ descriptor on type */ PyDict_SetItemString(dict, "__doc__", pyg_object_descr_doc_get()); - /* generate the pygtk module name and extract the base type name */ - gtype_name = (gchar*)g_type_name(gtype); - if (g_str_has_prefix(gtype_name, "Gtk")) { - mod_name = "gtk"; - gtype_name += 3; - type_name = g_strconcat(mod_name, ".", gtype_name, NULL); - } else if (g_str_has_prefix(gtype_name, "Gdk")) { - mod_name = "gtk.gdk"; - gtype_name += 3; - type_name = g_strconcat(mod_name, ".", gtype_name, NULL); - } else if (g_str_has_prefix(gtype_name, "Atk")) { - mod_name = "atk"; - gtype_name += 3; - type_name = g_strconcat(mod_name, ".", gtype_name, NULL); - } else if (g_str_has_prefix(gtype_name, "Pango")) { - mod_name = "pango"; - gtype_name += 5; - type_name = g_strconcat(mod_name, ".", gtype_name, NULL); - } else { - mod_name = "__main__"; - type_name = g_strconcat(mod_name, ".", gtype_name, NULL); - } + /* Something special to point out that it's not accessible through + * gi.repository */ + o = PyUnicode_FromString ("__gi__"); + PyDict_SetItemString (dict, "__module__", o); + Py_DECREF (o); type = (PyTypeObject*)PyObject_CallFunction((PyObject *) Py_TYPE(py_parent_type), - "sNN", type_name, bases, dict); - g_free(type_name); + "sNN", g_type_name (gtype), bases, dict); if (type == NULL) { PyErr_Print(); - pyglib_gil_state_release(state); + PyGILState_Release(state); return NULL; } @@ -799,21 +829,15 @@ pygobject_new_with_interfaces(GType gtype) if (PyType_Ready(type) < 0) { g_warning ("couldn't make the type `%s' ready", type->tp_name); - pyglib_gil_state_release(state); + PyGILState_Release(state); return NULL; } - /* insert type name in module dict */ - modules = PyImport_GetModuleDict(); - if ((module = PyDict_GetItemString(modules, mod_name)) != NULL) { - if (PyObject_SetAttrString(module, gtype_name, (PyObject *)type) < 0) - PyErr_Clear(); - } /* stash a pointer to the python class with the GType */ Py_INCREF(type); g_type_set_qdata(gtype, pygobject_class_key, type); - pyglib_gil_state_release(state); + PyGILState_Release(state); return type; } @@ -846,16 +870,13 @@ static void pygobject_inherit_slots(PyTypeObject *type, PyObject *bases, gboolean check_for_present) { static int slot_offsets[] = { offsetof(PyTypeObject, tp_richcompare), -#if PY_VERSION_HEX < 0x03000000 - offsetof(PyTypeObject, tp_compare), -#endif offsetof(PyTypeObject, tp_richcompare), offsetof(PyTypeObject, tp_hash), offsetof(PyTypeObject, tp_iter), offsetof(PyTypeObject, tp_repr), offsetof(PyTypeObject, tp_str), - offsetof(PyTypeObject, tp_print) }; - int i; + }; + gsize i; /* Happens when registering gobject.GObject itself, at least. */ if (!bases) @@ -869,11 +890,11 @@ static void pygobject_find_slot_for(PyTypeObject *type, PyObject *bases, int slot_offset, gboolean check_for_present) { -#define TYPE_SLOT(type) (* (void **) (((char *) (type)) + slot_offset)) +#define TYPE_SLOT(type) (* (void **) (void *) (((char *) (type)) + slot_offset)) void *found_slot = NULL; - int num_bases = PyTuple_Size(bases); - int i; + Py_ssize_t num_bases = PyTuple_Size(bases); + Py_ssize_t i; if (check_for_present && TYPE_SLOT(type) != NULL) { /* We are requested to check if there is any custom slot value @@ -921,6 +942,8 @@ pygobject_find_slot_for(PyTypeObject *type, PyObject *bases, int slot_offset, * or interface has been registered for the given GType, then a new * type will be created. * + * Does not set an exception when NULL is returned. + * * Returns: The wrapper class for the GObject or NULL if the * GType has no registered type and a new type couldn't be created */ @@ -930,19 +953,22 @@ pygobject_lookup_class(GType gtype) PyTypeObject *py_type; if (gtype == G_TYPE_INTERFACE) - return &PyGInterface_Type; + return &PyGInterface_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); + py_type = g_type_get_qdata(gtype, pyginterface_type_key); - if (py_type == NULL) - py_type = (PyTypeObject *)pygi_type_import_by_g_type(gtype); + if (py_type == NULL) { + py_type = (PyTypeObject *)pygi_type_import_by_g_type(gtype); + PyErr_Clear (); + } - if (py_type == NULL) { - py_type = pygobject_new_with_interfaces(gtype); - g_type_set_qdata(gtype, pyginterface_type_key, py_type); - } + if (py_type == NULL) { + py_type = pygobject_new_with_interfaces(gtype); + PyErr_Clear (); + g_type_set_qdata(gtype, pyginterface_type_key, py_type); + } } return py_type; @@ -1040,7 +1066,12 @@ pygobject_unwatch_closure(gpointer data, GClosure *closure) { PyGObjectData *inst_data = data; + /* Despite no Python API is called the list inst_data->closures + * must be protected by GIL as it is used by GC in + * pygobject_traverse */ + PyGILState_STATE state = PyGILState_Ensure(); inst_data->closures = g_slist_remove (inst_data->closures, closure); + PyGILState_Release(state); } /** @@ -1067,6 +1098,7 @@ pygobject_watch_closure(PyObject *self, GClosure *closure) gself = (PyGObject *)self; data = pygobject_get_inst_data(gself); + g_return_if_fail(data != NULL); g_return_if_fail(g_slist_find(data->closures, closure) == NULL); data->closures = g_slist_prepend(data->closures, closure); g_closure_add_invalidate_notifier(closure, data, pygobject_unwatch_closure); @@ -1075,7 +1107,7 @@ pygobject_watch_closure(PyObject *self, GClosure *closure) /* -------------- PyGObject behaviour ----------------- */ -PYGLIB_DEFINE_TYPE("gi._gobject.GObject", PyGObject_Type, PyGObject); +PYGI_DEFINE_TYPE("gi._gi.GObject", PyGObject_Type, PyGObject); static void pygobject_dealloc(PyGObject *self) @@ -1087,7 +1119,9 @@ pygobject_dealloc(PyGObject *self) * object. */ PyObject_GC_UnTrack((PyObject *)self); - PyObject_ClearWeakRefs((PyObject *)self); + if (self->weakreflist != NULL) + PyObject_ClearWeakRefs((PyObject *)self); + /* this forces inst_data->type to be updated, which could prove * important if a new wrapper has to be created and it is of a * unregistered type */ @@ -1118,29 +1152,46 @@ pygobject_richcompare(PyObject *self, PyObject *other, int op) return Py_NotImplemented; } - return _pyglib_generic_ptr_richcompare(((PyGObject*)self)->obj, - ((PyGObject*)other)->obj, - op); + return pyg_ptr_richcompare(((PyGObject*)self)->obj, + ((PyGObject*)other)->obj, + op); } -static long +static Py_hash_t pygobject_hash(PyGObject *self) { - return (long)self->obj; + return (Py_hash_t)(gintptr)(self->obj); } static PyObject * pygobject_repr(PyGObject *self) { - gchar buf[256]; + PyObject *module, *repr; + gchar *module_str, *namespace; - g_snprintf(buf, sizeof(buf), - "<%s object at 0x%lx (%s at 0x%lx)>", - Py_TYPE(self)->tp_name, - (long)self, - self->obj ? G_OBJECT_TYPE_NAME(self->obj) : "uninitialized", - (long)self->obj); - return PYGLIB_PyUnicode_FromString(buf); + module = PyObject_GetAttrString ((PyObject *)self, "__module__"); + if (module == NULL) + return NULL; + + if (!PyUnicode_Check (module)) { + Py_DECREF (module); + return NULL; + } + + module_str = PyUnicode_AsUTF8 (module); + namespace = g_strrstr (module_str, "."); + if (namespace == NULL) { + namespace = module_str; + } else { + namespace += 1; + } + + repr = PyUnicode_FromFormat ("<%s.%s object at %p (%s at %p)>", + namespace, Py_TYPE (self)->tp_name, self, + self->obj ? G_OBJECT_TYPE_NAME (self->obj) : "uninitialized", + self->obj); + Py_DECREF (module); + return repr; } @@ -1154,8 +1205,10 @@ pygobject_traverse(PyGObject *self, visitproc visit, void *arg) if (self->inst_dict) ret = visit(self->inst_dict, arg); if (ret != 0) return ret; - if (data) { - + /* Only let the GC track the closures when tp_clear() would free them. + * https://bugzilla.gnome.org/show_bug.cgi?id=731501 + */ + if (data && self->obj->ref_count == 1) { for (tmp = data->closures; tmp != NULL; tmp = tmp->next) { PyGClosure *closure = tmp->data; @@ -1177,8 +1230,8 @@ pygobject_clear(PyGObject *self) { if (self->obj) { g_object_set_qdata_full(self->obj, pygobject_wrapper_key, NULL, NULL); - if (self->inst_dict) { - g_object_remove_toggle_ref(self->obj, pyg_toggle_notify, self); + if (pygobject_toggle_ref_is_active (self)) { + g_object_remove_toggle_ref(self->obj, pyg_toggle_notify, NULL); self->private_flags.flags &= ~PYGOBJECT_USING_TOGGLE_REF; } else { Py_BEGIN_ALLOW_THREADS; @@ -1197,23 +1250,28 @@ pygobject_free(PyObject *op) PyObject_GC_Del(op); } -gboolean +static gboolean pygobject_prepare_construct_properties(GObjectClass *class, PyObject *kwargs, - guint *n_params, GParameter **params) + guint *n_properties, const char **names[], const GValue **values) { - *n_params = 0; - *params = NULL; + *n_properties = 0; + *names = NULL; + *values = NULL; if (kwargs) { Py_ssize_t pos = 0; PyObject *key; PyObject *value; + Py_ssize_t len; - *params = g_new0(GParameter, PyDict_Size(kwargs)); + len = PyDict_Size(kwargs); + *names = g_new(const char*, len); + *values = g_new0(GValue, len); while (PyDict_Next(kwargs, &pos, &key, &value)) { GParamSpec *pspec; - GParameter *param = &(*params)[*n_params]; - const gchar *key_str = PYGLIB_PyUnicode_AsString(key); + GValue *gvalue = &(*values)[*n_properties]; + + const gchar *key_str = PyUnicode_AsUTF8 (key); pspec = g_object_class_find_property(class, key_str); if (!pspec) { @@ -1222,16 +1280,16 @@ pygobject_prepare_construct_properties(GObjectClass *class, PyObject *kwargs, G_OBJECT_CLASS_NAME(class), key_str); return FALSE; } - g_value_init(¶m->value, G_PARAM_SPEC_VALUE_TYPE(pspec)); - if (pyg_param_gvalue_from_pyobject(¶m->value, value, pspec) < 0) { + g_value_init(gvalue, G_PARAM_SPEC_VALUE_TYPE(pspec)); + if (pyg_param_gvalue_from_pyobject(gvalue, value, pspec) < 0) { PyErr_Format(PyExc_TypeError, "could not convert value for property `%s' from %s to %s", key_str, Py_TYPE(value)->tp_name, g_type_name(G_PARAM_SPEC_VALUE_TYPE(pspec))); return FALSE; } - param->name = g_strdup(key_str); - ++(*n_params); + (*names)[*n_properties] = g_strdup(key_str); + ++(*n_properties); } } return TRUE; @@ -1243,11 +1301,24 @@ static int pygobject_init(PyGObject *self, PyObject *args, PyObject *kwargs) { GType object_type; - guint n_params = 0, i; - GParameter *params = NULL; + guint n_properties = 0, i; + const GValue *values = NULL; + const char **names = NULL; GObjectClass *class; - if (!PyArg_ParseTuple(args, ":GObject.__init__", &object_type)) + /* Only do GObject creation and property setting if the GObject hasn't + * already been created. The case where self->obj already exists can occur + * when C constructors are called directly (Gtk.Button.new_with_label) + * and we are simply wrapping the result with a PyGObject. + * In these cases we want to ignore any keyword arguments passed along + * to __init__ and simply return. + * + * See: https://bugzilla.gnome.org/show_bug.cgi?id=705810 + */ + if (self->obj != NULL) + return 0; + + if (!PyArg_ParseTuple(args, ":GObject.__init__", NULL)) return -1; object_type = pyg_type_from_object((PyObject *)self); @@ -1266,18 +1337,20 @@ pygobject_init(PyGObject *self, PyObject *args, PyObject *kwargs) return -1; } - if (!pygobject_prepare_construct_properties (class, kwargs, &n_params, ¶ms)) + if (!pygobject_prepare_construct_properties (class, kwargs, &n_properties, &names, &values)) goto cleanup; - if (pygobject_constructv(self, n_params, params)) - PyErr_SetString(PyExc_RuntimeError, "could not create object"); - + if (pygobject_constructv(self, n_properties, names, values)) + PyErr_SetString(PyExc_RuntimeError, "could not create object"); + cleanup: - for (i = 0; i < n_params; i++) { - g_free((gchar *) params[i].name); - g_value_unset(¶ms[i].value); + for (i = 0; i < n_properties; i++) { + g_free(names[i]); + g_value_unset(&values[i]); } - g_free(params); + g_free(names); + g_free(values); + g_type_class_unref(class); return (self->obj) ? 0 : -1; @@ -1292,46 +1365,23 @@ pygobject_init(PyGObject *self, PyObject *args, PyObject *kwargs) } static PyObject * -pygobject_get_property(PyGObject *self, PyObject *args) +pygobject_get_property (PyGObject *self, PyObject *args) { gchar *param_name; - GParamSpec *pspec; - GValue value = { 0, }; - PyObject *ret; - if (!PyArg_ParseTuple(args, "s:GObject.get_property", ¶m_name)) - return NULL; + if (!PyArg_ParseTuple (args, "s:GObject.get_property", ¶m_name)) { + return NULL; + } CHECK_GOBJECT(self); - - pspec = g_object_class_find_property(G_OBJECT_GET_CLASS(self->obj), - param_name); - if (!pspec) { - PyErr_Format(PyExc_TypeError, - "object of type `%s' does not have property `%s'", - g_type_name(G_OBJECT_TYPE(self->obj)), param_name); - return NULL; - } - if (!(pspec->flags & G_PARAM_READABLE)) { - PyErr_Format(PyExc_TypeError, "property %s is not readable", - param_name); - return NULL; - } - g_value_init(&value, G_PARAM_SPEC_VALUE_TYPE(pspec)); - Py_BEGIN_ALLOW_THREADS; - g_object_get_property(self->obj, param_name, &value); - Py_END_ALLOW_THREADS; - ret = pyg_param_gvalue_as_pyobject(&value, TRUE, pspec); - g_value_unset(&value); - return ret; + return pygi_get_property_value_by_name (self, param_name); } static PyObject * pygobject_get_properties(PyGObject *self, PyObject *args) { - GObjectClass *class; - int len, i; + Py_ssize_t len, i; PyObject *tuple; if ((len = PyTuple_Size(args)) < 1) { @@ -1340,48 +1390,27 @@ pygobject_get_properties(PyGObject *self, PyObject *args) } tuple = PyTuple_New(len); - class = G_OBJECT_GET_CLASS(self->obj); for (i = 0; i < len; i++) { PyObject *py_property = PyTuple_GetItem(args, i); gchar *property_name; - GParamSpec *pspec; - GValue value = { 0 }; PyObject *item; - if (!PYGLIB_PyUnicode_Check(py_property)) { + if (!PyUnicode_Check (py_property)) { PyErr_SetString(PyExc_TypeError, "Expected string argument for property."); - return NULL; - } - - property_name = PYGLIB_PyUnicode_AsString(py_property); - - pspec = g_object_class_find_property(class, - property_name); - if (!pspec) { - PyErr_Format(PyExc_TypeError, - "object of type `%s' does not have property `%s'", - g_type_name(G_OBJECT_TYPE(self->obj)), property_name); - return NULL; - } - if (!(pspec->flags & G_PARAM_READABLE)) { - PyErr_Format(PyExc_TypeError, "property %s is not readable", - property_name); - return NULL; + goto fail; } - g_value_init(&value, G_PARAM_SPEC_VALUE_TYPE(pspec)); - - Py_BEGIN_ALLOW_THREADS; - g_object_get_property(self->obj, property_name, &value); - Py_END_ALLOW_THREADS; - item = pyg_value_as_pyobject(&value, TRUE); - PyTuple_SetItem(tuple, i, item); - - g_value_unset(&value); + property_name = PyUnicode_AsUTF8 (py_property); + item = pygi_get_property_value_by_name (self, property_name); + PyTuple_SetItem (tuple, i, item); } return tuple; + +fail: + Py_DECREF (tuple); + return NULL; } static PyObject * @@ -1439,7 +1468,7 @@ pygobject_set_properties(PyGObject *self, PyObject *args, PyObject *kwargs) pos = 0; while (kwargs && PyDict_Next (kwargs, &pos, &key, &value)) { - gchar *key_str = PYGLIB_PyUnicode_AsString(key); + gchar *key_str = PyUnicode_AsUTF8 (key); GParamSpec *pspec; int ret = -1; @@ -1482,10 +1511,10 @@ pygbinding_closure_invalidate(gpointer data, GClosure *closure) PyGClosure *pc = (PyGClosure *)closure; PyGILState_STATE state; - state = pyglib_gil_state_ensure(); + state = PyGILState_Ensure(); Py_XDECREF(pc->callback); Py_XDECREF(pc->extra_args); - pyglib_gil_state_release(state); + PyGILState_Release(state); pc->callback = NULL; pc->extra_args = NULL; @@ -1504,7 +1533,7 @@ pygbinding_marshal (GClosure *closure, PyObject *params, *ret; GValue *out_value; - state = pyglib_gil_state_ensure(); + state = PyGILState_Ensure(); /* construct Python tuple for the parameter values */ params = PyTuple_New(2); @@ -1539,7 +1568,7 @@ pygbinding_marshal (GClosure *closure, out: Py_DECREF(params); - pyglib_gil_state_release(state); + PyGILState_Release(state); } static GClosure * @@ -1623,14 +1652,14 @@ pygobject_bind_property(PyGObject *self, PyObject *args) 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); + PyUnicode_AsUTF8 (source_repr), source_name, + PyUnicode_AsUTF8 (target_repr), target_name); Py_DECREF(source_repr); Py_DECREF(target_repr); return NULL; } - return pygbinding_weak_ref_new(G_OBJECT (binding)); + return pygobject_new (G_OBJECT (binding)); } static PyObject * @@ -1646,12 +1675,21 @@ connect_helper(PyGObject *self, gchar *name, PyObject *callback, PyObject *extra &sigid, &detail, TRUE)) { PyObject *repr = PyObject_Repr((PyObject*)self); PyErr_Format(PyExc_TypeError, "%s: unknown signal name: %s", - PYGLIB_PyUnicode_AsString(repr), + PyUnicode_AsUTF8 (repr), name); Py_DECREF(repr); return NULL; } + if (object && !PyObject_TypeCheck (object, &PyGObject_Type)) { + if (PyErr_WarnEx (PyGIDeprecationWarning, + "Using non GObject arguments for connect_object() is deprecated, use: " + "connect_data(signal, callback, data, connect_flags=GObject.ConnectFlags.SWAPPED)", + 1)) { + return NULL; + } + } + g_signal_query (sigid, &query_info); if (!pyg_gtype_is_custom (query_info.itype)) { /* The signal is implemented by a non-Python class, probably @@ -1670,7 +1708,7 @@ connect_helper(PyGObject *self, gchar *name, PyObject *callback, PyObject *extra pygobject_watch_closure((PyObject *)self, closure); handlerid = g_signal_connect_closure_by_id(self->obj, sigid, detail, closure, after); - return PyLong_FromUnsignedLong(handlerid); + return pygi_gulong_to_py (handlerid); } static PyObject * @@ -1678,7 +1716,7 @@ pygobject_connect(PyGObject *self, PyObject *args) { PyObject *first, *callback, *extra_args, *ret; gchar *name; - guint len; + Py_ssize_t len; len = PyTuple_Size(args); if (len < 2) { @@ -1845,13 +1883,13 @@ pygobject_emit(PyGObject *self, PyObject *args) &signal_id, &detail, TRUE)) { repr = PyObject_Repr((PyObject*)self); PyErr_Format(PyExc_TypeError, "%s: unknown signal name: %s", - PYGLIB_PyUnicode_AsString(repr), + PyUnicode_AsUTF8 (repr), name); Py_DECREF(repr); return NULL; } g_signal_query(signal_id, &query); - if (len != query.n_params + 1) { + if ((gsize)len != query.n_params + 1) { gchar buf[128]; g_snprintf(buf, sizeof(buf), @@ -1890,15 +1928,26 @@ pygobject_emit(PyGObject *self, PyObject *args) if (query.return_type != G_TYPE_NONE) g_value_init(&ret, query.return_type & ~G_SIGNAL_TYPE_STATIC_SCOPE); + Py_BEGIN_ALLOW_THREADS; g_signal_emitv(params, signal_id, detail, &ret); + Py_END_ALLOW_THREADS; for (i = 0; i < query.n_params + 1; i++) g_value_unset(¶ms[i]); g_free(params); if ((query.return_type & ~G_SIGNAL_TYPE_STATIC_SCOPE) != G_TYPE_NONE) { + gboolean was_floating = FALSE; + + if (G_VALUE_HOLDS_OBJECT (&ret)) { + GObject *obj = g_value_get_object (&ret); + if (obj != NULL && G_IS_OBJECT(obj)) { + was_floating = g_object_is_floating (obj); + } + } py_ret = pyg_value_as_pyobject(&ret, TRUE); - g_value_unset(&ret); + if (!was_floating) + g_value_unset(&ret); } else { Py_INCREF(Py_None); py_ret = Py_None; @@ -1936,7 +1985,7 @@ pygobject_chain_from_overridden(PyGObject *self, PyObject *args) return NULL; } g_signal_query(signal_id, &query); - if (len != query.n_params) { + if (len < 0 || (gsize)len != query.n_params) { gchar buf[128]; g_snprintf(buf, sizeof(buf), @@ -1992,7 +2041,7 @@ pygobject_chain_from_overridden(PyGObject *self, PyObject *args) static PyObject * pygobject_weak_ref(PyGObject *self, PyObject *args) { - int len; + Py_ssize_t len; PyObject *callback = NULL, *user_data = NULL; PyObject *retval; @@ -2047,7 +2096,7 @@ pygobject_disconnect_by_func(PyGObject *self, PyObject *args) if (!closure) { repr = PyObject_Repr((PyObject*)pyfunc); PyErr_Format(PyExc_TypeError, "nothing connected to %s", - PYGLIB_PyUnicode_AsString(repr)); + PyUnicode_AsUTF8 (repr)); Py_DECREF(repr); return NULL; } @@ -2057,7 +2106,7 @@ pygobject_disconnect_by_func(PyGObject *self, PyObject *args) 0, 0, closure, NULL, NULL); - return PYGLIB_PyLong_FromLong(retval); + return pygi_guint_to_py (retval); } static PyObject * @@ -2081,7 +2130,7 @@ pygobject_handler_block_by_func(PyGObject *self, PyObject *args) if (!closure) { repr = PyObject_Repr((PyObject*)pyfunc); PyErr_Format(PyExc_TypeError, "nothing connected to %s", - PYGLIB_PyUnicode_AsString(repr)); + PyUnicode_AsUTF8 (repr)); Py_DECREF(repr); return NULL; } @@ -2091,7 +2140,7 @@ pygobject_handler_block_by_func(PyGObject *self, PyObject *args) 0, 0, closure, NULL, NULL); - return PYGLIB_PyLong_FromLong(retval); + return pygi_guint_to_py (retval); } static PyObject * @@ -2115,7 +2164,7 @@ pygobject_handler_unblock_by_func(PyGObject *self, PyObject *args) if (!closure) { repr = PyObject_Repr((PyObject*)pyfunc); PyErr_Format(PyExc_TypeError, "nothing connected to %s", - PYGLIB_PyUnicode_AsString(repr)); + PyUnicode_AsUTF8 (repr)); Py_DECREF(repr); return NULL; } @@ -2125,7 +2174,7 @@ pygobject_handler_unblock_by_func(PyGObject *self, PyObject *args) 0, 0, closure, NULL, NULL); - return PYGLIB_PyLong_FromLong(retval); + return pygi_guint_to_py (retval); } @@ -2150,20 +2199,18 @@ static PyMethodDef pygobject_methods[] = { { NULL, NULL, 0 } }; - +#ifdef PYGI_OBJECT_USE_CUSTOM_DICT static PyObject * pygobject_get_dict(PyGObject *self, void *closure) { if (self->inst_dict == NULL) { - self->inst_dict = PyDict_New(); - if (self->inst_dict == NULL) - return NULL; - if (G_LIKELY(self->obj)) - pygobject_switch_to_toggle_ref(self); + self->inst_dict = PyDict_New(); + pygobject_toggle_ref_ensure (self); } Py_INCREF(self->inst_dict); return self->inst_dict; } +#endif static PyObject * pygobject_get_refcount(PyGObject *self, void *closure) @@ -2172,32 +2219,28 @@ pygobject_get_refcount(PyGObject *self, void *closure) PyErr_Format(PyExc_TypeError, "GObject instance is not yet created"); return NULL; } - return PYGLIB_PyLong_FromLong(self->obj->ref_count); + return pygi_guint_to_py (self->obj->ref_count); } static PyObject * pygobject_get_pointer(PyGObject *self, void *closure) { - return PYGLIB_CPointer_WrapPointer (self->obj, NULL); + return PyCapsule_New (self->obj, NULL, NULL); } static int pygobject_setattro(PyObject *self, PyObject *name, PyObject *value) { int res; - PyGObject *gself = (PyGObject *) self; - PyObject *inst_dict_before = gself->inst_dict; - /* call parent type's setattro */ res = PyGObject_Type.tp_base->tp_setattro(self, name, value); - if (inst_dict_before == NULL && gself->inst_dict != NULL) { - if (G_LIKELY(gself->obj)) - pygobject_switch_to_toggle_ref(gself); - } + pygobject_toggle_ref_ensure ((PyGObject *) self); return res; } static PyGetSetDef pygobject_getsets[] = { +#ifdef PYGI_OBJECT_USE_CUSTOM_DICT { "__dict__", (getter)pygobject_get_dict, (setter)0 }, +#endif { "__grefcount__", (getter)pygobject_get_refcount, (setter)0, }, { "__gpointer__", (getter)pygobject_get_pointer, (setter)0, }, { NULL, 0, 0 } @@ -2215,7 +2258,7 @@ typedef struct { gboolean have_floating_ref; } PyGObjectWeakRef; -PYGLIB_DEFINE_TYPE("gi._gobject.GObjectWeakRef", PyGObjectWeakRef_Type, PyGObjectWeakRef); +PYGI_DEFINE_TYPE("gi._gi.GObjectWeakRef", PyGObjectWeakRef_Type, PyGObjectWeakRef); static int pygobject_weak_ref_traverse(PyGObjectWeakRef *self, visitproc visit, void *arg) @@ -2233,7 +2276,7 @@ pygobject_weak_ref_notify(PyGObjectWeakRef *self, GObject *dummy) self->obj = NULL; if (self->callback) { PyObject *retval; - PyGILState_STATE state = pyglib_gil_state_ensure(); + PyGILState_STATE state = PyGILState_Ensure(); retval = PyObject_Call(self->callback, self->user_data, NULL); if (retval) { if (retval != Py_None) @@ -2251,7 +2294,7 @@ pygobject_weak_ref_notify(PyGObjectWeakRef *self, GObject *dummy) self->have_floating_ref = FALSE; Py_DECREF((PyObject *) self); } - pyglib_gil_state_release(state); + PyGILState_Release(state); } } @@ -2334,63 +2377,15 @@ pygobject_weak_ref_call(PyGObjectWeakRef *self, PyObject *args, PyObject *kw) } } - -/* -------------- 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(); + state = PyGILState_Ensure(); Py_INCREF(object); - pyglib_gil_state_release(state); + PyGILState_Release(state); return object; } @@ -2400,13 +2395,16 @@ pyobject_free(gpointer boxed) PyObject *object = boxed; PyGILState_STATE state; - state = pyglib_gil_state_ensure(); + state = PyGILState_Ensure(); Py_DECREF(object); - pyglib_gil_state_release(state); + PyGILState_Release(state); } -void -pygobject_object_register_types(PyObject *d) +/** + * Returns 0 on success, or -1 and sets an exception. + */ +int +pyi_object_register_types(PyObject *d) { PyObject *o, *descr; @@ -2435,7 +2433,9 @@ pygobject_object_register_types(PyObject *d) PyGObject_Type.tp_weaklistoffset = offsetof(PyGObject, weakreflist); PyGObject_Type.tp_methods = pygobject_methods; PyGObject_Type.tp_getset = pygobject_getsets; +#ifdef PYGI_OBJECT_USE_CUSTOM_DICT PyGObject_Type.tp_dictoffset = offsetof(PyGObject, inst_dict); +#endif PyGObject_Type.tp_init = (initproc)pygobject_init; PyGObject_Type.tp_free = (freefunc)pygobject_free; PyGObject_Type.tp_alloc = PyType_GenericAlloc; @@ -2455,18 +2455,19 @@ pygobject_object_register_types(PyObject *d) "Python attributes."; PyGProps_Type.tp_traverse = (traverseproc)pygobject_props_traverse; PyGProps_Type.tp_iter = (getiterfunc)pygobject_props_get_iter; + PyGProps_Type.tp_methods = pygobject_props_methods; if (PyType_Ready(&PyGProps_Type) < 0) - return; + return -1; /* GPropsDescr */ PyGPropsDescr_Type.tp_flags = Py_TPFLAGS_DEFAULT; PyGPropsDescr_Type.tp_descr_get = pyg_props_descr_descr_get; if (PyType_Ready(&PyGPropsDescr_Type) < 0) - return; + return -1; descr = PyObject_New(PyObject, &PyGPropsDescr_Type); PyDict_SetItemString(PyGObject_Type.tp_dict, "props", descr); PyDict_SetItemString(PyGObject_Type.tp_dict, "__module__", - o=PYGLIB_PyUnicode_FromString("gi._gobject._gobject")); + o=PyUnicode_FromString ("gi._gi")); Py_DECREF(o); /* GPropsIter */ @@ -2475,7 +2476,7 @@ pygobject_object_register_types(PyObject *d) PyGPropsIter_Type.tp_doc = "GObject properties iterator"; PyGPropsIter_Type.tp_iternext = (iternextfunc)pygobject_props_iter_next; if (PyType_Ready(&PyGPropsIter_Type) < 0) - return; + return -1; PyGObjectWeakRef_Type.tp_dealloc = (destructor)pygobject_weak_ref_dealloc; PyGObjectWeakRef_Type.tp_call = (ternaryfunc)pygobject_weak_ref_call; @@ -2485,14 +2486,66 @@ pygobject_object_register_types(PyObject *d) PyGObjectWeakRef_Type.tp_clear = (inquiry)pygobject_weak_ref_clear; PyGObjectWeakRef_Type.tp_methods = pygobject_weak_ref_methods; if (PyType_Ready(&PyGObjectWeakRef_Type) < 0) - return; + return -1; 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); + return 0; +} + +PyObject * +pyg_object_new (PyGObject *self, PyObject *args, PyObject *kwargs) +{ + PyObject *pytype; + GType type; + GObject *obj = NULL; + GObjectClass *class; + guint n_properties = 0, i; + const GValue *values = NULL; + const char **names = NULL; + + if (!PyArg_ParseTuple (args, "O:gobject.new", &pytype)) { + return NULL; + } + + if ((type = pyg_type_from_object (pytype)) == 0) + return NULL; + + if (G_TYPE_IS_ABSTRACT(type)) { + PyErr_Format(PyExc_TypeError, "cannot create instance of abstract " + "(non-instantiable) type `%s'", g_type_name(type)); + return NULL; + } + + if ((class = g_type_class_ref (type)) == NULL) { + PyErr_SetString(PyExc_TypeError, + "could not get a reference to type class"); + return NULL; + } + + if (!pygobject_prepare_construct_properties (class, kwargs, &n_properties, &names, &values)) + goto cleanup; + + obj = pygobject_object_new_with_properties(type, n_properties, names, values); + + if (!obj) + PyErr_SetString (PyExc_RuntimeError, "could not create object"); + + cleanup: + for (i = 0; i < n_properties; i++) { + g_free(names[i]); + g_value_unset(&values[i]); + } + g_free(names); + g_free(values); + + g_type_class_unref(class); + + if (obj) { + pygobject_sink (obj); + self = (PyGObject *) pygobject_new((GObject *)obj); + g_object_unref(obj); + } else + self = NULL; + + return (PyObject *) self; } diff --git a/gi/pygobject-object.h b/gi/pygobject-object.h new file mode 100644 index 0000000..95e95aa --- /dev/null +++ b/gi/pygobject-object.h @@ -0,0 +1,52 @@ +#ifndef _PYGOBJECT_OBJECT_H_ +#define _PYGOBJECT_OBJECT_H_ + +#include <Python.h> +#include <glib-object.h> +#include "pygobject-internal.h" + +/* Data that belongs to the GObject instance, not the Python wrapper */ +struct _PyGObjectData { + PyTypeObject *type; /* wrapper type for this instance */ + GSList *closures; +}; + +extern GType PY_TYPE_OBJECT; +extern GQuark pygobject_instance_data_key; +extern GQuark pygobject_custom_key; +extern GQuark pygobject_wrapper_key; +extern GQuark pygobject_class_key; +extern GQuark pygobject_class_init_key; + +extern PyTypeObject PyGObjectWeakRef_Type; +extern PyTypeObject PyGPropsIter_Type; +extern PyTypeObject PyGPropsDescr_Type; +extern PyTypeObject PyGProps_Type; +extern PyTypeObject PyGObject_Type; +extern PyTypeObject *PyGObject_MetaType; + +static inline PyGObjectData * +pyg_object_peek_inst_data(GObject *obj) +{ + return ((PyGObjectData *) + g_object_get_qdata(obj, pygobject_instance_data_key)); +} + +void pygobject_register_class (PyObject *dict, + const gchar *type_name, + GType gtype, PyTypeObject *type, + PyObject *bases); +void pygobject_register_wrapper (PyObject *self); +PyObject * pygobject_new (GObject *obj); +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); +int pyi_object_register_types (PyObject *d); +void pygobject_ref_float(PyGObject *self); +void pygobject_ref_sink(PyGObject *self); +PyObject * pyg_object_new (PyGObject *self, PyObject *args, PyObject *kwargs); + +GClosure * gclosure_from_pyfunc(PyGObject *object, PyObject *func); + +#endif /*_PYGOBJECT_OBJECT_H_*/ diff --git a/gi/_gobject/pygobject.h b/gi/pygobject.h index 76b8b11..a45a4b0 100644 --- a/gi/_gobject/pygobject.h +++ b/gi/pygobject.h @@ -25,7 +25,7 @@ struct _PyGClosure { typedef enum { PYGOBJECT_USING_TOGGLE_REF = 1 << 0, PYGOBJECT_IS_FLOATING_REF = 1 << 1, - PYGOBJECT_GOBJECT_WAS_FLOATING = 1 << 2, + PYGOBJECT_GOBJECT_WAS_FLOATING = 1 << 2 } PyGObjectFlags; /* closures is just an alias for what is found in the @@ -57,6 +57,8 @@ typedef struct { } PyGBoxed; #define pyg_boxed_get(v,t) ((t *)((PyGBoxed *)(v))->boxed) +#define pyg_boxed_get_ptr(v) (((PyGBoxed *)(v))->boxed) +#define pyg_boxed_set_ptr(v,p) (((PyGBoxed *)(v))->boxed = (gpointer)p) #define pyg_boxed_check(v,typecode) (PyObject_TypeCheck(v, &PyGBoxed_Type) && ((PyGBoxed *)(v))->gtype == typecode) typedef struct { @@ -66,6 +68,8 @@ typedef struct { } PyGPointer; #define pyg_pointer_get(v,t) ((t *)((PyGPointer *)(v))->pointer) +#define pyg_pointer_get_ptr(v) (((PyGPointer *)(v))->pointer) +#define pyg_pointer_set_ptr(v,p) (((PyGPointer *)(v))->pointer = (gpointer)p) #define pyg_pointer_check(v,typecode) (PyObject_TypeCheck(v, &PyGPointer_Type) && ((PyGPointer *)(v))->gtype == typecode) typedef void (*PyGFatalExceptionFunc) (void); @@ -76,8 +80,13 @@ typedef struct { GParamSpec *pspec; } PyGParamSpec; -#define PyGParamSpec_Get(v) (((PyGParamSpec *)v)->pspec) -#define PyGParamSpec_Check(v) (PyObject_TypeCheck(v, &PyGParamSpec_Type)) +#define pyg_param_spec_get(v) (((PyGParamSpec *)v)->pspec) +#define pyg_param_spec_set(v,p) (((PyGParamSpec *)v)->pspec = (GParamSpec*)p) +#define pyg_param_spec_check(v) (PyObject_TypeCheck(v, &PyGParamSpec_Type)) + +/* Deprecated in favor of lower case with underscore macros above. */ +#define PyGParamSpec_Get pyg_param_spec_get +#define PyGParamSpec_Check pyg_param_spec_check typedef int (*PyGClassInitFunc) (gpointer gclass, PyTypeObject *pyclass); typedef PyTypeObject * (*PyGTypeRegistrationFunction) (const gchar *name, @@ -145,12 +154,14 @@ struct _PyGObject_Functions { PyObject *(* paramspec_new)(GParamSpec *spec); GParamSpec *(*paramspec_get)(PyObject *tuple); int (*pyobj_to_unichar_conv)(PyObject *pyobj, void* ptr); +G_GNUC_BEGIN_IGNORE_DEPRECATIONS gboolean (*parse_constructor_args)(GType obj_type, char **arg_names, char **prop_names, GParameter *params, guint *nparams, PyObject **py_args); +G_GNUC_END_IGNORE_DEPRECATIONS PyObject *(* param_gvalue_as_pyobject) (const GValue* gvalue, gboolean copy_boxed, const GParamSpec* pspec); @@ -199,21 +210,12 @@ struct _PyGObject_Functions { }; -#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_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 #define pyg_enable_threads() #define pyg_set_thread_block_funcs(a, b) #define pyg_block_threads() @@ -343,11 +345,13 @@ pygobject_init(int req_major, int req_minor, int req_micro) } cobject = PyObject_GetAttrString(gobject, "_PyGObject_API"); - if (cobject && PyCapsule_CheckExact(cobject)) + if (cobject && PyCapsule_CheckExact(cobject)) { _PyGObject_API = (struct _PyGObject_Functions *) PyCapsule_GetPointer(cobject, "gobject._PyGObject_API"); - else { + Py_DECREF (cobject); + } else { PyErr_SetString(PyExc_ImportError, "could not import gobject (could not find _PyGObject_API object)"); + Py_XDECREF (cobject); Py_DECREF(gobject); return NULL; } diff --git a/gi/_glib/pygoptioncontext.c b/gi/pygoptioncontext.c index 8ecbff8..c2f402c 100644 --- a/gi/_glib/pygoptioncontext.c +++ b/gi/pygoptioncontext.c @@ -15,20 +15,52 @@ * 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 + * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif +#include <config.h> -#include <pyglib.h> -#include "pyglib-private.h" #include "pygoptioncontext.h" +#include "pygi-error.h" +#include "pygi-util.h" +#include "pygi-basictype.h" -PYGLIB_DEFINE_TYPE("gi._glib.OptionContext", PyGOptionContext_Type, PyGOptionContext) +PYGI_DEFINE_TYPE("gi._gi.OptionContext", PyGOptionContext_Type, PyGOptionContext) + +/** + * pyg_option_group_transfer_group: + * @group: a GOptionGroup wrapper + * + * This is used to transfer the GOptionGroup to a GOptionContext. After this + * is called, the calle must handle the release of the GOptionGroup. + * + * When #NULL is returned, the GOptionGroup was already transfered. + * + * Returns: Either #NULL or the wrapped GOptionGroup. + */ +static GOptionGroup * +pyglib_option_group_transfer_group(PyObject *obj) +{ + PyGOptionGroup *self = (PyGOptionGroup*)obj; + + if (self->is_in_context) + return NULL; + + self->is_in_context = TRUE; + + /* Here we increase the reference count of the PyGOptionGroup, because now + * the GOptionContext holds an reference to us (it is the userdata passed + * to g_option_group_new(). + * + * The GOptionGroup is freed with the GOptionContext. + * + * We set it here because if we would do this in the init method we would + * hold two references and the PyGOptionGroup would never be freed. + */ + Py_INCREF(self); + + return self->group; +} /** * pyg_option_context_new: @@ -58,7 +90,7 @@ pyg_option_context_init(PyGOptionContext *self, { char *parameter_string; - if (!PyArg_ParseTuple(args, "s:gi._glib.GOptionContext.__init__", + if (!PyArg_ParseTuple(args, "s:gi._gi.GOptionContext.__init__", ¶meter_string)) return -1; @@ -119,7 +151,7 @@ pyg_option_context_parse(PyGOptionContext *self, for (pos = 0; pos < argv_length; pos++) { arg = PyList_GetItem(argv, pos); - argv_content[pos] = g_strdup(PYGLIB_PyUnicode_AsString(arg)); + argv_content[pos] = g_strdup(PyUnicode_AsUTF8 (arg)); if (argv_content[pos] == NULL) { g_strfreev(argv_content); @@ -129,7 +161,7 @@ pyg_option_context_parse(PyGOptionContext *self, original = g_strdupv(argv_content); g_assert(argv_length <= G_MAXINT); - argv_length_int = argv_length; + argv_length_int = (gint)argv_length; Py_BEGIN_ALLOW_THREADS; result = g_option_context_parse(self->context, &argv_length_int, &argv_content, &error); @@ -140,14 +172,14 @@ pyg_option_context_parse(PyGOptionContext *self, { g_strfreev(argv_content); g_strfreev(original); - pyglib_error_check(&error); + pygi_error_check(&error); return NULL; } new_argv = PyList_New(g_strv_length(argv_content)); for (pos = 0; pos < argv_length; pos++) { - arg = PYGLIB_PyUnicode_FromString(argv_content[pos]); + arg = PyUnicode_FromString (argv_content[pos]); PyList_SetItem(new_argv, pos, arg); } @@ -178,7 +210,7 @@ pyg_option_context_set_help_enabled(PyGOptionContext *self, static PyObject * pyg_option_context_get_help_enabled(PyGOptionContext *self) { - return PyBool_FromLong(g_option_context_get_help_enabled(self->context)); + return pygi_gboolean_to_py (g_option_context_get_help_enabled(self->context)); } static PyObject * @@ -205,7 +237,7 @@ pyg_option_context_set_ignore_unknown_options(PyGOptionContext *self, static PyObject * pyg_option_context_get_ignore_unknown_options(PyGOptionContext *self) { - return PyBool_FromLong( + return pygi_gboolean_to_py ( g_option_context_get_ignore_unknown_options(self->context)); } @@ -297,9 +329,9 @@ static PyObject* pyg_option_context_richcompare(PyObject *self, PyObject *other, int op) { if (Py_TYPE(self) == Py_TYPE(other) && Py_TYPE(self) == &PyGOptionContext_Type) - return _pyglib_generic_ptr_richcompare(((PyGOptionContext*)self)->context, - ((PyGOptionContext*)other)->context, - op); + return pyg_ptr_richcompare(((PyGOptionContext*)self)->context, + ((PyGOptionContext*)other)->context, + op); else { Py_INCREF(Py_NotImplemented); return Py_NotImplemented; @@ -309,7 +341,7 @@ pyg_option_context_richcompare(PyObject *self, PyObject *other, int op) static PyObject * pyg_option_get_context(PyGOptionContext *self) { - return PYGLIB_CPointer_WrapPointer(self->context, "goption.context"); + return PyCapsule_New (self->context, "goption.context", NULL); } static PyMethodDef pyg_option_context_methods[] = { @@ -325,13 +357,23 @@ static PyMethodDef pyg_option_context_methods[] = { { NULL, NULL, 0 }, }; -void -pyglib_option_context_register_types(PyObject *d) +/** + * Returns 0 on success, or -1 and sets an exception. + */ +int +pygi_option_context_register_types(PyObject *d) { PyGOptionContext_Type.tp_dealloc = (destructor)pyg_option_context_dealloc; PyGOptionContext_Type.tp_richcompare = pyg_option_context_richcompare; PyGOptionContext_Type.tp_flags = Py_TPFLAGS_DEFAULT; PyGOptionContext_Type.tp_methods = pyg_option_context_methods; PyGOptionContext_Type.tp_init = (initproc)pyg_option_context_init; - PYGLIB_REGISTER_TYPE(d, PyGOptionContext_Type, "OptionContext"); + PyGOptionContext_Type.tp_alloc = PyType_GenericAlloc; + PyGOptionContext_Type.tp_new = PyType_GenericNew; + if (PyType_Ready(&PyGOptionContext_Type)) + return -1; + + PyDict_SetItemString(d, "OptionContext", (PyObject *)&PyGOptionContext_Type); + + return 0; } diff --git a/gi/_glib/pygoptioncontext.h b/gi/pygoptioncontext.h index efe5ffa..4dea56d 100644 --- a/gi/_glib/pygoptioncontext.h +++ b/gi/pygoptioncontext.h @@ -14,9 +14,7 @@ * 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 + * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ #ifndef __PYG_OPTIONCONTEXT_H__ @@ -34,6 +32,6 @@ typedef struct { PyObject* pyg_option_context_new(GOptionContext *context); -void pyglib_option_context_register_types(PyObject *d); +int pygi_option_context_register_types(PyObject *d); #endif /* __PYG_OPTIONCONTEXT_H__ */ diff --git a/gi/_glib/pygoptiongroup.c b/gi/pygoptiongroup.c index 2990342..9d1bdc1 100644 --- a/gi/_glib/pygoptiongroup.c +++ b/gi/pygoptiongroup.c @@ -15,20 +15,16 @@ * 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 + * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif +#include <config.h> -#include <pyglib.h> -#include "pyglib-private.h" #include "pygoptiongroup.h" +#include "pygi-error.h" +#include "pygi-util.h" -PYGLIB_DEFINE_TYPE("gi._glib.OptionGroup", PyGOptionGroup_Type, PyGOptionGroup) +PYGI_DEFINE_TYPE("gi._gi.OptionGroup", PyGOptionGroup_Type, PyGOptionGroup) /** * pyg_option_group_new: @@ -62,7 +58,7 @@ check_if_owned(PyGOptionGroup *self) if (self->other_owner) { PyErr_SetString(PyExc_ValueError, "The GOptionGroup was not created by " - "gi._glib.OptionGroup(), so operation is not possible."); + "gi._gi.OptionGroup(), so operation is not possible."); return TRUE; } return FALSE; @@ -72,7 +68,7 @@ static void destroy_g_group(PyGOptionGroup *self) { PyGILState_STATE state; - state = pyglib_gil_state_ensure(); + state = PyGILState_Ensure(); self->group = NULL; Py_CLEAR(self->callback); @@ -85,7 +81,7 @@ destroy_g_group(PyGOptionGroup *self) Py_DECREF(self); } - pyglib_gil_state_release(state); + PyGILState_Release(state); } static int @@ -119,8 +115,11 @@ pyg_option_group_dealloc(PyGOptionGroup *self) { GOptionGroup *tmp = self->group; self->group = NULL; - if (tmp) + if (tmp) { + G_GNUC_BEGIN_IGNORE_DEPRECATIONS g_option_group_free(tmp); + G_GNUC_END_IGNORE_DEPRECATIONS + } } PyObject_Del(self); @@ -136,8 +135,7 @@ arg_func(const gchar *option_name, PyGILState_STATE state; gboolean no_error; - state = pyglib_gil_state_ensure(); - + state = PyGILState_Ensure(); if (value == NULL) ret = PyObject_CallFunction(self->callback, "sOO", option_name, Py_None, self); @@ -150,9 +148,9 @@ arg_func(const gchar *option_name, Py_DECREF(ret); no_error = TRUE; } else - no_error = pyglib_gerror_exception_check(error) != -1; + no_error = pygi_gerror_exception_check(error) != -1; - pyglib_gil_state_release(state); + PyGILState_Release(state); return no_error; } @@ -271,9 +269,9 @@ pyg_option_group_richcompare(PyObject *self, PyObject *other, int op) { if (Py_TYPE(self) == Py_TYPE(other) && Py_TYPE(self) == &PyGOptionGroup_Type) { - return _pyglib_generic_ptr_richcompare(((PyGOptionGroup*)self)->group, - ((PyGOptionGroup*)other)->group, - op); + return pyg_ptr_richcompare(((PyGOptionGroup*)self)->group, + ((PyGOptionGroup*)other)->group, + op); } else { Py_INCREF(Py_NotImplemented); return Py_NotImplemented; @@ -286,13 +284,24 @@ static PyMethodDef pyg_option_group_methods[] = { { NULL, NULL, 0 }, }; -void -pyglib_option_group_register_types(PyObject *d) +/** + * Returns 0 on success, or -1 and sets an exception. + */ +int +pygi_option_group_register_types(PyObject *d) { PyGOptionGroup_Type.tp_dealloc = (destructor)pyg_option_group_dealloc; PyGOptionGroup_Type.tp_richcompare = pyg_option_group_richcompare; PyGOptionGroup_Type.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE; PyGOptionGroup_Type.tp_methods = pyg_option_group_methods; PyGOptionGroup_Type.tp_init = (initproc)pyg_option_group_init; - PYGLIB_REGISTER_TYPE(d, PyGOptionGroup_Type, "OptionGroup"); + PyGOptionGroup_Type.tp_alloc = PyType_GenericAlloc; + PyGOptionGroup_Type.tp_new = PyType_GenericNew; + + if (PyType_Ready(&PyGOptionGroup_Type)) + return -1; + + PyDict_SetItemString(d, "OptionGroup", (PyObject *)&PyGOptionGroup_Type); + + return 0; } diff --git a/gi/_glib/pygoptiongroup.h b/gi/pygoptiongroup.h index 872b9c6..65d08e4 100644 --- a/gi/_glib/pygoptiongroup.h +++ b/gi/pygoptiongroup.h @@ -14,14 +14,15 @@ * 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 + * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ #ifndef __PYG_OPTIONGROUP_H__ #define __PYG_OPTIONGROUP_H__ +#include <Python.h> +#include <glib.h> + extern PyTypeObject PyGOptionGroup_Type; typedef struct { @@ -35,7 +36,7 @@ typedef struct { PyObject* pyg_option_group_new(GOptionGroup *group); -void pyglib_option_group_register_types(PyObject *d); +int pygi_option_group_register_types(PyObject *d); #endif /* __PYG_OPTIONGROUP_H__ */ diff --git a/gi/pygparamspec.c b/gi/pygparamspec.c new file mode 100644 index 0000000..e49bd36 --- /dev/null +++ b/gi/pygparamspec.c @@ -0,0 +1,423 @@ +/* -*- Mode: C; c-basic-offset: 4 -*- + * pygtk- Python bindings for the GTK toolkit. + * Copyright (C) 1998-2003 James Henstridge + * Copyright (C) 2004 Johan Dahlin + * + * pygenum.c: GEnum and GFlag wrappers + * + * 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, see <http://www.gnu.org/licenses/>. + */ + +#include <config.h> + +#include <Python.h> +#include <glib-object.h> + +#include "pygenum.h" +#include "pygflags.h" +#include "pygi-type.h" +#include "pygparamspec.h" +#include "pygi-util.h" +#include "pygi-basictype.h" + +PYGI_DEFINE_TYPE("gobject.GParamSpec", PyGParamSpec_Type, PyGParamSpec); + +static PyObject* +pyg_param_spec_richcompare(PyObject *self, PyObject *other, int op) +{ + if (Py_TYPE(self) == Py_TYPE(other) && Py_TYPE(self) == &PyGParamSpec_Type) + return pyg_ptr_richcompare (pyg_param_spec_get (self), + pyg_param_spec_get (other), + op); + else { + Py_INCREF(Py_NotImplemented); + return Py_NotImplemented; + } +} + +static Py_hash_t +pyg_param_spec_hash(PyGParamSpec *self) +{ + return (Py_hash_t)(gintptr)(pyg_param_spec_get (self)); +} + +static PyObject * +pyg_param_spec_repr(PyGParamSpec *self) +{ + char buf[80]; + + g_snprintf(buf, sizeof(buf), "<%s '%s'>", + G_PARAM_SPEC_TYPE_NAME (pyg_param_spec_get (self)), + g_param_spec_get_name (pyg_param_spec_get (self))); + return PyUnicode_FromString (buf); +} + +static void +pyg_param_spec_dealloc(PyGParamSpec *self) +{ + g_param_spec_unref (pyg_param_spec_get (self)); + PyObject_DEL(self); +} + + +static PyObject * +pygenum_from_pspec(GParamSpec *pspec) +{ + PyObject *pyclass; + GParamSpecEnum *enum_pspec; + GType enum_type; + + enum_pspec = G_PARAM_SPEC_ENUM(pspec); + enum_type = G_ENUM_CLASS_TYPE(enum_pspec->enum_class); + pyclass = (PyObject*)g_type_get_qdata(enum_type, pygenum_class_key); + if (pyclass == NULL) { + pyclass = pyg_enum_add(NULL, g_type_name(enum_type), NULL, enum_type); + if (pyclass == NULL) + pyclass = Py_None; + } + + Py_INCREF(pyclass); + return pyclass; +} + +static PyObject * +pygflags_from_pspec(GParamSpec *pspec) +{ + PyObject *pyclass; + GParamSpecFlags *flag_pspec; + GType flag_type; + + flag_pspec = G_PARAM_SPEC_FLAGS(pspec); + flag_type = G_FLAGS_CLASS_TYPE(flag_pspec->flags_class); + pyclass = (PyObject*)g_type_get_qdata(flag_type, pygflags_class_key); + if (pyclass == NULL) { + pyclass = pyg_flags_add(NULL, g_type_name(flag_type), NULL, flag_type); + if (pyclass == NULL) + pyclass = Py_None; + } + Py_INCREF(pyclass); + return pyclass; +} + +static PyObject * +pyg_param_spec_getattr(PyGParamSpec *self, const gchar *attr) +{ + GParamSpec *pspec; + + pspec = pyg_param_spec_get (self); + + /* common attributes */ + if (!strcmp(attr, "__gtype__")) { + return pyg_type_wrapper_new(G_PARAM_SPEC_TYPE(pspec)); + } else if (!strcmp(attr, "name")) { + return Py_BuildValue("s", g_param_spec_get_name(pspec)); + } else if (!strcmp(attr, "nick")) { + return Py_BuildValue("s", g_param_spec_get_nick(pspec)); + } else if (!strcmp(attr, "blurb") || !strcmp(attr, "__doc__")) { + return Py_BuildValue("s", g_param_spec_get_blurb(pspec)); + } else if (!strcmp(attr, "flags")) { + return pygi_guint_to_py (pspec->flags); + } else if (!strcmp(attr, "value_type")) { + return pyg_type_wrapper_new(pspec->value_type); + } else if (!strcmp(attr, "owner_type")) { + return pyg_type_wrapper_new(pspec->owner_type); + } + + if (G_IS_PARAM_SPEC_CHAR(pspec)) { + if (!strcmp(attr, "default_value")) { + return PyUnicode_FromFormat( + "%c", G_PARAM_SPEC_CHAR(pspec)->default_value); + } else if (!strcmp(attr, "minimum")) { + return pygi_gint8_to_py (G_PARAM_SPEC_CHAR(pspec)->minimum); + } else if (!strcmp(attr, "maximum")) { + return pygi_gint8_to_py (G_PARAM_SPEC_CHAR(pspec)->maximum); + } + } else if (G_IS_PARAM_SPEC_UCHAR(pspec)) { + if (!strcmp(attr, "default_value")) { + return PyUnicode_FromFormat( + "%c", G_PARAM_SPEC_UCHAR(pspec)->default_value); + } else if (!strcmp(attr, "minimum")) { + return pygi_guint8_to_py (G_PARAM_SPEC_UCHAR(pspec)->minimum); + } else if (!strcmp(attr, "maximum")) { + return pygi_guint8_to_py (G_PARAM_SPEC_UCHAR(pspec)->maximum); + } + } else if (G_IS_PARAM_SPEC_BOOLEAN(pspec)) { + if (!strcmp(attr, "default_value")) { + return pygi_gboolean_to_py (G_PARAM_SPEC_BOOLEAN(pspec)->default_value); + } + } else if (G_IS_PARAM_SPEC_INT(pspec)) { + if (!strcmp(attr, "default_value")) { + return pygi_gint_to_py (G_PARAM_SPEC_INT(pspec)->default_value); + } else if (!strcmp(attr, "minimum")) { + return pygi_gint_to_py (G_PARAM_SPEC_INT(pspec)->minimum); + } else if (!strcmp(attr, "maximum")) { + return pygi_gint_to_py (G_PARAM_SPEC_INT(pspec)->maximum); + } + } else if (G_IS_PARAM_SPEC_UINT(pspec)) { + if (!strcmp(attr, "default_value")) { + return pygi_guint_to_py (G_PARAM_SPEC_UINT(pspec)->default_value); + } else if (!strcmp(attr, "minimum")) { + return pygi_guint_to_py (G_PARAM_SPEC_UINT(pspec)->minimum); + } else if (!strcmp(attr, "maximum")) { + return pygi_guint_to_py (G_PARAM_SPEC_UINT(pspec)->maximum); + } + } else if (G_IS_PARAM_SPEC_LONG(pspec)) { + if (!strcmp(attr, "default_value")) { + return pygi_glong_to_py (G_PARAM_SPEC_LONG(pspec)->default_value); + } else if (!strcmp(attr, "minimum")) { + return pygi_glong_to_py (G_PARAM_SPEC_LONG(pspec)->minimum); + } else if (!strcmp(attr, "maximum")) { + return pygi_glong_to_py (G_PARAM_SPEC_LONG(pspec)->maximum); + } + } else if (G_IS_PARAM_SPEC_ULONG(pspec)) { + if (!strcmp(attr, "default_value")) { + return pygi_gulong_to_py (G_PARAM_SPEC_ULONG(pspec)->default_value); + } else if (!strcmp(attr, "minimum")) { + return pygi_gulong_to_py (G_PARAM_SPEC_ULONG(pspec)->minimum); + } else if (!strcmp(attr, "maximum")) { + return pygi_gulong_to_py (G_PARAM_SPEC_ULONG(pspec)->maximum); + } + } else if (G_IS_PARAM_SPEC_INT64(pspec)) { + if (!strcmp(attr, "default_value")) { + return pygi_gint64_to_py (G_PARAM_SPEC_INT64(pspec)->default_value); + } else if (!strcmp(attr, "minimum")) { + return pygi_gint64_to_py (G_PARAM_SPEC_INT64(pspec)->minimum); + } else if (!strcmp(attr, "maximum")) { + return pygi_gint64_to_py (G_PARAM_SPEC_INT64(pspec)->maximum); + } + } else if (G_IS_PARAM_SPEC_UINT64(pspec)) { + if (!strcmp(attr, "default_value")) { + return pygi_guint64_to_py (G_PARAM_SPEC_UINT64(pspec)->default_value); + } else if (!strcmp(attr, "minimum")) { + return pygi_guint64_to_py (G_PARAM_SPEC_UINT64(pspec)->minimum); + } else if (!strcmp(attr, "maximum")) { + return pygi_guint64_to_py (G_PARAM_SPEC_UINT64(pspec)->maximum); + } + } else if (G_IS_PARAM_SPEC_UNICHAR(pspec)) { + if (!strcmp(attr, "default_value")) { + return PyUnicode_FromFormat( + "%c", G_PARAM_SPEC_UNICHAR(pspec)->default_value); + } + } else if (G_IS_PARAM_SPEC_ENUM(pspec)) { + if (!strcmp(attr, "default_value")) { + return pyg_enum_from_gtype( + pspec->value_type, G_PARAM_SPEC_ENUM(pspec)->default_value); + } else if (!strcmp(attr, "enum_class")) { + return pygenum_from_pspec(pspec); + } + } else if (G_IS_PARAM_SPEC_FLAGS(pspec)) { + if (!strcmp(attr, "default_value")) { + return pyg_flags_from_gtype( + pspec->value_type, G_PARAM_SPEC_FLAGS(pspec)->default_value); + } else if (!strcmp(attr, "flags_class")) { + return pygflags_from_pspec(pspec); + } + } else if (G_IS_PARAM_SPEC_FLOAT(pspec)) { + if (!strcmp(attr, "default_value")) { + return pygi_gfloat_to_py (G_PARAM_SPEC_FLOAT(pspec)->default_value); + } else if (!strcmp(attr, "minimum")) { + return pygi_gfloat_to_py (G_PARAM_SPEC_FLOAT(pspec)->minimum); + } else if (!strcmp(attr, "maximum")) { + return pygi_gfloat_to_py (G_PARAM_SPEC_FLOAT(pspec)->maximum); + } else if (!strcmp(attr, "epsilon")) { + return pygi_gfloat_to_py (G_PARAM_SPEC_FLOAT(pspec)->epsilon); + } + } else if (G_IS_PARAM_SPEC_DOUBLE(pspec)) { + if (!strcmp(attr, "default_value")) { + return pygi_gdouble_to_py ( + G_PARAM_SPEC_DOUBLE(pspec)->default_value); + } else if (!strcmp(attr, "minimum")) { + return pygi_gdouble_to_py (G_PARAM_SPEC_DOUBLE(pspec)->minimum); + } else if (!strcmp(attr, "maximum")) { + return pygi_gdouble_to_py (G_PARAM_SPEC_DOUBLE(pspec)->maximum); + } else if (!strcmp(attr, "epsilon")) { + return pygi_gdouble_to_py (G_PARAM_SPEC_DOUBLE(pspec)->epsilon); + } + } else if (G_IS_PARAM_SPEC_STRING(pspec)) { + if (!strcmp(attr, "default_value")) { + return Py_BuildValue( + "s", G_PARAM_SPEC_STRING(pspec)->default_value); + } else if (!strcmp(attr, "cset_first")) { + return Py_BuildValue( + "s", G_PARAM_SPEC_STRING(pspec)->cset_first); + } else if (!strcmp(attr, "cset_nth")) { + return Py_BuildValue( + "s", G_PARAM_SPEC_STRING(pspec)->cset_nth); + } else if (!strcmp(attr, "substitutor")) { + return Py_BuildValue( + "c", G_PARAM_SPEC_STRING(pspec)->substitutor); + } else if (!strcmp(attr, "null_fold_if_empty")) { + return pygi_gboolean_to_py ( + G_PARAM_SPEC_STRING(pspec)->null_fold_if_empty); + } else if (!strcmp(attr, "ensure_non_null")) { + return pygi_gboolean_to_py ( + G_PARAM_SPEC_STRING(pspec)->ensure_non_null); + } + } else { + /* This is actually not what's exported by GObjects paramspecs, + * But we exported this in earlier versions, so it's better to keep it here + * compatibility. But don't return it in __dir__, to "hide" it. + */ + if (!strcmp(attr, "default_value")) { + /* XXX: Raise deprecation warning */ + Py_INCREF(Py_None); + return Py_None; + } + } + + PyErr_SetString(PyExc_AttributeError, attr); + return NULL; +} + + +static PyObject * +pyg_param_spec_dir(PyGParamSpec *self, PyObject *dummy) +{ + GParamSpec *pspec = pyg_param_spec_get (self); + + if (G_IS_PARAM_SPEC_CHAR(pspec)) { + return Py_BuildValue("[sssssssssss]", "__doc__", "__gtype__", + "blurb", "default_value", "flags", + "maximum", "minimum", "name", "nick", + "owner_type", "value_type"); + } else if (G_IS_PARAM_SPEC_UCHAR(pspec)) { + return Py_BuildValue("[sssssssssss]", "__doc__", "__gtype__", + "blurb", "default_value", + "flags", "maximum", "minimum", + "name", "nick", "owner_type", + "value_type"); + } else if (G_IS_PARAM_SPEC_BOOLEAN(pspec)) { + return Py_BuildValue("[sssssssss]", "__doc__", "__gtype__", + "blurb", "default_value", + "flags", "name", "nick", "owner_type", + "value_type"); + } else if (G_IS_PARAM_SPEC_INT(pspec)) { + return Py_BuildValue("[sssssssssss]", "__doc__", "__gtype__", + "blurb", "default_value", + "flags", "maximum", "minimum", "name", + "nick", "owner_type", "value_type"); + } else if (G_IS_PARAM_SPEC_UINT(pspec)) { + return Py_BuildValue("[sssssssssss]", "__doc__", "__gtype__", + "blurb", "default_value", + "flags", "maximum", "minimum", + "name", "nick", "owner_type", + "value_type"); + } else if (G_IS_PARAM_SPEC_LONG(pspec)) { + return Py_BuildValue("[sssssssssss]", "__doc__", "__gtype__", + "blurb", "default_value", + "flags", "maximum", "minimum", "name", + "nick", "owner_type", "value_type"); + } else if (G_IS_PARAM_SPEC_ULONG(pspec)) { + return Py_BuildValue("[sssssssssss]", "__doc__", "__gtype__", + "blurb", "default_value", + "flags", "maximum", "minimum", "name", + "nick", "owner_type", "value_type"); + } else if (G_IS_PARAM_SPEC_INT64(pspec)) { + return Py_BuildValue("[sssssssssss]", "__doc__", "__gtype__", + "blurb", "default_value", + "flags", "maximum", "minimum", "name", + "nick", "owner_type", "value_type"); + } else if (G_IS_PARAM_SPEC_UINT64(pspec)) { + return Py_BuildValue("[sssssssssss]", "__doc__", "__gtype__", + "blurb", "default_value", + "flags", "maximum", "minimum", + "name", "nick", "owner_type", + "value_type"); + } else if (G_IS_PARAM_SPEC_UNICHAR(pspec)) { + return Py_BuildValue("[sssssssss]", "__doc__", "__gtype__", + "blurb", "default_value", + "flags", "name", "nick", "owner_type", + "value_type"); + } else if (G_IS_PARAM_SPEC_ENUM(pspec)) { + return Py_BuildValue("[ssssssssss]", "__doc__", "__gtype__", + "blurb", "default_value", "enum_class", + "flags", "name", "nick", "owner_type", + "value_type"); + } else if (G_IS_PARAM_SPEC_FLAGS(pspec)) { + return Py_BuildValue("[ssssssssss]", "__doc__", "__gtype__", + "blurb", "default_value", + "flags", "flags_class", "name", "nick", + "owner_type", "value_type"); + } else if (G_IS_PARAM_SPEC_FLOAT(pspec)) { + return Py_BuildValue("[ssssssssssss]", "__doc__", "__gtype__", + "blurb", "epsilon", + "flags", "maximum", "minimum", "name", "nick", "owner_type", + "value_type", + "default_value"); + } else if (G_IS_PARAM_SPEC_DOUBLE(pspec)) { + return Py_BuildValue("[ssssssssssss]", "__doc__", "__gtype__", + "blurb", "default_value", "epsilon", + "flags", "maximum", "minimum", "name", "nick", + "owner_type", "value_type"); + } else if (G_IS_PARAM_SPEC_STRING(pspec)) { + return Py_BuildValue("[ssssssssssssss]", "__doc__", "__gtype__", + "blurb", "cset_first", "cset_nth", "default_value", + "ensure_non_null", "flags", "name", "nick", + "null_fold_if_empty", "owner_type", "substitutor", + "value_type"); + } else { + return Py_BuildValue("[ssssssss]", "__doc__", "__gtype__", "blurb", + "flags", "name", "nick", + "owner_type", "value_type"); + } +} + +static PyMethodDef pyg_param_spec_methods[] = { + { "__dir__", (PyCFunction)pyg_param_spec_dir, METH_NOARGS}, + { NULL, NULL, 0} +}; + +/** + * pyg_param_spec_new: + * @pspec: a GParamSpec. + * + * Creates a wrapper for a GParamSpec. + * + * Returns: the GParamSpec wrapper. + */ +PyObject * +pyg_param_spec_new(GParamSpec *pspec) +{ + PyGParamSpec *self; + + self = (PyGParamSpec *)PyObject_NEW(PyGParamSpec, + &PyGParamSpec_Type); + if (self == NULL) + return NULL; + + pyg_param_spec_set (self, g_param_spec_ref (pspec)); + return (PyObject *)self; +} + +/** + * Returns 0 on success, or -1 and sets an exception. + */ +int +pygi_paramspec_register_types(PyObject *d) +{ + Py_SET_TYPE(&PyGParamSpec_Type, &PyType_Type); + PyGParamSpec_Type.tp_dealloc = (destructor)pyg_param_spec_dealloc; + PyGParamSpec_Type.tp_getattr = (getattrfunc)pyg_param_spec_getattr; + PyGParamSpec_Type.tp_richcompare = pyg_param_spec_richcompare; + PyGParamSpec_Type.tp_flags = Py_TPFLAGS_DEFAULT; + PyGParamSpec_Type.tp_repr = (reprfunc)pyg_param_spec_repr; + PyGParamSpec_Type.tp_hash = (hashfunc)pyg_param_spec_hash; + PyGParamSpec_Type.tp_methods = pyg_param_spec_methods; + + if (PyType_Ready(&PyGParamSpec_Type)) + return -1; + PyDict_SetItemString(d, "GParamSpec", (PyObject *)&PyGParamSpec_Type); + + return 0; +} diff --git a/gi/_gobject/pygparamspec.h b/gi/pygparamspec.h index 64aab0c..8798535 100644 --- a/gi/_gobject/pygparamspec.h +++ b/gi/pygparamspec.h @@ -15,17 +15,17 @@ * 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 + * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ #ifndef __PYGOBJECT_PARAMSPEC_H__ #define __PYGOBJECT_PARAMSPEC_H__ +#include <glib-object.h> + extern PyTypeObject PyGParamSpec_Type; PyObject * pyg_param_spec_new (GParamSpec *pspec); -void pygobject_paramspec_register_types(PyObject *d); +int pygi_paramspec_register_types(PyObject *d); #endif /* __PYGOBJECT_PARAMSPEC_H__ */ diff --git a/gi/_gobject/pygpointer.c b/gi/pygpointer.c index 575c751..6d6b62f 100644 --- a/gi/_gobject/pygpointer.c +++ b/gi/pygpointer.c @@ -15,25 +15,22 @@ * 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 + * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ -#ifdef HAVE_CONFIG_H -# include <config.h> -#endif +#include <config.h> -#include <pyglib.h> -#include "pygobject-private.h" +#include <Python.h> +#include <glib-object.h> #include "pygpointer.h" - -#include "pygi.h" +#include "pygi-type.h" +#include "pygi-type.h" +#include "pygi-util.h" GQuark pygpointer_class_key; -PYGLIB_DEFINE_TYPE("gobject.GPointer", PyGPointer_Type, PyGPointer); +PYGI_DEFINE_TYPE("gobject.GPointer", PyGPointer_Type, PyGPointer); static void pyg_pointer_dealloc(PyGPointer *self) @@ -45,19 +42,19 @@ static PyObject* pyg_pointer_richcompare(PyObject *self, PyObject *other, int op) { if (Py_TYPE(self) == Py_TYPE(other)) - return _pyglib_generic_ptr_richcompare(((PyGPointer*)self)->pointer, - ((PyGPointer*)other)->pointer, - op); + return pyg_ptr_richcompare (pyg_pointer_get_ptr (self), + pyg_pointer_get_ptr (other), + op); else { Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } } -static long +static Py_hash_t pyg_pointer_hash(PyGPointer *self) { - return (long)self->pointer; + return (Py_hash_t)(gintptr)(pyg_pointer_get_ptr (self)); } static PyObject * @@ -65,9 +62,10 @@ pyg_pointer_repr(PyGPointer *self) { gchar buf[128]; - g_snprintf(buf, sizeof(buf), "<%s at 0x%lx>", g_type_name(self->gtype), - (long)self->pointer); - return PYGLIB_PyUnicode_FromString(buf); + g_snprintf(buf, sizeof(buf), "<%s at 0x%" G_GUINTPTR_FORMAT ">", + g_type_name(self->gtype), + (guintptr)pyg_pointer_get_ptr (self)); + return PyUnicode_FromString (buf); } static int @@ -78,7 +76,7 @@ pyg_pointer_init(PyGPointer *self, PyObject *args, PyObject *kwargs) if (!PyArg_ParseTuple(args, ":GPointer.__init__")) return -1; - self->pointer = NULL; + pyg_pointer_set_ptr (self, NULL); self->gtype = 0; g_snprintf(buf, sizeof(buf), "%s can not be constructed", @@ -116,7 +114,8 @@ pyg_register_pointer(PyObject *dict, const gchar *class_name, if (!type->tp_dealloc) type->tp_dealloc = (destructor)pyg_pointer_dealloc; - Py_TYPE(type) = &PyType_Type; + Py_SET_TYPE(type, &PyType_Type); + g_assert (Py_TYPE (&PyGPointer_Type) != NULL); type->tp_base = &PyGPointer_Type; if (PyType_Ready(type) < 0) { @@ -154,11 +153,11 @@ pyg_pointer_new(GType pointer_type, gpointer pointer) PyTypeObject *tp; g_return_val_if_fail(pointer_type != 0, NULL); - state = pyglib_gil_state_ensure(); + state = PyGILState_Ensure(); if (!pointer) { Py_INCREF(Py_None); - pyglib_gil_state_release(state); + PyGILState_Release(state); return Py_None; } @@ -171,20 +170,25 @@ pyg_pointer_new(GType pointer_type, gpointer pointer) tp = (PyTypeObject *)&PyGPointer_Type; /* fallback */ self = PyObject_NEW(PyGPointer, tp); - pyglib_gil_state_release(state); + PyGILState_Release(state); if (self == NULL) return NULL; - self->pointer = pointer; + pyg_pointer_set_ptr (self, pointer); self->gtype = pointer_type; return (PyObject *)self; } -void -pygobject_pointer_register_types(PyObject *d) +/** + * Returns 0 on success, or -1 and sets an exception. + */ +int +pygi_pointer_register_types(PyObject *d) { + PyObject *pygtype; + pygpointer_class_key = g_quark_from_static_string("PyGPointer::class"); PyGPointer_Type.tp_dealloc = (destructor)pyg_pointer_dealloc; @@ -194,5 +198,16 @@ pygobject_pointer_register_types(PyObject *d) PyGPointer_Type.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE; PyGPointer_Type.tp_init = (initproc)pyg_pointer_init; PyGPointer_Type.tp_free = (freefunc)pyg_pointer_free; - PYGOBJECT_REGISTER_GTYPE(d, PyGPointer_Type, "GPointer", G_TYPE_POINTER); + PyGPointer_Type.tp_alloc = PyType_GenericAlloc; + PyGPointer_Type.tp_new = PyType_GenericNew; + if (PyType_Ready(&PyGPointer_Type)) + return -1; + + pygtype = pyg_type_wrapper_new (G_TYPE_POINTER); + PyDict_SetItemString (PyGPointer_Type.tp_dict, "__gtype__", pygtype); + Py_DECREF (pygtype); + + PyDict_SetItemString(d, "GPointer", (PyObject *)&PyGPointer_Type); + + return 0; } diff --git a/gi/_gobject/pygpointer.h b/gi/pygpointer.h index f2923da..df2c1e0 100644 --- a/gi/_gobject/pygpointer.h +++ b/gi/pygpointer.h @@ -14,14 +14,22 @@ * 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 + * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ #ifndef __PYGOBJECT_POINTER_H__ #define __PYGOBJECT_POINTER_H__ -void pygobject_pointer_register_types(PyObject *d); +#include <Python.h> + +extern GQuark pygpointer_class_key; + +extern PyTypeObject PyGPointer_Type; + +void pyg_register_pointer (PyObject *dict, const gchar *class_name, + GType pointer_type, PyTypeObject *type); +PyObject * pyg_pointer_new (GType pointer_type, gpointer pointer); + +int pygi_pointer_register_types(PyObject *d); #endif /* __PYGOBJECT_POINTER_H__ */ diff --git a/gi/_glib/pygspawn.c b/gi/pygspawn.c index 72746b8..56ecf06 100644 --- a/gi/_glib/pygspawn.c +++ b/gi/pygspawn.c @@ -16,30 +16,38 @@ * 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 + * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ #include <Python.h> #include <glib.h> -#include "pyglib.h" -#include "pyglib-private.h" - +#include "pygi-util.h" +#include "pygi-basictype.h" #include "pygspawn.h" +#include "pygi-error.h" struct _PyGChildSetupData { PyObject *func; PyObject *data; }; -PYGLIB_DEFINE_TYPE("gi._glib.Pid", PyGPid_Type, PYGLIB_PyLongObject) +PYGI_DEFINE_TYPE("gi._gi.Pid", PyGPid_Type, PyLongObject) + +static GPid +pyg_pid_get_pid (PyObject *self) +{ +#ifdef G_OS_WIN32 + return (GPid)PyLong_AsVoidPtr (self); +#else + return (GPid)PyLong_AsLong (self); +#endif +} static PyObject * pyg_pid_close(PyObject *self, PyObject *args, PyObject *kwargs) { - g_spawn_close_pid(PYGLIB_PyLong_AsLong(self)); + g_spawn_close_pid(pyg_pid_get_pid (self)); Py_INCREF(Py_None); return Py_None; } @@ -52,22 +60,28 @@ static PyMethodDef pyg_pid_methods[] = { static void pyg_pid_free(PyObject *gpid) { - g_spawn_close_pid((GPid) PYGLIB_PyLong_AsLong(gpid)); - PYGLIB_PyLong_Type.tp_free((void *) gpid); + g_spawn_close_pid(pyg_pid_get_pid (gpid)); + PyLong_Type.tp_free((void *) gpid); } static int pyg_pid_tp_init(PyObject *self, PyObject *args, PyObject *kwargs) { - PyErr_SetString(PyExc_TypeError, "gi._glib.Pid cannot be manually instantiated"); + PyErr_SetString(PyExc_TypeError, "gi._gi.Pid cannot be manually instantiated"); return -1; } PyObject * pyg_pid_new(GPid pid) { - return PyObject_CallMethod((PyObject*)&PyGPid_Type, "__new__", "Oi", - &PyGPid_Type, pid); + PyObject *long_val; +#ifdef G_OS_WIN32 + long_val = PyLong_FromVoidPtr (pid); +#else + long_val = pygi_gint_to_py (pid); +#endif + return PyObject_CallMethod((PyObject*)&PyGPid_Type, "__new__", "ON", + &PyGPid_Type, long_val); } static void @@ -78,7 +92,7 @@ _pyg_spawn_async_callback(gpointer user_data) PyGILState_STATE gil; data = (struct _PyGChildSetupData *) user_data; - gil = pyglib_gil_state_ensure(); + gil = PyGILState_Ensure(); if (data->data) retval = PyObject_CallFunction(data->func, "O", data->data); else @@ -90,7 +104,7 @@ _pyg_spawn_async_callback(gpointer user_data) Py_DECREF(data->func); Py_XDECREF(data->data); g_slice_free(struct _PyGChildSetupData, data); - pyglib_gil_state_release(gil); + PyGILState_Release(gil); } PyObject * @@ -108,10 +122,10 @@ pyglib_spawn_async(PyObject *object, PyObject *args, PyObject *kwargs) gint *standard_input, *standard_output, *standard_error; struct _PyGChildSetupData *callback_data = NULL; GError *error = NULL; - GPid child_pid = -1; + GPid child_pid = 0; Py_ssize_t len, i; - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|OsiOOOOO:gi._glib.spawn_async", + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|OsiOOOOO:gi._gi.spawn_async", kwlist, &pyargv, &pyenvp, &working_directory, &flags, &func, &user_data, @@ -136,7 +150,7 @@ pyglib_spawn_async(PyObject *object, PyObject *args, PyObject *kwargs) /* parse argv */ if (!PySequence_Check(pyargv)) { PyErr_SetString(PyExc_TypeError, - "gi._glib.spawn_async: " + "gi._gi.spawn_async: " "first argument must be a sequence of strings"); return NULL; } @@ -144,15 +158,15 @@ pyglib_spawn_async(PyObject *object, PyObject *args, PyObject *kwargs) argv = g_new0(char *, len + 1); for (i = 0; i < len; ++i) { PyObject *tmp = PySequence_ITEM(pyargv, i); - if (tmp == NULL || !PYGLIB_PyUnicode_Check(tmp)) { + if (tmp == NULL || !PyUnicode_Check (tmp)) { PyErr_SetString(PyExc_TypeError, - "gi._glib.spawn_async: " + "gi._gi.spawn_async: " "first argument must be a sequence of strings"); g_free(argv); Py_XDECREF(tmp); return NULL; } - argv[i] = PYGLIB_PyUnicode_AsString(tmp); + argv[i] = PyUnicode_AsUTF8 (tmp); Py_DECREF(tmp); } @@ -160,7 +174,7 @@ pyglib_spawn_async(PyObject *object, PyObject *args, PyObject *kwargs) if (pyenvp) { if (!PySequence_Check(pyenvp)) { PyErr_SetString(PyExc_TypeError, - "gi._glib.spawn_async: " + "gi._gi.spawn_async: " "second argument must be a sequence of strings"); g_free(argv); return NULL; @@ -169,16 +183,16 @@ pyglib_spawn_async(PyObject *object, PyObject *args, PyObject *kwargs) envp = g_new0(char *, len + 1); for (i = 0; i < len; ++i) { PyObject *tmp = PySequence_ITEM(pyenvp, i); - if (tmp == NULL || !PYGLIB_PyUnicode_Check(tmp)) { + if (tmp == NULL || !PyUnicode_Check (tmp)) { PyErr_SetString(PyExc_TypeError, - "gi._glib.spawn_async: " + "gi._gi.spawn_async: " "second argument must be a sequence of strings"); g_free(envp); Py_XDECREF(tmp); g_free(argv); return NULL; } - envp[i] = PYGLIB_PyUnicode_AsString(tmp); + envp[i] = PyUnicode_AsUTF8 (tmp); Py_DECREF(tmp); } } @@ -216,28 +230,28 @@ pyglib_spawn_async(PyObject *object, PyObject *args, PyObject *kwargs) Py_XDECREF(callback_data->data); g_slice_free(struct _PyGChildSetupData, callback_data); } - pyglib_error_check(&error); + pygi_error_check(&error); return NULL; } g_free(argv); if (envp) g_free(envp); if (standard_input) - pystdin = PYGLIB_PyLong_FromLong(*standard_input); + pystdin = pygi_gint_to_py(*standard_input); else { Py_INCREF(Py_None); pystdin = Py_None; } if (standard_output) - pystdout = PYGLIB_PyLong_FromLong(*standard_output); + pystdout = pygi_gint_to_py(*standard_output); else { Py_INCREF(Py_None); pystdout = Py_None; } if (standard_error) - pystderr = PYGLIB_PyLong_FromLong(*standard_error); + pystderr = pygi_gint_to_py(*standard_error); else { Py_INCREF(Py_None); pystderr = Py_None; @@ -246,14 +260,24 @@ pyglib_spawn_async(PyObject *object, PyObject *args, PyObject *kwargs) return Py_BuildValue("NNNN", pyg_pid_new(child_pid), pystdin, pystdout, pystderr); } -void -pyglib_spawn_register_types(PyObject *d) +/** + * Returns 0 on success, or -1 and sets an exception. + */ +int +pygi_spawn_register_types(PyObject *d) { - PyGPid_Type.tp_base = &PYGLIB_PyLong_Type; + PyGPid_Type.tp_base = &PyLong_Type; PyGPid_Type.tp_flags = Py_TPFLAGS_DEFAULT; PyGPid_Type.tp_methods = pyg_pid_methods; PyGPid_Type.tp_init = pyg_pid_tp_init; PyGPid_Type.tp_free = (freefunc)pyg_pid_free; - PyGPid_Type.tp_new = PYGLIB_PyLong_Type.tp_new; - PYGLIB_REGISTER_TYPE(d, PyGPid_Type, "Pid"); + PyGPid_Type.tp_new = PyLong_Type.tp_new; + PyGPid_Type.tp_alloc = PyType_GenericAlloc; + + if (PyType_Ready(&PyGPid_Type)) + return -1; + + PyDict_SetItemString(d, "Pid", (PyObject *)&PyGPid_Type); + + return 0; } diff --git a/gi/_glib/pygspawn.h b/gi/pygspawn.h index 2e8dd3c..c493ef8 100644 --- a/gi/_glib/pygspawn.h +++ b/gi/pygspawn.h @@ -14,16 +14,14 @@ * 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 + * License along with this library; if not, see <http://www.gnu.org/licenses/>. */ #ifndef __PYG_PID_H__ #define __PYG_PID_H__ PyObject * pyg_pid_new(GPid pid); -void pyglib_spawn_register_types(PyObject *d); +int pygi_spawn_register_types(PyObject *d); PyObject * pyglib_spawn_async(PyObject *self, PyObject *args, PyObject *kwargs); diff --git a/gi/pygtkcompat.py b/gi/pygtkcompat.py index 4a9c4be..364fb6c 100644 --- a/gi/pygtkcompat.py +++ b/gi/pygtkcompat.py @@ -1,4 +1,3 @@ -from __future__ import absolute_import import warnings from gi import PyGIDeprecationWarning diff --git a/gi/repository/Makefile.am b/gi/repository/Makefile.am deleted file mode 100644 index 1177ad5..0000000 --- a/gi/repository/Makefile.am +++ /dev/null @@ -1,16 +0,0 @@ -pygirepositorydir = $(pyexecdir)/gi/repository - -pygirepository_PYTHON = \ - __init__.py - - -# 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 $(pygirepository_PYTHON); do \ - [ -e $(builddir)/$$f ] || $(LN_S) $(srcdir)/$$f $(builddir)/$$f; \ - done - -all-local: build_pylinks -check-local: build_pylinks diff --git a/gi/repository/Makefile.in b/gi/repository/Makefile.in deleted file mode 100644 index 72cbd29..0000000 --- a/gi/repository/Makefile.in +++ /dev/null @@ -1,574 +0,0 @@ -# Makefile.in generated by automake 1.13.3 from Makefile.am. -# @configure_input@ - -# Copyright (C) 1994-2013 Free Software Foundation, Inc. - -# This Makefile.in is free software; the Free Software Foundation -# gives unlimited permission to copy and/or distribute it, -# with or without modifications, as long as this notice is preserved. - -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY, to the extent permitted by law; without -# even the implied warranty of MERCHANTABILITY or FITNESS FOR A -# PARTICULAR PURPOSE. - -@SET_MAKE@ -VPATH = @srcdir@ -am__is_gnu_make = test -n '$(MAKEFILE_LIST)' && test -n '$(MAKELEVEL)' -am__make_running_with_option = \ - case $${target_option-} in \ - ?) ;; \ - *) echo "am__make_running_with_option: internal error: invalid" \ - "target option '$${target_option-}' specified" >&2; \ - exit 1;; \ - esac; \ - has_opt=no; \ - sane_makeflags=$$MAKEFLAGS; \ - if $(am__is_gnu_make); then \ - sane_makeflags=$$MFLAGS; \ - else \ - case $$MAKEFLAGS in \ - *\\[\ \ ]*) \ - bs=\\; \ - sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ - | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ - esac; \ - fi; \ - skip_next=no; \ - strip_trailopt () \ - { \ - flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ - }; \ - for flg in $$sane_makeflags; do \ - test $$skip_next = yes && { skip_next=no; continue; }; \ - case $$flg in \ - *=*|--*) continue;; \ - -*I) strip_trailopt 'I'; skip_next=yes;; \ - -*I?*) strip_trailopt 'I';; \ - -*O) strip_trailopt 'O'; skip_next=yes;; \ - -*O?*) strip_trailopt 'O';; \ - -*l) strip_trailopt 'l'; skip_next=yes;; \ - -*l?*) strip_trailopt 'l';; \ - -[dEDm]) skip_next=yes;; \ - -[JT]) skip_next=yes;; \ - esac; \ - case $$flg in \ - *$$target_option*) has_opt=yes; break;; \ - esac; \ - done; \ - test $$has_opt = yes -am__make_dryrun = (target_option=n; $(am__make_running_with_option)) -am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) -pkgdatadir = $(datadir)/@PACKAGE@ -pkgincludedir = $(includedir)/@PACKAGE@ -pkglibdir = $(libdir)/@PACKAGE@ -pkglibexecdir = $(libexecdir)/@PACKAGE@ -am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd -install_sh_DATA = $(install_sh) -c -m 644 -install_sh_PROGRAM = $(install_sh) -c -install_sh_SCRIPT = $(install_sh) -c -INSTALL_HEADER = $(INSTALL_DATA) -transform = $(program_transform_name) -NORMAL_INSTALL = : -PRE_INSTALL = : -POST_INSTALL = : -NORMAL_UNINSTALL = : -PRE_UNINSTALL = : -POST_UNINSTALL = : -build_triplet = @build@ -host_triplet = @host@ -subdir = gi/repository -DIST_COMMON = $(srcdir)/Makefile.in $(srcdir)/Makefile.am \ - $(pygirepository_PYTHON) $(top_srcdir)/py-compile -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 -am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ - $(ACLOCAL_M4) -mkinstalldirs = $(install_sh) -d -CONFIG_HEADER = $(top_builddir)/config.h -CONFIG_CLEAN_FILES = -CONFIG_CLEAN_VPATH_FILES = -AM_V_P = $(am__v_P_@AM_V@) -am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) -am__v_P_0 = false -am__v_P_1 = : -AM_V_GEN = $(am__v_GEN_@AM_V@) -am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) -am__v_GEN_0 = @echo " GEN " $@; -am__v_GEN_1 = -AM_V_at = $(am__v_at_@AM_V@) -am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) -am__v_at_0 = @ -am__v_at_1 = -SOURCES = -DIST_SOURCES = -am__can_run_installinfo = \ - case $$AM_UPDATE_INFO_DIR in \ - n|no|NO) false;; \ - *) (install-info --version) >/dev/null 2>&1;; \ - esac -am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; -am__vpath_adj = case $$p in \ - $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ - *) f=$$p;; \ - esac; -am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; -am__install_max = 40 -am__nobase_strip_setup = \ - srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` -am__nobase_strip = \ - for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" -am__nobase_list = $(am__nobase_strip_setup); \ - for p in $$list; do echo "$$p $$p"; done | \ - sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ - $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ - if (++n[$$2] == $(am__install_max)) \ - { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ - END { for (dir in files) print dir, files[dir] }' -am__base_list = \ - sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ - sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' -am__uninstall_files_from_dir = { \ - test -z "$$files" \ - || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ - || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ - $(am__cd) "$$dir" && rm -f $$files; }; \ - } -am__py_compile = PYTHON=$(PYTHON) $(SHELL) $(py_compile) -am__installdirs = "$(DESTDIR)$(pygirepositorydir)" -am__pep3147_tweak = \ - sed -e 's|\.py$$||' -e 's|[^/]*$$|__pycache__/&.*.py|' -py_compile = $(top_srcdir)/py-compile -am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) -DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) -ACLOCAL = @ACLOCAL@ -ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@ -AMTAR = @AMTAR@ -AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ -AR = @AR@ -AS = @AS@ -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@ -DATADIR = @DATADIR@ -DEFS = @DEFS@ -DEPDIR = @DEPDIR@ -DLLTOOL = @DLLTOOL@ -DSYMUTIL = @DSYMUTIL@ -DUMPBIN = @DUMPBIN@ -ECHO_C = @ECHO_C@ -ECHO_N = @ECHO_N@ -ECHO_T = @ECHO_T@ -EGREP = @EGREP@ -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@ -GI_DATADIR = @GI_DATADIR@ -GI_LIBS = @GI_LIBS@ -GLIB_CFLAGS = @GLIB_CFLAGS@ -GLIB_COMPILE_RESOURCES = @GLIB_COMPILE_RESOURCES@ -GLIB_GENMARSHAL = @GLIB_GENMARSHAL@ -GLIB_LIBS = @GLIB_LIBS@ -GLIB_MKENUMS = @GLIB_MKENUMS@ -GOBJECT_QUERY = @GOBJECT_QUERY@ -GREP = @GREP@ -INSTALL = @INSTALL@ -INSTALL_DATA = @INSTALL_DATA@ -INSTALL_PROGRAM = @INSTALL_PROGRAM@ -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@ -LIBOBJS = @LIBOBJS@ -LIBS = @LIBS@ -LIBTOOL = @LIBTOOL@ -LIPO = @LIPO@ -LN_S = @LN_S@ -LTLIBOBJS = @LTLIBOBJS@ -MAKEINFO = @MAKEINFO@ -MANIFEST_TOOL = @MANIFEST_TOOL@ -MKDIR_P = @MKDIR_P@ -NM = @NM@ -NMEDIT = @NMEDIT@ -OBJDUMP = @OBJDUMP@ -OBJEXT = @OBJEXT@ -OTOOL = @OTOOL@ -OTOOL64 = @OTOOL64@ -PACKAGE = @PACKAGE@ -PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ -PACKAGE_NAME = @PACKAGE_NAME@ -PACKAGE_STRING = @PACKAGE_STRING@ -PACKAGE_TARNAME = @PACKAGE_TARNAME@ -PACKAGE_URL = @PACKAGE_URL@ -PACKAGE_VERSION = @PACKAGE_VERSION@ -PATH_SEPARATOR = @PATH_SEPARATOR@ -PKG_CONFIG = @PKG_CONFIG@ -PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ -PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ -PLATFORM = @PLATFORM@ -PYCAIRO_CFLAGS = @PYCAIRO_CFLAGS@ -PYCAIRO_LIBS = @PYCAIRO_LIBS@ -PYGOBJECT_MAJOR_VERSION = @PYGOBJECT_MAJOR_VERSION@ -PYGOBJECT_MICRO_VERSION = @PYGOBJECT_MICRO_VERSION@ -PYGOBJECT_MINOR_VERSION = @PYGOBJECT_MINOR_VERSION@ -PYTHON = @PYTHON@ -PYTHON_BASENAME = @PYTHON_BASENAME@ -PYTHON_EXEC_PREFIX = @PYTHON_EXEC_PREFIX@ -PYTHON_INCLUDES = @PYTHON_INCLUDES@ -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@ -SET_MAKE = @SET_MAKE@ -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@ -abs_top_srcdir = @abs_top_srcdir@ -ac_ct_AR = @ac_ct_AR@ -ac_ct_CC = @ac_ct_CC@ -ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ -am__include = @am__include@ -am__leading_dot = @am__leading_dot@ -am__quote = @am__quote@ -am__tar = @am__tar@ -am__untar = @am__untar@ -bindir = @bindir@ -build = @build@ -build_alias = @build_alias@ -build_cpu = @build_cpu@ -build_os = @build_os@ -build_vendor = @build_vendor@ -builddir = @builddir@ -datadir = @datadir@ -datarootdir = @datarootdir@ -docdir = @docdir@ -dvidir = @dvidir@ -exec_prefix = @exec_prefix@ -host = @host@ -host_alias = @host_alias@ -host_cpu = @host_cpu@ -host_os = @host_os@ -host_vendor = @host_vendor@ -htmldir = @htmldir@ -includedir = @includedir@ -infodir = @infodir@ -install_sh = @install_sh@ -libdir = @libdir@ -libexecdir = @libexecdir@ -localedir = @localedir@ -localstatedir = @localstatedir@ -mandir = @mandir@ -mkdir_p = @mkdir_p@ -oldincludedir = @oldincludedir@ -pdfdir = @pdfdir@ -pkgpyexecdir = @pkgpyexecdir@ -pkgpythondir = @pkgpythondir@ -prefix = @prefix@ -program_transform_name = @program_transform_name@ -psdir = @psdir@ -pyexecdir = @pyexecdir@ -pythondir = @pythondir@ -sbindir = @sbindir@ -sharedstatedir = @sharedstatedir@ -srcdir = @srcdir@ -sysconfdir = @sysconfdir@ -target_alias = @target_alias@ -top_build_prefix = @top_build_prefix@ -top_builddir = @top_builddir@ -top_srcdir = @top_srcdir@ -pygirepositorydir = $(pyexecdir)/gi/repository -pygirepository_PYTHON = \ - __init__.py - -all: all-am - -.SUFFIXES: -$(srcdir)/Makefile.in: $(srcdir)/Makefile.am $(am__configure_deps) - @for dep in $?; do \ - case '$(am__configure_deps)' in \ - *$$dep*) \ - ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ - && { if test -f $@; then exit 0; else break; fi; }; \ - exit 1;; \ - esac; \ - done; \ - echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign gi/repository/Makefile'; \ - $(am__cd) $(top_srcdir) && \ - $(AUTOMAKE) --foreign gi/repository/Makefile -.PRECIOUS: Makefile -Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status - @case '$?' in \ - *config.status*) \ - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ - *) \ - echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe)'; \ - cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \ - esac; - -$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh - -$(top_srcdir)/configure: $(am__configure_deps) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh -$(ACLOCAL_M4): $(am__aclocal_m4_deps) - cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh -$(am__aclocal_m4_deps): - -mostlyclean-libtool: - -rm -f *.lo - -clean-libtool: - -rm -rf .libs _libs -install-pygirepositoryPYTHON: $(pygirepository_PYTHON) - @$(NORMAL_INSTALL) - @list='$(pygirepository_PYTHON)'; dlist=; list2=; test -n "$(pygirepositorydir)" || list=; \ - if test -n "$$list"; then \ - echo " $(MKDIR_P) '$(DESTDIR)$(pygirepositorydir)'"; \ - $(MKDIR_P) "$(DESTDIR)$(pygirepositorydir)" || exit 1; \ - fi; \ - for p in $$list; do \ - if test -f "$$p"; then b=; else b="$(srcdir)/"; fi; \ - if test -f $$b$$p; then \ - $(am__strip_dir) \ - dlist="$$dlist $$f"; \ - list2="$$list2 $$b$$p"; \ - else :; fi; \ - done; \ - for file in $$list2; do echo $$file; done | $(am__base_list) | \ - while read files; do \ - echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(pygirepositorydir)'"; \ - $(INSTALL_DATA) $$files "$(DESTDIR)$(pygirepositorydir)" || exit $$?; \ - done || exit $$?; \ - if test -n "$$dlist"; then \ - $(am__py_compile) --destdir "$(DESTDIR)" \ - --basedir "$(pygirepositorydir)" $$dlist; \ - else :; fi - -uninstall-pygirepositoryPYTHON: - @$(NORMAL_UNINSTALL) - @list='$(pygirepository_PYTHON)'; test -n "$(pygirepositorydir)" || list=; \ - py_files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ - test -n "$$py_files" || exit 0; \ - dir='$(DESTDIR)$(pygirepositorydir)'; \ - pyc_files=`echo "$$py_files" | sed 's|$$|c|'`; \ - pyo_files=`echo "$$py_files" | sed 's|$$|o|'`; \ - py_files_pep3147=`echo "$$py_files" | $(am__pep3147_tweak)`; \ - echo "$$py_files_pep3147";\ - pyc_files_pep3147=`echo "$$py_files_pep3147" | sed 's|$$|c|'`; \ - pyo_files_pep3147=`echo "$$py_files_pep3147" | sed 's|$$|o|'`; \ - st=0; \ - for files in \ - "$$py_files" \ - "$$pyc_files" \ - "$$pyo_files" \ - "$$pyc_files_pep3147" \ - "$$pyo_files_pep3147" \ - ; do \ - $(am__uninstall_files_from_dir) || st=$$?; \ - done; \ - exit $$st -tags TAGS: - -ctags CTAGS: - -cscope cscopelist: - - -distdir: $(DISTFILES) - @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ - list='$(DISTFILES)'; \ - dist_files=`for file in $$list; do echo $$file; done | \ - sed -e "s|^$$srcdirstrip/||;t" \ - -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ - case $$dist_files in \ - */*) $(MKDIR_P) `echo "$$dist_files" | \ - sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ - sort -u` ;; \ - esac; \ - for file in $$dist_files; do \ - if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ - if test -d $$d/$$file; then \ - dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ - if test -d "$(distdir)/$$file"; then \ - find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ - fi; \ - if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ - cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ - find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ - fi; \ - cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ - else \ - test -f "$(distdir)/$$file" \ - || cp -p $$d/$$file "$(distdir)/$$file" \ - || exit 1; \ - fi; \ - done -check-am: all-am - $(MAKE) $(AM_MAKEFLAGS) check-local -check: check-am -all-am: Makefile all-local -installdirs: - for dir in "$(DESTDIR)$(pygirepositorydir)"; do \ - test -z "$$dir" || $(MKDIR_P) "$$dir"; \ - done -install: install-am -install-exec: install-exec-am -install-data: install-data-am -uninstall: uninstall-am - -install-am: all-am - @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am - -installcheck: installcheck-am -install-strip: - if test -z '$(STRIP)'; then \ - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ - install; \ - else \ - $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ - install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ - "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ - fi -mostlyclean-generic: - -clean-generic: - -distclean-generic: - -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) - -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) - -maintainer-clean-generic: - @echo "This command is intended for maintainers to use" - @echo "it deletes files that may require special tools to rebuild." -clean: clean-am - -clean-am: clean-generic clean-libtool mostlyclean-am - -distclean: distclean-am - -rm -f Makefile -distclean-am: clean-am distclean-generic - -dvi: dvi-am - -dvi-am: - -html: html-am - -html-am: - -info: info-am - -info-am: - -install-data-am: install-pygirepositoryPYTHON - -install-dvi: install-dvi-am - -install-dvi-am: - -install-exec-am: - -install-html: install-html-am - -install-html-am: - -install-info: install-info-am - -install-info-am: - -install-man: - -install-pdf: install-pdf-am - -install-pdf-am: - -install-ps: install-ps-am - -install-ps-am: - -installcheck-am: - -maintainer-clean: maintainer-clean-am - -rm -f Makefile -maintainer-clean-am: distclean-am maintainer-clean-generic - -mostlyclean: mostlyclean-am - -mostlyclean-am: mostlyclean-generic mostlyclean-libtool - -pdf: pdf-am - -pdf-am: - -ps: ps-am - -ps-am: - -uninstall-am: uninstall-pygirepositoryPYTHON - -.MAKE: check-am install-am install-strip - -.PHONY: all all-am all-local check check-am check-local clean \ - clean-generic clean-libtool cscopelist-am ctags-am distclean \ - distclean-generic distclean-libtool distdir dvi dvi-am html \ - html-am info info-am install install-am install-data \ - install-data-am install-dvi install-dvi-am install-exec \ - install-exec-am install-html install-html-am install-info \ - install-info-am install-man install-pdf install-pdf-am \ - install-ps install-ps-am install-pygirepositoryPYTHON \ - install-strip installcheck installcheck-am installdirs \ - maintainer-clean maintainer-clean-generic mostlyclean \ - mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ - tags-am uninstall uninstall-am uninstall-pygirepositoryPYTHON - - -# 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 $(pygirepository_PYTHON); do \ - [ -e $(builddir)/$$f ] || $(LN_S) $(srcdir)/$$f $(builddir)/$$f; \ - done - -all-local: build_pylinks -check-local: build_pylinks - -# Tell versions [3.59,3.63) of GNU make to not export all variables. -# Otherwise a system limit (for SysV at least) may be exceeded. -.NOEXPORT: diff --git a/gi/repository/__init__.py b/gi/repository/__init__.py index 5c5552a..640fc8e 100644 --- a/gi/repository/__init__.py +++ b/gi/repository/__init__.py @@ -18,8 +18,6 @@ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 # USA -from __future__ import absolute_import - import sys from ..importer import DynamicImporter diff --git a/gi/repository/meson.build b/gi/repository/meson.build new file mode 100644 index 0000000..fdc136b --- /dev/null +++ b/gi/repository/meson.build @@ -0,0 +1,5 @@ +python_sources = ['__init__.py'] + +python.install_sources(python_sources, + subdir : join_paths('gi', 'repository') +) diff --git a/gi/types.py b/gi/types.py index 7c0f617..9205936 100644 --- a/gi/types.py +++ b/gi/types.py @@ -20,14 +20,10 @@ # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 # USA -from __future__ import absolute_import +import re -import sys -import warnings - -from . import _gobject -from ._gobject._gobject import GInterface -from ._gobject.constants import TYPE_INVALID +from ._constants import TYPE_INVALID +from .docstring import generate_doc_string from ._gi import \ InterfaceInfo, \ @@ -35,15 +31,19 @@ from ._gi import \ StructInfo, \ VFuncInfo, \ register_interface_info, \ - hook_up_vfunc_implementation + hook_up_vfunc_implementation, \ + GInterface +from . import _gi + +StructInfo, GInterface # pyflakes +from . import _propertyhelper as propertyhelper +from . import _signalhelper as signalhelper -StructInfo # pyflakes -if (3, 0) <= sys.version_info < (3, 3): - # callable not available for python 3.0 thru 3.2 - def callable(obj): - return hasattr(obj, '__call__') +def snake_case(name): + s1 = re.sub('(.)([A-Z][a-z]+)', r'\1_\2', name) + return re.sub('([a-z0-9])([A-Z])', r'\1_\2', s1).lower() class MetaClassHelper(object): @@ -51,6 +51,17 @@ class MetaClassHelper(object): for method_info in cls.__info__.get_methods(): setattr(cls, method_info.__name__, method_info) + def _setup_class_methods(cls): + info = cls.__info__ + class_struct = info.get_class_struct() + if class_struct is None: + return + for method_info in class_struct.get_methods(): + name = method_info.__name__ + # Don't mask regular methods or base class methods with TypeClass methods. + if not hasattr(cls, name): + setattr(cls, name, classmethod(method_info)) + def _setup_fields(cls): for field_info in cls.__info__.get_fields(): name = field_info.get_name().replace('-', '_') @@ -67,6 +78,8 @@ class MetaClassHelper(object): if not vfunc_name.startswith("do_") or not callable(py_vfunc): continue + skip_ambiguity_check = False + # If a method name starts with "do_" assume it is a vfunc, and search # in the base classes for a method with the same name to override. # Recursion is necessary as overriden methods in most immediate parent @@ -78,6 +91,20 @@ class MetaClassHelper(object): vfunc_info = method break + if not hasattr(base, '__info__') or not hasattr(base.__info__, 'get_vfuncs'): + continue + + base_name = snake_case(base.__info__.get_type_name()) + + for v in base.__info__.get_vfuncs(): + if vfunc_name == 'do_%s_%s' % (base_name, v.get_name()): + vfunc_info = v + skip_ambiguity_check = True + break + + if vfunc_info: + break + # If we did not find a matching method name in the bases, we might # be overriding an interface virtual method. Since interfaces do not # provide implementations, there will be no method attribute installed @@ -88,22 +115,22 @@ class MetaClassHelper(object): vfunc_info = find_vfunc_info_in_interface(cls.__bases__, vfunc_name[len("do_"):]) if vfunc_info is not None: - assert vfunc_name == ('do_' + vfunc_info.get_name()) # Check to see if there are vfuncs with the same name in the bases. # We have no way of specifying which one we are supposed to override. - ambiguous_base = find_vfunc_conflict_in_bases(vfunc_info, cls.__bases__) - if ambiguous_base is not None: - base_info = vfunc_info.get_container() - raise TypeError('Method %s() on class %s.%s is ambiguous ' - 'with methods in base classes %s.%s and %s.%s' % - (vfunc_name, - cls.__info__.get_namespace(), - cls.__info__.get_name(), - base_info.get_namespace(), - base_info.get_name(), - ambiguous_base.__info__.get_namespace(), - ambiguous_base.__info__.get_name() - )) + if not skip_ambiguity_check: + ambiguous_base = find_vfunc_conflict_in_bases(vfunc_info, cls.__bases__) + if ambiguous_base is not None: + base_info = vfunc_info.get_container() + raise TypeError('Method %s() on class %s.%s is ambiguous ' + 'with methods in base classes %s.%s and %s.%s' % + (vfunc_name, + cls.__info__.get_namespace(), + cls.__info__.get_name(), + base_info.get_namespace(), + base_info.get_name(), + ambiguous_base.__info__.get_namespace(), + ambiguous_base.__info__.get_name() + )) hook_up_vfunc_implementation(vfunc_info, cls.__gtype__, py_vfunc) @@ -132,7 +159,7 @@ def find_vfunc_info_in_interface(bases, vfunc_name): # This can be seen in IntrospectionModule.__getattr__() in module.py. # We do not need to search regular classes here, only wrapped interfaces. # We also skip GInterface, because it is not wrapped and has no __info__ attr. - # Skip bases without __info__ (static _gobject._gobject.GObject) + # Skip bases without __info__ (static _gi.GObject) if base is GInterface or\ not issubclass(base, GInterface) or\ not hasattr(base, '__info__'): @@ -169,8 +196,32 @@ def find_vfunc_conflict_in_bases(vfunc, bases): return None -class GObjectMeta(_gobject.GObjectMeta, MetaClassHelper): +class _GObjectMetaBase(type): + """Metaclass for automatically registering GObject classes.""" + def __init__(cls, name, bases, dict_): + type.__init__(cls, name, bases, dict_) + propertyhelper.install_properties(cls) + signalhelper.install_signals(cls) + cls._type_register(cls.__dict__) + + def _type_register(cls, namespace): + # don't register the class if already registered + if '__gtype__' in namespace: + return + + # Do not register a new GType for the overrides, as this would sort of + # defeat the purpose of overrides... + if cls.__module__.startswith('gi.overrides.'): + return + _gi.type_register(cls, namespace.get('__gtype_name__')) + + +_gi._install_metaclass(_GObjectMetaBase) + + +class GObjectMeta(_GObjectMetaBase, MetaClassHelper): + """Meta class used for GI GObject based types.""" def __init__(cls, name, bases, dict_): super(GObjectMeta, cls).__init__(name, bases, dict_) is_gi_defined = False @@ -184,6 +235,8 @@ class GObjectMeta(_gobject.GObjectMeta, MetaClassHelper): if is_python_defined: cls._setup_vfuncs() elif is_gi_defined: + if isinstance(cls.__info__, ObjectInfo): + cls._setup_class_methods() cls._setup_methods() cls._setup_constants() cls._setup_native_vfuncs() @@ -196,6 +249,22 @@ class GObjectMeta(_gobject.GObjectMeta, MetaClassHelper): def mro(cls): return mro(cls) + @property + def __doc__(cls): + """Meta class property which shows up on any class using this meta-class.""" + if cls == GObjectMeta: + return '' + + doc = cls.__dict__.get('__doc__', None) + if doc is not None: + return doc + + # For repository classes, dynamically generate a doc string if it wasn't overridden. + if cls.__module__.startswith(('gi.repository.', 'gi.overrides')): + return generate_doc_string(cls.__info__) + + return None + def mro(C): """Compute the class precedence list (mro) according to C3, with GObject @@ -218,19 +287,7 @@ def mro(C): # in __mro__ at each point. Therefore at this point we know that # we already have our base class MRO's available to us, there is # no need for us to (re)calculate them. - if hasattr(base, '__mro__'): - bases_of_subclasses += [list(base.__mro__)] - else: - warnings.warn('Mixin class %s is an old style class, please ' - 'update this to derive from "object".' % base, - RuntimeWarning) - # For old-style classes (Python2 only), the MRO is not - # easily accessible. As we do need it here, we calculate - # it via recursion, according to the C3 algorithm. Using C3 - # for old style classes deviates from Python's own behaviour, - # but visible effects here would be a corner case triggered by - # questionable design. - bases_of_subclasses += [mro(base)] + bases_of_subclasses += [list(base.__mro__)] bases_of_subclasses += [list(C.__bases__)] while bases_of_subclasses: @@ -257,7 +314,12 @@ def mro(C): return bases +def nothing(*args, **kwargs): + pass + + class StructMeta(type, MetaClassHelper): + """Meta class used for GI Struct based types.""" def __init__(cls, name, bases, dict_): super(StructMeta, cls).__init__(name, bases, dict_) @@ -273,6 +335,16 @@ class StructMeta(type, MetaClassHelper): for method_info in cls.__info__.get_methods(): if method_info.is_constructor() and \ method_info.__name__ == 'new' and \ - not method_info.get_arguments(): + (not method_info.get_arguments() or + cls.__info__.get_size() == 0): cls.__new__ = staticmethod(method_info) + # Boxed will raise an exception + # if arguments are given to __init__ + cls.__init__ = nothing break + + @property + def __doc__(cls): + if cls == StructMeta: + return '' + return generate_doc_string(cls.__info__) |