././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/.coveragerc0000664000000000000000000000013315074674453014464 0ustar00rootroot[run] branch = True relative_files = True include = gi/* tests/* pygtkcompat/* ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/.flake80000664000000000000000000000013015074674453013513 0ustar00rootroot[flake8] ignore=E501,E123,E124,E402,E731,E722,W504,F824 exclude=subprojects,build,.venv ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/.gitignore0000664000000000000000000000043215074674453014335 0ustar00rootroot.venv .mypy_cache *.bak *.lo *.o *.orig *.pyc *.rej *.so *.la *.tab.c *~ .*.sw[nop] *.gir *.typelib *.dll *.dylib .DS_STORE .idea .cache .pytest_cache /config.h /tmp/* /build/ /dist/ /pygobject.egg-info/ /docs/_build /PyGObject.egg-info/ *.pyd *.dll.a .coverage pdm.lock .pdm-python././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/.gitlab-ci/Dockerfile0000664000000000000000000000340015074674453016246 0ustar00rootrootFROM ubuntu:jammy ENV DEBIAN_FRONTEND=noninteractive RUN apt-get update && apt-get install -y \ software-properties-common \ build-essential \ ccache \ curl \ dbus \ gir1.2-gtk-3.0 \ gir1.2-gtk-4.0 \ git \ gobject-introspection \ lcov \ libbz2-dev \ libcairo2-dev \ libffi-dev \ libgirepository1.0-dev \ libglib2.0-dev \ libgtk-3-0 \ libgtk-4-1 \ libreadline-dev \ libsqlite3-dev \ libssl-dev \ liblzma-dev \ ninja-build \ python3-pip \ sudo \ xauth \ xvfb \ && rm -rf /var/lib/apt/lists/* RUN add-apt-repository -y ppa:pypy/ppa \ && apt-get update \ && apt-get install -y pypy3 pypy3-dev pypy3-venv \ && rm -rf /var/lib/apt/lists/* ARG HOST_USER_ID=5555 ENV HOST_USER_ID ${HOST_USER_ID} RUN useradd -u $HOST_USER_ID -ms /bin/bash user RUN echo 'user ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers USER user WORKDIR /home/user ENV LANG C.UTF-8 ENV CI true ENV PYENV_ROOT /home/user/.pyenv ENV PATH="${PYENV_ROOT}/shims:${PYENV_ROOT}/bin:${PATH}" ENV PYTHON_CONFIGURE_OPTS="--enable-shared" # https://github.com/pyenv/pyenv/releases ENV PYENV_GIT_TAG v2.3.31 RUN curl -L https://raw.githubusercontent.com/pyenv/pyenv-installer/master/bin/pyenv-installer | bash # Register the pypy3 system installation RUN mkdir -p "${PYENV_ROOT}/versions/pypy3-system/bin/" RUN sudo ln -s /usr/bin/pypy3 "${PYENV_ROOT}/versions/pypy3-system/bin/python" RUN pyenv rehash RUN pyenv install --debug 3.8 RUN pyenv install --debug 3.9 RUN pyenv install --debug 3.10 RUN pyenv install --debug 3.11 RUN pyenv install --debug 3.12 ENV PATH="/usr/lib/ccache:${PATH}" COPY --chown=user:user set_env.sh /home/user/set_env.sh RUN chmod +x /home/user/set_env.sh ENTRYPOINT ["/home/user/set_env.sh"]././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/.gitlab-ci/Dockerfile.old0000664000000000000000000000135515074674453017032 0ustar00rootrootFROM i386/debian:bullseye ENV DEBIAN_FRONTEND=noninteractive RUN apt-get update && apt-get install -y \ autoconf-archive \ build-essential \ ccache \ curl \ dbus \ gir1.2-gtk-3.0 \ git \ gobject-introspection \ lcov \ libcairo2-dev \ libffi-dev \ libgirepository1.0-dev \ libglib2.0-dev \ libgtk-3-0 \ libtool \ locales \ python3-dev \ python3-venv \ sudo \ xauth \ xvfb \ && rm -rf /var/lib/apt/lists/* ARG HOST_USER_ID=5555 ENV HOST_USER_ID ${HOST_USER_ID} RUN useradd -u $HOST_USER_ID -ms /bin/bash user RUN echo 'user ALL=(ALL) NOPASSWD:ALL' >> /etc/sudoers USER user WORKDIR /home/user ENV LANG C.UTF-8 ENV CI true ENV PATH="/usr/lib/ccache:${PATH}" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/.gitlab-ci/README.rst0000664000000000000000000000116115074674453015745 0ustar00rootrootCI Docker Images ================ There are two images which are used for CI and which can be found here: https://gitlab.gnome.org/GNOME/pygobject/container_registry * `Dockerfile` - contains various Python versions and a commonly used distro. Run `run-docker.sh` to build it and run a shell in it. After that it can be pushed. * `Dockerfile.old` - 32bit using the oldest supported distro, to test with old stuff. Run `run-docker-old.sh` to build it and run a shell in it. After that it can be pushed. The scripts spawn a shell in the container with the source code mounted, so things can be tested locally if needed. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/.gitlab-ci/build-sdists.sh0000775000000000000000000000063215074674453017225 0ustar00rootroot#!/bin/bash set -e python -m pip install --upgrade pdm python -m pdm build VERSION=$(grep version meson.build | head -1 | sed "s/^.*'\([0-9\.]*\)'.*$/\1/") if [[ "$VERSION" =~ ^[0-9]\.[0-9]*[13579]\. ]] then cat << EOF ****************** ATTENTION ****************** This is an UNstable release. Do NOT upload this release to PyPI. ****************** ATTENTION ****************** EOF fi ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/.gitlab-ci/coverage-docker.sh0000775000000000000000000000137215074674453017661 0ustar00rootroot#!/bin/bash set -e # Make the Windows paths match our current layout python ./.gitlab-ci/fixup-lcov-paths.py coverage/*.lcov # Remove external headers (except gi tests) for path in coverage/*.lcov; do lcov --config-file .gitlab-ci/lcovrc -r "${path}" '/usr/include/*' -o "${path}" lcov --config-file .gitlab-ci/lcovrc -r "${path}" '/home/*' -o "${path}" lcov --config-file .gitlab-ci/lcovrc -r "${path}" '*/msys64/*' -o "${path}" lcov --config-file .gitlab-ci/lcovrc -r "${path}" '*subprojects/*' -o "${path}" lcov --config-file .gitlab-ci/lcovrc -r "${path}" '*tmp-introspect*' -o "${path}" done genhtml --ignore-errors=source --config-file .gitlab-ci/lcovrc \ coverage/*.lcov -o coverage/ cd coverage rm -f .coverage* rm -f *.lcov ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/.gitlab-ci/fixup-lcov-paths.py0000664000000000000000000000226415074674453020046 0ustar00rootrootimport sys import os import re def main(argv): # Fix paths in lcov files generated on a Windows host so they match our # current source layout. paths = argv[1:] for path in paths: print("cov-fixup:", path) with open(path, "r", encoding="utf-8") as h: text = h.read() text = text.replace("\\\\", "/").replace("\\", "/") new_root = os.getcwd() def make_abs(m): p = m.group(1) if p.startswith("C:/"): p = p.replace("C:/", "/c/") if not p.startswith("/"): p = os.path.join(new_root, p) return "SF:" + p text = re.sub("SF:(.*?)$", make_abs, text, 0, re.MULTILINE) canidate = None for old_root in set(re.findall(":(.*?)/gi/.*?$", text, re.MULTILINE)): if canidate is None or len(old_root) < len(canidate): canidate = old_root if canidate: print("replacing %r with %r" % (canidate, new_root)) text = text.replace(canidate, new_root) with open(path, "w", encoding="utf-8") as h: h.write(text) if __name__ == "__main__": sys.exit(main(sys.argv)) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/.gitlab-ci/lcovrc0000664000000000000000000000110215074674453015464 0ustar00rootroot# lcov and genhtml configuration # See http://ltp.sourceforge.net/coverage/lcov/lcovrc.5.php # Always enable branch coverage lcov_branch_coverage = 1 # Exclude precondition assertions, as we can never reasonably get full branch # coverage of them, as they should never normally fail. # See https://github.com/linux-test-project/lcov/issues/44 lcov_excl_br_line = LCOV_EXCL_BR_LINE|g_return_if_fail|g_return_val_if_fail|g_assert|g_assert_ # Similarly for unreachable assertions. lcov_excl_line = LCOV_EXCL_LINE|g_return_if_reached|g_return_val_if_reached|g_assert_not_reached ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/.gitlab-ci/org.gnome.PyGObject.Devel.yaml0000664000000000000000000000200415074674453021715 0ustar00rootrootapp-id: org.gnome.PyGObject.Devel runtime: org.gnome.Sdk runtime-version: '48' sdk: org.gnome.Sdk build-options: build-args: - '--share=network' test-args: - '--socket=x11' - '--share=network' env: PYTEST_ADDOPTS: '-vs --cov' TEST_GTK_VERSION: '3.0' modules: - name: dependencies buildsystem: simple build-commands: - python3 --version - glib-compile-schemas --version - echo "GTK VERSION ${TEST_GTK_VERSION}" - pip3 install --prefix=${FLATPAK_DEST} pycairo pytest pytest-cov - name: pygobject buildsystem: meson builddir: true config-opts: - '-Dtests=true' sources: - type: dir path: .. run-tests: true test-rule: '' test-commands: # Remove vala-nightly, since it contains an incompatible version of libdbus - >- LD_LIBRARY_PATH=$(echo $LD_LIBRARY_PATH | sed s/vala-nightly/foobar/) meson test -v - cd .. && python3 -m coverage lcov -o "coverage/flatpak-${TEST_GTK_VERSION}.py.lcov" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/.gitlab-ci/run-docker-old.sh0000775000000000000000000000051515074674453017444 0ustar00rootroot#!/bin/bash set -e TAG="registry.gitlab.gnome.org/gnome/pygobject/old:v6" sudo docker build --build-arg HOST_USER_ID="$UID" --tag "${TAG}" \ --file "Dockerfile.old" . sudo docker run --rm --security-opt label=disable \ --volume "$(pwd)/..:/home/user/app" --workdir "/home/user/app" \ --tty --interactive "${TAG}" bash ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/.gitlab-ci/run-docker-runtime.sh0000775000000000000000000000063115074674453020350 0ustar00rootroot#!/bin/bash set -e TAG="registry.gitlab.gnome.org/gnome/gnome-runtime-images/gnome:master" sudo docker pull "${TAG}" sudo docker run --privileged --rm --security-opt label=disable \ --volume "$(pwd)/..:/home/user/app" --workdir "/home/user/app" \ --tty --interactive "${TAG}" xvfb-run -a flatpak run --filesystem=host \ --share=network --socket=x11 --devel --command=bash org.gnome.Sdk//master ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/.gitlab-ci/run-docker.sh0000775000000000000000000000051315074674453016666 0ustar00rootroot#!/bin/bash set -e TAG="registry.gitlab.gnome.org/gnome/pygobject/main:v23" sudo docker build --build-arg HOST_USER_ID="$UID" --tag "${TAG}" \ --file "Dockerfile" . sudo docker run --rm --security-opt label=disable \ --volume "$(pwd)/..:/home/user/app" --workdir "/home/user/app" \ --tty --interactive "${TAG}" bash ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/.gitlab-ci/set_env.sh0000775000000000000000000000015115074674453016256 0ustar00rootroot#!/bin/sh set -e export PYENV_VERSION PYENV_VERSION="$(pyenv latest "${PYTHON_VERSION:-3}")" exec "$@" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/.gitlab-ci/test-docker-old.sh0000775000000000000000000000115015074674453017613 0ustar00rootroot#!/bin/bash set -e python3 --version python3 -m venv _venv source _venv/bin/activate # ccache setup export CCACHE_BASEDIR="$(pwd)" export CCACHE_DIR="${CCACHE_BASEDIR}/_ccache" COV_DIR="$(pwd)/coverage" COV_KEY="${CI_JOB_NAME}" export COVERAGE_FILE="${COV_DIR}/.coverage.${COV_KEY}" mkdir -p "${COV_DIR}" mkdir -p "${CCACHE_DIR}" # test python -m pip install --upgrade pip python -m pip install pycairo pytest pytest-cov meson ninja meson setup _build PYTEST_ADDOPTS="--cov" xvfb-run -a meson test --suite pygobject --timeout-multiplier 4 -C _build -v python -m coverage lcov -o "${COV_DIR}/${COV_KEY}.py.lcov" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/.gitlab-ci/test-docker.sh0000775000000000000000000000307015074674453017042 0ustar00rootroot#!/bin/bash set -e python --version PYVER=$(python -c "import sys; sys.stdout.write('.'.join(map(str, sys.version_info[:2])))") PYIMPL=$(python -c "import sys, platform; sys.stdout.write(platform.python_implementation())") SOURCE_DIR="$(pwd)" COV_DIR="${SOURCE_DIR}/coverage" COV_KEY="${CI_JOB_NAME}" export CFLAGS="-coverage -ftest-coverage -fprofile-arcs -Werror" export MALLOC_CHECK_=3 export MALLOC_PERTURB_=$((${RANDOM} % 255 + 1)) export G_SLICE="debug-blocks" export COVERAGE_FILE="${COV_DIR}/.coverage.${COV_KEY}" export CCACHE_BASEDIR="$(pwd)" export CCACHE_DIR="${CCACHE_BASEDIR}/_ccache" # https://docs.python.org/3/using/cmdline.html#envvar-PYTHONDEVMODE export PYTHONDEVMODE=1 export MESONPY_EDITABLE_VERBOSE=1 mkdir -p "${CCACHE_DIR}" mkdir -p "${COV_DIR}" python -m venv /tmp/venv source /tmp/venv/bin/activate # XXX: meson tries to use this for some reason, but it's not there by default mkdir -p /tmp/venv/include/pypy3.9 python -m pip install --upgrade pip python -m pip install flake8 meson meson-python pycairo pytest pytest-cov # CODE QUALITY python -m flake8 # BUILD & TEST python -m pip install --config-settings=setup-args="-Dtests=true" --no-build-isolation --editable '.[dev]' # TEST lcov --config-file .gitlab-ci/lcovrc --directory . --capture --initial --output-file \ "${COV_DIR}/${CI_JOB_NAME}-baseline.lcov" xvfb-run -a python -m pytest -v --cov python -m coverage lcov -o "${COV_DIR}/${COV_KEY}.py.lcov" # COLLECT GCOV COVERAGE lcov --config-file .gitlab-ci/lcovrc --directory . --capture --output-file \ "${COV_DIR}/${CI_JOB_NAME}.lcov" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/.gitlab-ci/test-flatpak.sh0000775000000000000000000000051715074674453017220 0ustar00rootroot#!/bin/bash set -e sed -i "/TEST_GTK_VERSION:/s/'.*'/'${TEST_GTK_VERSION:-3.0}'/" .gitlab-ci/org.gnome.PyGObject.Devel.yaml xvfb-run -a flatpak-builder --user --keep-build-dirs --verbose --disable-rofiles-fuse flatpak_ci .gitlab-ci/org.gnome.PyGObject.Devel.yaml mv .flatpak-builder/build/pygobject/coverage . chmod -R 777 coverage ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/.gitlab-ci/test-msys2.sh0000775000000000000000000000327015074674453016652 0ustar00rootroot#!/bin/bash set -e pacman --noconfirm -Suy pacman --noconfirm -S --needed \ "${MINGW_PACKAGE_PREFIX}"-ccache \ "${MINGW_PACKAGE_PREFIX}"-glib2 \ "${MINGW_PACKAGE_PREFIX}"-gobject-introspection \ "${MINGW_PACKAGE_PREFIX}"-gtk3 \ "${MINGW_PACKAGE_PREFIX}"-libffi \ "${MINGW_PACKAGE_PREFIX}"-meson \ "${MINGW_PACKAGE_PREFIX}"-ninja \ "${MINGW_PACKAGE_PREFIX}"-python \ "${MINGW_PACKAGE_PREFIX}"-python-cairo \ "${MINGW_PACKAGE_PREFIX}"-python-pip \ "${MINGW_PACKAGE_PREFIX}"-python-pytest \ "${MINGW_PACKAGE_PREFIX}"-python-pytest-cov \ "${MINGW_PACKAGE_PREFIX}"-toolchain \ git \ lcov # ccache setup export PATH="$MSYSTEM/lib/ccache/bin:$PATH" mkdir -p _ccache CCACHE_BASEDIR="$(pwd)" export CCACHE_BASEDIR CCACHE_DIR="${CCACHE_BASEDIR}/_ccache" export CCACHE_DIR # coverage setup COV_DIR="$(pwd)/coverage" COV_KEY="${CI_JOB_NAME_SLUG}" mkdir -p "${COV_DIR}" export COVERAGE_FILE="${COV_DIR}/.coverage.${COV_KEY}" # Test results JUNIT_XML="test-results.xml" # https://docs.python.org/3/using/cmdline.html#envvar-PYTHONDEVMODE export PYTHONDEVMODE=1 MSYSTEM='' CFLAGS="-coverage -ftest-coverage -fprofile-arcs -Werror" meson setup _build lcov \ --config-file .gitlab-ci/lcovrc \ --directory "$(pwd)" --capture --initial --output-file \ "${COV_DIR}/${COV_KEY}-baseline.lcov" MSYSTEM='' meson compile -C _build -v MSYSTEM='' PYTEST_ADDOPTS="--cov -sv --junit-xml=${JUNIT_XML}" meson test --suite pygobject --timeout-multiplier 4 -C _build -v MSYSTEM='' python -m coverage lcov -o "${COV_DIR}/${COV_KEY}.py.lcov" lcov \ --config-file .gitlab-ci/lcovrc \ --directory "$(pwd)" --capture --output-file \ "${COV_DIR}/${COV_KEY}.lcov" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/.gitlab-ci.yml0000664000000000000000000000605415074674453015007 0ustar00rootrootinclude: - component: gitlab.gnome.org/GNOME/citemplates/release-service@master inputs: dist-job-name: "sdist" tarball-artifact-path: "${TARBALL_ARTIFACT_PATH}" stages: - build_and_test - coverage - deploy variables: TARBALL_ARTIFACT_PATH: "dist/${CI_PROJECT_NAME}-${CI_COMMIT_TAG}.tar.gz" default: image: registry.gitlab.gnome.org/gnome/pygobject/main:v23 cache: paths: - _ccache/ linux: stage: build_and_test parallel: matrix: - PYTHON_VERSION: - "3.9" - "3.10" - "3.11" - "3.12" - "pypy3" TEST_GTK_VERSION: "3.0" - PYTHON_VERSION: "3.11" TEST_GTK_VERSION: "4.0" artifacts: when: always paths: - coverage/ - test-results.xml reports: junit: test-results.xml script: - bash -x ./.gitlab-ci/test-docker.sh windows: stage: build_and_test tags: - win32-ps parallel: matrix: - MSYSTEM: - "MINGW32" - "MINGW64" artifacts: when: always paths: - coverage/ - _build/meson-logs - test-results.xml reports: junit: test-results.xml script: - $env:CHERE_INVOKING = 'yes' - C:\msys64\usr\bin\pacman --noconfirm -Syyuu - C:\msys64\usr\bin\bash -lc "bash -x ./.gitlab-ci/test-msys2.sh" coverage: stage: coverage artifacts: paths: - coverage/ variables: PYTHON_VERSION: "3.9" script: - bash -x ./.gitlab-ci/coverage-docker.sh coverage: '/^\s+lines\.+:\s+([\d.]+\%)\s+/' pages: stage: deploy dependencies: - coverage before_script: - python -m pip install "pdm!=2.17.3" - python -m pdm install -v script: - python -m pdm run sphinx-build -T -E -W --keep-going -b html -d _build/doctrees -D language=en docs/ public - mv coverage/ public/ artifacts: paths: - public expire_in: 30 days rules: - if: $CI_COMMIT_BRANCH == "main" - if: $CI_COMMIT_TAG sdist: stage: build_and_test artifacts: paths: - dist/ script: - git config --global --add safe.directory "$CI_PROJECT_DIR" - bash -x ./.gitlab-ci/build-sdists.sh gnome-48: stage: build_and_test image: quay.io/gnome_infrastructure/gnome-runtime-images:gnome-48 tags: - flatpak parallel: matrix: - TEST_GTK_VERSION: - "3.0" - "4.0" artifacts: paths: - coverage/ script: - bash -x ./.gitlab-ci/test-flatpak.sh python3.12-pdm: stage: build_and_test variables: PYTHON_VERSION: "3.12" TEST_GTK_VERSION: "3.0" before_script: - python -m pip install "pdm!=2.17.3" - python -m pdm install -v script: - xvfb-run -a python -m pdm run pytest minimal-meson: allow_failure: true stage: build_and_test image: quay.io/fedora/fedora:40 before_script: - dnf install --assumeyes gcc meson git flex bison diffutils python3-devel python3-pytest gobject-introspection-devel script: - meson setup _build - meson compile -C _build - PYTEST_ADDOPTS="-sv -k 'not test_cairo'" meson test -C _build --suite pygobject --verbose ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/.pre-commit-config.yaml0000664000000000000000000000031615074674453016627 0ustar00rootroot# This is a configuration file for the pre-commit tool. # Documentation is available at https://pre-commit.com/#plugins repos: - repo: https://github.com/PyCQA/flake8 rev: 7.1.1 hooks: - id: flake8 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/COPYING0000664000000000000000000006351015074674453013406 0ustar00rootroot GNU LESSER GENERAL PUBLIC LICENSE Version 2.1, February 1999 Copyright (C) 1991, 1999 Free Software Foundation, Inc. 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. [This is the first released version of the Lesser GPL. It also counts as the successor of the GNU Library Public License, version 2, hence the version number 2.1.] Preamble The licenses for most software are designed to take away your freedom to share and change it. By contrast, the GNU General Public Licenses are intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. This license, the Lesser General Public License, applies to some specially designated software packages--typically libraries--of the Free Software Foundation and other authors who decide to use it. You can use it too, but we suggest you first think carefully about whether this license or the ordinary General Public License is the better strategy to use in any particular case, based on the explanations below. When we speak of free software, we are referring to freedom of use, not price. Our General Public Licenses are designed to make sure that you have the freedom to distribute copies of free software (and charge for this service if you wish); that you receive source code or can get it if you want it; that you can change the software and use pieces of it in new free programs; and that you are informed that you can do these things. To protect your rights, we need to make restrictions that forbid distributors to deny you these rights or to ask you to surrender these rights. These restrictions translate to certain responsibilities for you if you distribute copies of the library or if you modify it. For example, if you distribute copies of the library, whether gratis or for a fee, you must give the recipients all the rights that we gave you. You must make sure that they, too, receive or can get the source code. If you link other code with the library, you must provide complete object files to the recipients, so that they can relink them with the library after making changes to the library and recompiling it. And you must show them these terms so they know their rights. We protect your rights with a two-step method: (1) we copyright the library, and (2) we offer you this license, which gives you legal permission to copy, distribute and/or modify the library. To protect each distributor, we want to make it very clear that there is no warranty for the free library. Also, if the library is modified by someone else and passed on, the recipients should know that what they have is not the original version, so that the original author's reputation will not be affected by problems that might be introduced by others. Finally, software patents pose a constant threat to the existence of any free program. We wish to make sure that a company cannot effectively restrict the users of a free program by obtaining a restrictive license from a patent holder. Therefore, we insist that any patent license obtained for a version of the library must be consistent with the full freedom of use specified in this license. Most GNU software, including some libraries, is covered by the ordinary GNU General Public License. This license, the GNU Lesser General Public License, applies to certain designated libraries, and is quite different from the ordinary General Public License. We use this license for certain libraries in order to permit linking those libraries into non-free programs. When a program is linked with a library, whether statically or using a shared library, the combination of the two is legally speaking a combined work, a derivative of the original library. The ordinary General Public License therefore permits such linking only if the entire combination fits its criteria of freedom. The Lesser General Public License permits more lax criteria for linking other code with the library. We call this license the "Lesser" General Public License because it does Less to protect the user's freedom than the ordinary General Public License. It also provides other free software developers Less of an advantage over competing non-free programs. These disadvantages are the reason we use the ordinary General Public License for many libraries. However, the Lesser license provides advantages in certain special circumstances. For example, on rare occasions, there may be a special need to encourage the widest possible use of a certain library, so that it becomes a de-facto standard. To achieve this, non-free programs must be allowed to use the library. A more frequent case is that a free library does the same job as widely used non-free libraries. In this case, there is little to gain by limiting the free library to free software only, so we use the Lesser General Public License. In other cases, permission to use a particular library in non-free programs enables a greater number of people to use a large body of free software. For example, permission to use the GNU C Library in non-free programs enables many more people to use the whole GNU operating system, as well as its variant, the GNU/Linux operating system. Although the Lesser General Public License is Less protective of the users' freedom, it does ensure that the user of a program that is linked with the Library has the freedom and the wherewithal to run that program using a modified version of the Library. The precise terms and conditions for copying, distribution and modification follow. Pay close attention to the difference between a "work based on the library" and a "work that uses the library". The former contains code derived from the library, whereas the latter must be combined with the library in order to run. GNU LESSER GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any software library or other program which contains a notice placed by the copyright holder or other authorized party saying it may be distributed under the terms of this Lesser General Public License (also called "this License"). Each licensee is addressed as "you". A "library" means a collection of software functions and/or data prepared so as to be conveniently linked with application programs (which use some of those functions and data) to form executables. The "Library", below, refers to any such software library or work which has been distributed under these terms. A "work based on the Library" means either the Library or any derivative work under copyright law: that is to say, a work containing the Library or a portion of it, either verbatim or with modifications and/or translated straightforwardly into another language. (Hereinafter, translation is included without limitation in the term "modification".) "Source code" for a work means the preferred form of the work for making modifications to it. For a library, complete source code means all the source code for all modules it contains, plus any associated interface definition files, plus the scripts used to control compilation and installation of the library. Activities other than copying, distribution and modification are not covered by this License; they are outside its scope. The act of running a program using the Library is not restricted, and output from such a program is covered only if its contents constitute a work based on the Library (independent of the use of the Library in a tool for writing it). Whether that is true depends on what the Library does and what the program that uses the Library does. 1. You may copy and distribute verbatim copies of the Library's complete source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this License and to the absence of any warranty; and distribute a copy of this License along with the Library. You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. 2. You may modify your copy or copies of the Library or any portion of it, thus forming a work based on the Library, and copy and distribute such modifications or work under the terms of Section 1 above, provided that you also meet all of these conditions: a) The modified work must itself be a software library. b) You must cause the files modified to carry prominent notices stating that you changed the files and the date of any change. c) You must cause the whole of the work to be licensed at no charge to all third parties under the terms of this License. d) If a facility in the modified Library refers to a function or a table of data to be supplied by an application program that uses the facility, other than as an argument passed when the facility is invoked, then you must make a good faith effort to ensure that, in the event an application does not supply such function or table, the facility still operates, and performs whatever part of its purpose remains meaningful. (For example, a function in a library to compute square roots has a purpose that is entirely well-defined independent of the application. Therefore, Subsection 2d requires that any application-supplied function or table used by this function must be optional: if the application does not supply it, the square root function must still compute square roots.) These requirements apply to the modified work as a whole. If identifiable sections of that work are not derived from the Library, and can be reasonably considered independent and separate works in themselves, then this License, and its terms, do not apply to those sections when you distribute them as separate works. But when you distribute the same sections as part of a whole which is a work based on the Library, the distribution of the whole must be on the terms of this License, whose permissions for other licensees extend to the entire whole, and thus to each and every part regardless of who wrote it. Thus, it is not the intent of this section to claim rights or contest your rights to work written entirely by you; rather, the intent is to exercise the right to control the distribution of derivative or collective works based on the Library. In addition, mere aggregation of another work not based on the Library with the Library (or with a work based on the Library) on a volume of a storage or distribution medium does not bring the other work under the scope of this License. 3. You may opt to apply the terms of the ordinary GNU General Public License instead of this License to a given copy of the Library. To do this, you must alter all the notices that refer to this License, so that they refer to the ordinary GNU General Public License, version 2, instead of to this License. (If a newer version than version 2 of the ordinary GNU General Public License has appeared, then you can specify that version instead if you wish.) Do not make any other change in these notices. Once this change is made in a given copy, it is irreversible for that copy, so the ordinary GNU General Public License applies to all subsequent copies and derivative works made from that copy. This option is useful when you wish to copy part of the code of the Library into a program that is not a library. 4. You may copy and distribute the Library (or a portion or derivative of it, under Section 2) in object code or executable form under the terms of Sections 1 and 2 above provided that you accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Sections 1 and 2 above on a medium customarily used for software interchange. If distribution of object code is made by offering access to copy from a designated place, then offering equivalent access to copy the source code from the same place satisfies the requirement to distribute the source code, even though third parties are not compelled to copy the source along with the object code. 5. A program that contains no derivative of any portion of the Library, but is designed to work with the Library by being compiled or linked with it, is called a "work that uses the Library". Such a work, in isolation, is not a derivative work of the Library, and therefore falls outside the scope of this License. However, linking a "work that uses the Library" with the Library creates an executable that is a derivative of the Library (because it contains portions of the Library), rather than a "work that uses the library". The executable is therefore covered by this License. Section 6 states terms for distribution of such executables. When a "work that uses the Library" uses material from a header file that is part of the Library, the object code for the work may be a derivative work of the Library even though the source code is not. Whether this is true is especially significant if the work can be linked without the Library, or if the work is itself a library. The threshold for this to be true is not precisely defined by law. If such an object file uses only numerical parameters, data structure layouts and accessors, and small macros and small inline functions (ten lines or less in length), then the use of the object file is unrestricted, regardless of whether it is legally a derivative work. (Executables containing this object code plus portions of the Library will still fall under Section 6.) Otherwise, if the work is a derivative of the Library, you may distribute the object code for the work under the terms of Section 6. Any executables containing that work also fall under Section 6, whether or not they are linked directly with the Library itself. 6. As an exception to the Sections above, you may also combine or link a "work that uses the Library" with the Library to produce a work containing portions of the Library, and distribute that work under terms of your choice, provided that the terms permit modification of the work for the customer's own use and reverse engineering for debugging such modifications. You must give prominent notice with each copy of the work that the Library is used in it and that the Library and its use are covered by this License. You must supply a copy of this License. If the work during execution displays copyright notices, you must include the copyright notice for the Library among them, as well as a reference directing the user to the copy of this License. Also, you must do one of these things: a) Accompany the work with the complete corresponding machine-readable source code for the Library including whatever changes were used in the work (which must be distributed under Sections 1 and 2 above); and, if the work is an executable linked with the Library, with the complete machine-readable "work that uses the Library", as object code and/or source code, so that the user can modify the Library and then relink to produce a modified executable containing the modified Library. (It is understood that the user who changes the contents of definitions files in the Library will not necessarily be able to recompile the application to use the modified definitions.) b) Use a suitable shared library mechanism for linking with the Library. A suitable mechanism is one that (1) uses at run time a copy of the library already present on the user's computer system, rather than copying library functions into the executable, and (2) will operate properly with a modified version of the library, if the user installs one, as long as the modified version is interface-compatible with the version that the work was made with. c) Accompany the work with a written offer, valid for at least three years, to give the same user the materials specified in Subsection 6a, above, for a charge no more than the cost of performing this distribution. d) If distribution of the work is made by offering access to copy from a designated place, offer equivalent access to copy the above specified materials from the same place. e) Verify that the user has already received a copy of these materials or that you have already sent this user a copy. For an executable, the required form of the "work that uses the Library" must include any data and utility programs needed for reproducing the executable from it. However, as a special exception, the materials to be distributed need not include anything that is normally distributed (in either source or binary form) with the major components (compiler, kernel, and so on) of the operating system on which the executable runs, unless that component itself accompanies the executable. It may happen that this requirement contradicts the license restrictions of other proprietary libraries that do not normally accompany the operating system. Such a contradiction means you cannot use both them and the Library together in an executable that you distribute. 7. You may place library facilities that are a work based on the Library side-by-side in a single library together with other library facilities not covered by this License, and distribute such a combined library, provided that the separate distribution of the work based on the Library and of the other library facilities is otherwise permitted, and provided that you do these two things: a) Accompany the combined library with a copy of the same work based on the Library, uncombined with any other library facilities. This must be distributed under the terms of the Sections above. b) Give prominent notice with the combined library of the fact that part of it is a work based on the Library, and explaining where to find the accompanying uncombined form of the same work. 8. You may not copy, modify, sublicense, link with, or distribute the Library except as expressly provided under this License. Any attempt otherwise to copy, modify, sublicense, link with, or distribute the Library is void, and will automatically terminate your rights under this License. However, parties who have received copies, or rights, from you under this License will not have their licenses terminated so long as such parties remain in full compliance. 9. You are not required to accept this License, since you have not signed it. However, nothing else grants you permission to modify or distribute the Library or its derivative works. These actions are prohibited by law if you do not accept this License. Therefore, by modifying or distributing the Library (or any work based on the Library), you indicate your acceptance of this License to do so, and all its terms and conditions for copying, distributing or modifying the Library or works based on it. 10. Each time you redistribute the Library (or any work based on the Library), the recipient automatically receives a license from the original licensor to copy, distribute, link with or modify the Library subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. You are not responsible for enforcing compliance by third parties with this License. 11. If, as a consequence of a court judgment or allegation of patent infringement or for any other reason (not limited to patent issues), conditions are imposed on you (whether by court order, agreement or otherwise) that contradict the conditions of this License, they do not excuse you from the conditions of this License. If you cannot distribute so as to satisfy simultaneously your obligations under this License and any other pertinent obligations, then as a consequence you may not distribute the Library at all. For example, if a patent license would not permit royalty-free redistribution of the Library by all those who receive copies directly or indirectly through you, then the only way you could satisfy both it and this License would be to refrain entirely from distribution of the Library. If any portion of this section is held invalid or unenforceable under any particular circumstance, the balance of the section is intended to apply, and the section as a whole is intended to apply in other circumstances. It is not the purpose of this section to induce you to infringe any patents or other property right claims or to contest validity of any such claims; this section has the sole purpose of protecting the integrity of the free software distribution system which is implemented by public license practices. Many people have made generous contributions to the wide range of software distributed through that system in reliance on consistent application of that system; it is up to the author/donor to decide if he or she is willing to distribute software through any other system and a licensee cannot impose that choice. This section is intended to make thoroughly clear what is believed to be a consequence of the rest of this License. 12. If the distribution and/or use of the Library is restricted in certain countries either by patents or by copyrighted interfaces, the original copyright holder who places the Library under this License may add an explicit geographical distribution limitation excluding those countries, so that distribution is permitted only in or among countries not thus excluded. In such case, this License incorporates the limitation as if written in the body of this License. 13. The Free Software Foundation may publish revised and/or new versions of the Lesser General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Library specifies a version number of this License which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Library does not specify a license version number, you may choose any version ever published by the Free Software Foundation. 14. If you wish to incorporate parts of the Library into other free programs whose distribution conditions are incompatible with these, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS How to Apply These Terms to Your New Libraries If you develop a new library, and you want it to be of the greatest possible use to the public, we recommend making it free software that everyone can redistribute and change. You can do so by permitting redistribution under these terms (or, alternatively, under the terms of the ordinary General Public License). To apply these terms, attach the following notices to the library. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 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 Also add information on how to contact you by electronic and paper mail. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the library, if necessary. Here is a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the library `Frob' (a library for tweaking knobs) written by James Random Hacker. , 1 April 1990 Ty Coon, President of Vice That's all there is to it! ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/METADATA.in0000664000000000000000000000150315074674453014055 0ustar00rootrootMetadata-Version: 1.2 Name: PyGObject Version: @VERSION@ Summary: Python bindings for GObject Introspection Home-page: https://pygobject.gnome.org Author: James Henstridge Author-email: james@daa.com.au Maintainer: Simon Feltman Maintainer-email: sfeltman@src.gnome.org License: GNU LGPL Description: Python bindings for GObject Introspection Platform: POSIX, Windows Classifier: Development Status :: 5 - Production/Stable Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: GNU Lesser General Public License v2 or later (LGPLv2+) Classifier: Operating System :: POSIX Classifier: Operating System :: Microsoft :: Windows Classifier: Programming Language :: C Classifier: Programming Language :: Python Classifier: Topic :: Software Development :: Libraries :: Python Modules Requires-Python: >=3.9, <4 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/NEWS0000664000000000000000000055012515074674453013055 0ustar00rootroot3.50.2 - 2025-10-18 ------------------- * Backport: GLib 2.86/GioUnix compatibility :mr:`458` * Backport: async: Use correct T_BOOL type for _asyncio_future_blocking :mr:`367` * Backport: Revert "override connection.register_object to prevent an invocation object from leaking" :mr:`404` 3.50.1 - 2025-05-25 ------------------- * Backport: Fix event loop selector with Python 3.13 :mr:`423` 3.50.0 - 2024-09-12 ------------------- * tests: Fix event test errors when GTK is not installed :mr:`347` 3.49.0 - 2024-09-06 (pre-release) --------------------------------- * Rename master branch to main * Drop support for Python 3.8 :mr:`300` * Add Override for Gio.DataInputStream :mr:`293` * Treat GParamSpec as any other fundamental type :mr:`268` * override connection.register_object to prevent an invocation object from leaking :mr:`219` * Various PyPy related fixes :mr:`299` * bind_property: Accept keyword arguments :mr:`309` * Various documentation improvements :mr:`342` :mr:`343` :mr:`338` :mr:`336` :mr:`335` :mr:`328` :mr:`329` :mr:`330` :mr:`325` :mr:`322` :mr:`312` * Python2 / GTK2 cleanups :mr:`338` :mr:`331` * asyncio integration with support to await Gio async functions :mr:`189` * meson: move from .egg-info to .dist-info/METADATA :mr:`306` * build: fixes for building with gobject-introspection 1.81 :mr:`344` 3.48.2 - 2024-04-06 ------------------- * Fix support for fundamental (primitive) types, such as Gst.Bitmask :issue:`624` :mr:`304` 3.48.1 - 2024-03-10 ------------------- * Fix installation with pip failing in some environments with ModuleNotFoundError in g-ir-scanner :issue:`622` :mr:`302` 3.48.0 - 2024-03-09 ------------------- :Note: See 3.47.0 below for more details. * test: fix some tests on macOS :mr:`296` * docs: some dark mode fixes :mr:`291` 3.47.0 - 2024-02-12 (pre-release) --------------------------------- :Note: This is an unstable release. :Note: This is the first release using meson-python, and thus meson, instead of setuptools for PEP-517 installations i.e. when installing via pip or similar. Distro packagers can continue to use plain meson to build pygobject, but doing PEP-517 builds should also be possible with meson-python instead of setuptools. * Drop setuptools in favor of meson-python :mr:`248` :mr:`253` :mr:`254` :mr:`255` :mr:`276` * Fundamental type support :mr:`250` * Fundamental type support for GValues :mr:`264` * pygi-convert.sh: migrate FILE_CHOOSER_CONFIRMATION_* :mr:`266` * gimodule, cairo: Use multi-phase initialization as per PEP-489 :mr:`271` * Deprecate classes in gi.option module :mr:`272` * Deprecate pygtkcompat :mr:`278` * Add support for (optional) nullable GErrors :mr:`259` * Fix CssProvider not valid in GTK2 :mr:`284` * Fix double free if array item cannot be marshalled to Python :mr:`280` * Raise exception if a callback property is encountered :mr:`269` * build: Fix pycairo detection "script" for Windows :mr:`267` * Replace deprecated ``pkgutil.find_loader`` call :mr:`252` * Avoid segfault on property access for incompletely initialized objects :mr:`260` * pygenum: When getting a member instance, use correct key for the lookup :mr:`262` Project / Development / CI: * Remove pborelli from the maintainer list :mr:`251` * Add Arjan Molenaar to maintainers :mr:`256` * Remove runtests script :mr:`257` * test: build in a minimal environment without gtk :mr:`258` * CI: add a job for creating sdists :mr:`294` Documentation: * Build documentation on GitLab Pages :mr:`287` :mr:`289` * Update docs to use Furo theme :mr:`288` * Various docs improvements: :mr:`274` :mr:`281` :mr:`282` :mr:`285` :mr:`286` :mr:`292` 3.44.2 - 2023-09-29 ------------------- * Add support for Python 3.12 (minor test fixes) :mr:`247` * meson: define pycairo_dep in case pycairo=disabled :mr:`242` * Complete the PEP-451 implementation in gi.importer :mr:`229` * Replace usage of deprecated FFI closure API :mr:`241` * Fix invalid marshalling in some cases for boxed values, for example with Gtk.StyleContext.get_property() :mr:`213` * overrides: Allow Gdk.{Color,RGBA} instances to be compared with other objects :mr:`233` * docs: Fix build failure due to extlinks with Sphinx 6 :mr:`244` 3.46.0 - 2023-09-10 ------------------- * build: Drop Python 3.7 support :mr:`238` * build: Require glib 2.64 and gobject-introspection 1.64 :mr:`243` * Add support for Python 3.12 (minor test fixes) :mr:`247` * Drop GTK 2 support (after being effectively unsupported for 12 years) :mr:`182` * meson: Require meson 0.56.0 :mr:`220` * meson: Set PYTHONPATH in devenv :mr:`235` * meson: define pycairo_dep in case pycairo=disabled :mr:`242` * meson: Use pycairo from target python before pkg-config :mr:`223` * Complete the PEP-451 implementation in gi.importer :mr:`229` * Replace usage of deprecated FFI closure API :mr:`241` * Fix invalid marshalling in some cases for boxed values, for example with Gtk.StyleContext.get_property() :mr:`213` * Consistent setting of enum and flag property :mr:`192` * Fix docstring for methods that return an array and have a length (out) argument :mr:`249` * overrides: Fix incompatibility for CssProvider.load_from_data() (GTK 4.10) :mr:`231` * overrides: Allow Gdk.{Color,RGBA} instances to be compared with other objects :mr:`233` * overrides: Add overrides for Gdk.FileList in Gdk-4.0 :mr:`245` * docs: Fix underline too short warning :mr:`246` * docs: Fix build failure due to extlinks with Sphinx 6 :mr:`244` * docs: List additional projects using PyGObject :mr:`230` * docs: Update Development Environment Docs :mr:`232` * docs: Update docs and code examples to GTK 4 :mr:`215` 3.44.1 - 2023-03-24 ------------------- * Fix tests with glib 2.76 :mr:`240` 3.44.0 - 2023-03-19 ------------------- No changes compared to 3.43.1 3.43.1 - 2023-01-28 ------------------- * Note: PyGObject is in need of more maintainers, please read https://www.bassi.io/articles/2022/12/02/on-pygobject/ * Note: This is an unstable release. * Drop support for Python 3.6 :mr:`184` * meson: bump minimum version to 0.53.0 and update subprojects :mr:`227` * gimodule: fix floating state of python objects created with g_object_new :mr:`129` * Gtk.Template: Accept PathLike objects as a filename :mr:`195` * info: Show which type/object callables are bound to :mr:`194` * IntrospectionModule: handle two threads loading type at same time :mr:`149` * Port to Py_TRASHCAN_BEGIN :mr:`226` * Other cleanups/improvements: :mr:`181` :mr:`173` * This release also includes all changes from 3.42.1 and 3.42.2 3.42.2 - 2022-07-16 ------------------- * Error out instead of crashing when marshaling unsupported fundamental types in some cases :mr:`180` * Add a workaround for a PyPy 3.9+ bug when threads are used :mr:`200` * Fix crashes when marshaling zero terminated arrays for certain item types :mr:`191` * Fix a crash/refcounting error in case marshaling a hash table fails :mr:`191` * Make the test suite pass again with PyPy :mr:`191` * tests: support running tests with (MSVC) CPython 3.8+ on Windows :mr:`206` * interface: Fix leak when overriding GInterfaceInfo :mr:`204` * setup.py: look up pycairo headers without importing the module (helps with building on Windows and MSVC CPython 3.8+) :mr:`205` 3.42.1 - 2022-04-17 ------------------- * Do not error out for unknown scopes :mr:`179` * gtk overrides: restore Gtk.ListStore.insert_with_valuesv with newer gtk4 :issue:`467` * gtk overrides: Do not override Treeview.enable_model_drag_xx for GTK4 :mr:`175` * Implement DynamicImporter.find_spec() to silence a deprecation warning with Python 3.10 :issue:`473` * Some test/CI fixes 3.42.0 - 2021-09-19 ------------------- * meson: Bump minimum meson_version to 0.47.0 * Expose GObject.Object.run_dispose() :issue:`470` * docs: document Gtk.Template. :issue:`396` * dev: Add poetry support * meson: use main branch for glib subproject * Fix some small memory leaks :mr:`178` 3.40.1 - 2021-03-30 ------------------- * Fix tests with glib 2.68 :mr:`166` * Fix a regression with marshalling partial() objects :mr:`165` :issue:`464` 3.40.0 - 2021-03-19 ------------------- * GTK 4 compatibility fixes :mr:`148` :mr:`159` :mr:`144` :mr:`145` * Python 3.9 and 3.10 compatibility fixes :mr:`152` :mr:`156` * New minimal dependency requirements due to dropping support for Ubuntu 16.04 :mr:`151` * Python 3.6+ * glib 2.56+ * gobject-introspection 1.56+ * pycairo 1.16+ 3.38.0 - 2020-09-12 ------------------- * Python 2 is no longer supported. Note for distros/packagers: In case you want to keep Python 2 support you'll likely split any existing package into a Python 2 and 3 version. Since these aren't parallel installable here are some recommendations on how to make it work: * Build the devel package from the Python 3 source package * Drop the headers/.pc files from the Python 2 build/package * Make sure no Python 2 using package depends on the devel package (@Arch: gnumeric can be build without Python support for example) See :issue:`392` for details * meson: Make the `pycairo` option a feature :mr:`146` :mr:`147` * gdk overrides: Fix wrapping of scroll events :mr:`141` * Add overrides for Gtk.Button set/get_focus_on_click :mr:`132` 3.36.1 - 2020-05-06 ------------------- * tests: Fix failing tests with pytest 5.4.0+ * Gtk: Add override to make sure both TreeModelSort.new_with_model and TreeModel.sort_new_with_model exist independend of the gtk version * Gtk.Template: Fix initialisation order errors with Widgets getting created from C (potentially through other templates) :issue:`257` :issue:`386` :issue:`341` :mr:`140` (:user:`Jean Felder `) * Gtk.Template: Fix errors when calling init_template() multiple times :mr:`140` (:user:`Jean Felder `) 3.36.0 - 2020-03-08 ------------------- This will be the last release supporting Python 2. * pygobject-object: Avoid checking whether NULL is floating :mr:`135` (:user:`Alexandru BăluÈ› `) * Avoid various new glib deprecation warnings * Port to g_object_new_with_properties() * Drop Python 2 support on Windows * gtk overrides: Drop Menu, MenuItem for Gtk 4 (:user:`Marinus Schraal `) * Docs: * Update openSUSE instructions (:user:`sharkwouter`) * Add Gaphor to Who is Using PyGObject (:user:`Dan Yeaw `) * Remove reference to a fixed bug (:user:`Christian Stadelmann `) 3.34.0 - 2019-09-09 ------------------- * No changes since 3.33.1 3.33.1 - 2019-08-18 ------------------- * Make GLib.Variant.unpack a bit less costly :mr:`121` (:user:`Mathieu Bridon `) * pygobject: ignore GParameter deprecations :mr:`122` (:user:`Christian Hergert `) * pygobject-object: fix refcount of floating return values :mr:`120` (:user:`Mathieu Duponchelle `) * pygi-info: remove some dead code :issue:`303` 3.32.2 - 2019-06-23 ------------------- * Python 3.8b1 compatibility fixes * tests: fix a test error when run under wayland * setup.py: specify python_requires 3.30.5 - 2019-06-16 ------------------- * tests/gimarshallingtestsextra.c/h: relicense to LGPLv2.1+ :issue:`320` * Fix a crash when marshalling a GError to Python fails :mr:`115` * Fix leak of transfer-full/container C arrays :mr:`117` (:user:`Tomasz MiÄ…sko `) * Python 3.8b1 compatibility fixes 3.32.1 - 2019-04-20 ------------------- * tests/gimarshallingtestsextra.c/h: relicense to LGPLv2.1+ :issue:`320` * meson: add ``tests`` option for disabling tests :mr:`113` (:user:`Adam Duskett `) * meson: tests: pass ``--quiet`` to g-ir-scanner :mr:`114` (:user:`Tim-Philipp Müller `) * Fix a crash when marshalling a GError to Python fails :mr:`115` * Fix leak of transfer-full/container C arrays :mr:`117` (:user:`Tomasz MiÄ…sko `) 3.32.0 - 2019-03-10 ------------------- * No changes since 3.31.4 3.31.4 - 2019-03-07 ------------------- * docs: document GObject.Object.weak_ref() :issue:`245` * cairo: Add cairo pattern foreign struct support :mr:`111` (:user:`Renato Florentino Garcia `) * cairo: Add cairo_matrix_t converter to GValue :mr:`112` (:user:`Renato Florentino Garcia `) 3.31.3 - 2019-02-02 ------------------- * Speed up destruction of boxed types :mr:`106` and GObject.Value.set_value() calls. This makes appending to a Gtk.TreeModel nearly twice as fast for example :issue:`46`, :issue:`218` * Allow passing None for boolean parameters * meson: Install .egg-info directory to arch'd dir. :mr:`109` (:user:`Elliott Sales de Andrade `) * gtk overrides: raise in case Gtk.Window is instantiated after gtk_init failed :issue:`298` * gio overrides: Warn when creating various dbus types without a constructor :issue:`15` * tests: Fix tests with glib 2.59.x :issue:`287` * tests: fix test_atoms failing in some environments :issue:`300` 3.31.2 - 2018-12-15 ------------------- * Changes included in 3.30.4 * GLib.Variant.keys: correctly raise TypeError for non-dict types * GLib.Variant: implement __bool__ for maybe types * cairo: Fix GValue converters in case of NULL * setup.py: Print an install command hint when pkg-config is missing * pygi-info: wrap g_union_info_get_alignment() :mr:`105` (:user:`Tomasz MiÄ…sko `) 3.30.4 - 2018-11-30 ------------------- * gtk overrides: Fix rows getting inserted on the wrong level with TreeStore.insert_before/insert_after if parent=None. :issue:`281` (3.30 regression, thanks to :user:`Cian Wilson ` for the report) 3.30.3 - 2018-11-27 ------------------- * GValue: fall back to the custom C marshaller to support fundamental types. This makes GValue work with GstFraction. :issue:`280` * GValue: Work around wrong annotations for GVariant * Fix GObject attribute access during instance init which can lead to errors with __getattr__ implementations of subclasses. This lead to criticals when instantiating Gio.DBusProxy. :issue:`267` 3.31.1 - 2018-11-17 ------------------- * Changes included in 3.30.2 * overrides: add Pango.Layout.set_text() override. :issue:`259` :mr:`89` * docs: link updates :mr:`93` (:user:`tijder`) * overrides: Use functools.wraps instead of custom version. :issue:`271` :mr:`95` (:user:`Kai Willadsen `) * tests: Make tests run with current gtk4 master * Add (again) a pyproject.toml for specifying the pycairo build dep (requires pip >=18.0) * setup.py: Make it possible to build without cairo support through the PYGOBJECT_WITHOUT_PYCAIRO env var. :issue:`250` 3.30.2 - 2018-11-11 ------------------- * tests: Fix some test with newer glib. * overrides: Fix crash when using non-ascii text with. Gtk.Builder.add_from_string/add_objects_from_string. :issue:`255` * Various meson/distutils build fixes for MSVC. :mr:`91` (:user:`Chun-wei Fan `) * foreign-cairo: Fix cairo marshalling not using the foreign converters in some cases. :issue:`260` * build: setup.py reproducible build fixes. :mr:`94` (:user:`Bernhard M. Wiedemann `) 3.30.1 - 2018-09-14 ------------------- * Fix various crashes on big endian systems. :issue:`247` (:user:`Dan Horák `) * meson: Don't link against libpython on non-Windows systems. :issue:`253` :mr:`84` 3.30.0 - 2018-08-31 ------------------- * Various test suite fixes to get things to pass with Ubuntu 18.10. 3.29.3 - 2018-08-16 ------------------- * meson: Support building pycairo as a subproject. :mr:`76` * meson: Declare_dependency for use by potential superprojects (:user:`Mathieu Duponchelle `) * meson: Update glib wrap file. :mr:`80` (:user:`Carlos Soriano `) * meson: Fix the Python 2 build not not use the system pycairo extension when running tests. :issue:`242` * pygi-convert.sh: Various fixes and updates. :mr:`77` :mr:`78` (:user:`Sander Sweers `) * Gtk.Template: Fix instantiation error when using the new code with older PyGObject. :mr:`79` (:user:`Kai Willadsen `) * Gtk.Template: Don't error out when loading a resource that is only available in an overlay. :issue:`230` * Fix various crashes when running against a debug Python 3.7 build. :mr:`82` (:user:`Simon McVittie `) * overrides: Allow calling GObject.Binding.unbind() multiple times with GLib 2.58+. :issue:`240` * overrides: Gio.ListStore overrides use splice() when adding/removing many items with GLib 2.58+. :issue:`115` :mr:`83` * Work around pylint reporting bogus warnings regarding a missing self argument for normal functions. :issue:`217` * Add override for GdkPixbuf.Pixbuf.new_from_data() to wrap new_from_bytes() to work around a use after free. :issue:`225` :mr:`74` 3.28.3 - 2018-05-31 ------------------- * Fix Gio.Application leak in case no signal handler is set before. :issue:`219` * Squash critical warning when using array as hash value (:user:`Philip Withnall `) 3.29.2 - 2018-05-16 ------------------- * Add a meson build system. :issue:`165` (:user:`Mathieu Duponchelle`) * Gtk.Template: Allow marking children as "internal-child". :mr:`58` * Gio.ListModel: implement most of the mutable sequence protocol. :issue:`115` :mr:`59` * Gio.Settings: implement __iter__. * Gio.Settings: support range types in __setitem__. :issue:`134` * Add overrides for Gio.ListStore.sort and Gio.ListStore.insert_sorted. :issue:`130` * Make Gtk.Widget.freeze_child_notify a context manager. :issue:`45` * OptionParser.parse_args: return leftover arguments. :issue:`200` * Release the GIL when emitting a signal. :mr:`66` (John Bassett ) * Add ActionMap and ActionMap.add_action_entries() to overrides. :issue:`29` :mr:`65` (:user:`yangfl`) * importer: raise ImportError in load_module() and not find_module(). :issue:`213` * Don't wrap GValue in GValue when creating GValueArray. :mr:`66` (Stian Selnes ) * ossig: Don't leak the callbacks in case the event loops are not stopped through SIGINT. :issue:`219` :mr:`72` * Various fixes (Havard Graff ) * Destroy custom GLib.Source instances when they get freed. :issue:`193` * Revert "Add PEP518/pyproject.toml file", fixes installation with pip 10, see https://github.com/pypa/pip/issues/5244 * Various fixes/improvements for PyPy. * Don't crash on multiple calls to GObject.Value.__del__. :mr:`66` Documentation: * Added StackOverflow (with PyGObject tag) as an contact resource. (:user:`buhtz`) * Add introduction to handling GLib.Error. :mr:`68` (:user:`Kai Willadsen `) * Add pycairo requires for development setup. :mr:`70` (:user:`Kai Willadsen `) 3.29.1 - 2018-04-15 ------------------- * Support for `PyPy `__ and PyPy3. :issue:`180` * cairo: support :class:`cairo.Matrix` conversion. :issue:`16` * Speed up repeated closure creation by caching the closure cache in the argument cache :issue:`103` (:user:`Garrett Regier `\, :user:`Christoph Reiter `) * setup.py: make setuptools/pkg_resources optional. :issue:`186` * setup.py: print installation instructions in case a dependency is missing. :issue:`194` * Remove autotools build system. * overrides: Make :meth:`Gtk.ListStore.insert_before`, :meth:`Gtk.ListStore.insert_after`, :meth:`Gtk.TreeStore.insert_before` and :meth:`Gtk.TreeStore.insert_after` atomic. * Make :class:`GLib.Error` picklable. :issue:`145` * Add basic support for template based widgets through ``Gtk.Template``. :issue:`52` * Various documentation improvements. :mr:`29` (:user:`Dan Yeaw `) * Add PEP518/pyproject.toml file. :mr:`44` (:user:`James Tocknell `) * Avoid truncating value returned from g_value_info_get_value. :mr:`51` (:user:`Tomasz MiÄ…sko `) * Fix typo in BoundSignal disconnect. :mr:`55` (:user:`Vladislav Glinsky `) 3.28.2 - 2018-03-27 ------------------- * setup.py: Don't install the test C extension when it's built. :issue:`181` * setup.py: Always define PY_SSIZE_T_CLEAN. :issue:`185` * Fix __str__ return type of Gtk.TreePath with depth == 0. :issue:`143` * Fix a crash when setting a str property with a value containing surrogates. :issue:`169` * tests: Fix a potential crash during tests 3.28.1 - 2018-03-17 ------------------- * Fix a GValue leak (regression). :issue:`176` (:user:`Mathieu Duponchelle`) * setup.py: don't install the tests package * Various fixes for 64bit Windows. :mr:`34` (:user:`Mathieu Duponchelle`) * Fix tests with glib 2.56.0 * Various fixes for Python 3.7. :issue:`170` :mr:`28` 3.28.0 - 2018-03-12 ------------------- * GLib.Variant: Fix creation of guchar arrays from bytes (3.27.2 regression). :issue:`174` :mr:`30` 3.27.5 - 2018-03-01 ------------------- * Re-revert transfer-none boxed copy changes (:mr:`23`). Now with more fixes and tests. :mr:`24` (:user:`Mathieu Duponchelle `) * Add caching for boxed type lookup and try to avoid the import lock. :mr:`13` (:user:`Mikhail Fludkov `) 3.27.4 - 2018-02-14 ------------------- * tests: Fix tests under Wayland. :issue:`163` * tests: Make it possible to use pytest directly. * Reverted transfer-none boxed copy changes (:mr:`10`) due to regressions in gnome-music. :issue:`164` :mr:`23` 3.27.3 - 2018-02-10 ------------------- * Fix a 3.27.2 regression where functions return invalid boxed values. :mr:`16` (thanks to :user:`Mikhail Fludkov ` for providing a test) * tests: Make tests run without Gtk/Gdk installed. :mr:`17` (:user:`Mikhail Fludkov `) * tests: Remove dependency on ``localedef``. :commit:`64b02e301` * tests: Require/Use pytest. :mr:`20` :issue:`153` 3.27.2 - 2018-02-07 ------------------- * setup.py: Add a "quality" command which is equal to "make check.quality". * setup.py: Add a "test" command which is equal to "make check". :mr:`5` * setup.py: Install pkg-config and header files. * setup.py: Improve pycairo header lookup with pycairo >=1.16. :issue:`150` * autotools: "make check.quality" now requires flake8. * overrides: Fix ``Gtk.Adjustment.__init__()`` overrides not setting "value" sometimes. :issue:`151` :mr:`3` * overrides: ``GLib.Variant``: add support to create maybe types. :issue:`152` :mr:`4` (:user:`Alberto Ruiz `) * Make it possible to resolve ambiguous vmethod names. Ambiguities can be resolved by implementing methods named "do_$namespaced_base_class_name_$vfunc_name". :mr:`9` :issue:`105` (:user:`Mathieu Duponchelle `) * Fix setting a property installed in Python from C in some cases. :mr:`8` (:user:`Mathieu Duponchelle `) * pygobject-object: fix memory corruption around list of closures. :mr:`12` :issue:`158` (:user:`Mikhail Fludkov `) * Don't copy the boxed if we are the sole owner of the wrapper after a closure. :mr:`14` * Only copy transfer-none boxed values in closures once the closure exists. This allows modifying the passed boxed while allowing to keep the wrapper around after the closure is done. :mr:`10` (:user:`Mathieu Duponchelle `) 3.27.1 - 2017-12-11 ------------------- * Revert "setup.py: Also set setup_requires to require pycairo" (Christoph Reiter) * setup.py: Also set setup_requires to require pycairo (Christoph Reiter) * setup.py: Provide a os.path.samefile fallback for Python 2 under Windows (Christoph Reiter) * Add sphinx based documentation (Christoph Reiter) (:bzbug:`791448`) * PKG-INFO: Revert name back to PyGObject (Christoph Reiter) * setup.py: Rework pycairo discovery to not use pkg-config (Christoph Reiter) * setup.py: Fix the distcheck command on Windows (Christoph Reiter) * setup.py: Remove various classifiers and the download-url which aren't accepted by pypi (Christoph Reiter) * version bump (Christoph Reiter) 3.27.0 - 2017-12-08 ------------------- * demo: pep8 fixes (Christoph Reiter) * Fix ctypes.PyDLL construction under Windows (Christoph Reiter) (:bzbug:`622084`) * configure.ac: Error out in case autoconf-archive isn't installed (Christoph Reiter) (:bzbug:`784428`) * Move pygi-convert.sh into tools (Christoph Reiter) * README: Convert to reST (Christoph Reiter) * demo: Move demo into examples and dist it (Christoph Reiter) (:bzbug:`735918`) * demo: Add new Gtk.FlowBox example (Gian Mario Tagliaretti) (:bzbug:`735918`) * demo: Use HeaderBar for main app window (Simon Feltman) (:bzbug:`735918`) * demo: PyFlakes and PEP8 fixes (Simon Feltman) (:bzbug:`735918`) * demo: Rename gtk-demo.py to demo.py (Simon Feltman) (:bzbug:`735918`) * demo: Rename demos/gtk-demo to simply demo (Simon Feltman) (:bzbug:`735918`) * Remove AUTHORS file (Christoph Reiter) * Remove pre-commit.hook (Christoph Reiter) * setup.py: Port to distutils/setuptools (Christoph Reiter) (:bzbug:`789211`) * Install a default SIGINT handler for functions which start an event loop (Christoph Reiter) (:bzbug:`622084`) * Make Python OS signal handlers run when an event loop is idling (Christoph Reiter) (:bzbug:`622084`) * Drop Python 3.3 support (Christoph Reiter) (:bzbug:`790787`) * Drop set_value usage in Gtk.List/TreeStore.set override (Sander Sweers) (:bzbug:`790346`) * pygobject-object: Fix Python GC collecting a ref cycle too early (Christoph Reiter) (:bzbug:`731501`) * Fix potential uninitialized memory access during GC (Daniel Colascione) (:bzbug:`786872`) * test: revert parts of the previous test as it's broken on 32 bit builds (Christoph Reiter) (:bzbug:`786948`) * flags: Add testcase for bug 786948 (Christoph Reiter) (:bzbug:`786948`) * fix potential overflow when marshalling flags from py interface (Philippe Renon) (:bzbug:`786948`) * to_py_array: Properly handle enum array items (Christoph Reiter) (:bzbug:`788890`) * pygobject.doap: Add myself as maintainer (Christoph Reiter) * closure: Fix unaligned and out-of-bounds access (James Clarke) (:bzbug:`788894`) * build: Fix not installing .egg-info file (Christoph Reiter) (:bzbug:`777719`) * Drop pygobject-3.0-uninstalled.pc file (Christoph Reiter) * tests: Windows fix (Christoph Reiter) * tests: some more C locale fixes (Christoph Reiter) * tests: Make the test suite pass with the C locale (Christoph Reiter) * configure.ac: post-release version bump to 3.27.0 (Christoph Reiter) 3.26.1 - 2017-10-27 ------------------- * pygobject-object: Fix Python GC collecting a ref cycle too early (Christoph Reiter) (:bzbug:`731501`) * Fix potential uninitialized memory access during GC (Daniel Colascione) (:bzbug:`786872`) * test: revert parts of the previous test as it's broken on 32 bit builds (Christoph Reiter) (:bzbug:`786948`) * flags: Add testcase for bug 786948 (Christoph Reiter) (:bzbug:`786948`) * fix potential overflow when marshalling flags from py interface (Philippe Renon) (:bzbug:`786948`) * to_py_array: Properly handle enum array items (Christoph Reiter) (:bzbug:`788890`) * closure: Fix unaligned and out-of-bounds access (James Clarke) (:bzbug:`788894`) * build: Fix not installing .egg-info file (Christoph Reiter) (:bzbug:`777719`) * configure.ac: version bump to 3.26.1 (Christoph Reiter) 2.28.7 - 2017-10-13 ------------------- * Move property and signal creation into _class_init() (Martin Pitt) * gio-types.defs: change some enums to flags (Ryan Lortie) * Fix set_qdata warning on accessing NULL gobject property (Ivan Stankovic) * Disable introspection support by default (Dieter Verfaillie) * Don't install codegen for Python 3 (Arfrever Frehtes Taifersar Arahesis) * Ship tests/te_ST@nouppera in release tarballs for tests to succeed (Martin Pitt) * [gi] Port test_properties from static gio to GI Gio (Martin Pitt) * [python3] fix build. PYcairo_IMPORT doesn't exists anymore (Ignacio Casal Quinteiro) * [python3] Fix maketrans import (Martin Pitt) * [gi-overrides] fix MessageBox so it correctly handles the type constructor param (John (J5) Palmieri) * gdbus tests: Fix hang if test case fails (Martin Pitt) * Fix crash in Gtk.TextIter overrides (Martin Pitt) * correctly initialize the _gi_cairo_functions array to be zero filled (John (J5) Palmieri) * [gtk-override] print warning if user imports Gtk 2.0 (John (J5) Palmieri) * Add support for enums in gobject.property (Johan Dahlin) 3.26.0 - 2017-09-12 ------------------- * configure.ac: pre-release version bump to 3.26.0 (Christoph Reiter) * closure: silence a new compiler warning (Christoph Reiter) * tests: skip some failing test under Windows with Python 3.6 (Christoph Reiter) * tests: pyflakes/pep8 fixes (Christoph Reiter) * tests: Fix cairo test with pycairo >= 1.13 (Christoph Reiter) * Make sure version information passed to require_version is a string. (Benjamin Berg) (:bzbug:`781582`) * configure.ac: post-release version bump to 3.25.2 (Christoph Reiter) 3.25.1 - 2017-04-21 ------------------- * Bump pycairo requirement to 1.11.1 (Christoph Reiter) (:bzbug:`707196`) * configure.ac: Always disable -Werror (Christoph Reiter) * foreign-cairo: Enable cairo.Region support also on Python 2 if available (Christoph Reiter) * configure.ac: remove unused PLATFORM variable (Christoph Reiter) * configure.ac: Remove unused PySignal_SetWakeupFd check (Christoph Reiter) * tests: remove python 2.5/3.2 compat code (Christoph Reiter) * configure.ac: Require Python 3.3 (Christoph Reiter) * tests: Make test suite run with GTK+ 4 (Christoph Reiter) * tests: always call require_version; add TEST_GTK_VERSION env var (Christoph Reiter) * tests: Fix make check.valgrind (Christoph Reiter) * tests: Don't skip Regress tests when cairo is missing (Christoph Reiter) * tests: fix invalid regex escaping (Christoph Reiter) * tests: avoid mapping a GtkWindow (Christoph Reiter) (:bzbug:`780812`) * tests: silence some glib deprecation warnings (Christoph Reiter) (:bzbug:`780812`) * tests: avoid deprecation warnings for assertRegexpMatches/assertRaisesRegexp (Christoph Reiter) (:bzbug:`780812`) * pygi-source: clear exceptions in finalize handler (Christoph Reiter) (:bzbug:`780812`) * Fix pep8 errors (Christoph Reiter) * Remove gi._gi._gobject and gi._gobject modules (Christoph Reiter) (:bzbug:`735206`) * Remove gi._gi._glib module (Christoph Reiter) (:bzbug:`735206`) * GValue: add overflow checking for py -> gint; forward marshaling exceptions (Christoph Reiter) (:bzbug:`769789`) * pygobject_lookup_class: clear exceptions between calls and don't return with one set (Christoph Reiter) (:bzbug:`773394`) * Avoid some new deprecation warnings (Christoph Reiter) (:bzbug:`780768`) * Raise RuntimeError in case an uninitilialized GObject.Object is marshaled (Christoph Reiter) (:bzbug:`730908`) * closure: support unichar args (Christoph Reiter) (:bzbug:`759276`) * Add support for bytes and non-utf-8 file names. (Christoph Reiter) (:bzbug:`746564`) * test_gi: use correct min/max constants for gsize/gssize (Christoph Reiter) (:bzbug:`780591`) * Don't use long format string for formatting pointers (Christoph Reiter) (:bzbug:`780591`) * Fix conversion from pointers to hashfunc return values. (Christoph Reiter) (:bzbug:`780591`) * Fix PyLong <-> GPid conversion on 64bit Windows (Christoph Reiter) (:bzbug:`780591`) * property: support setting flags (Christoph Reiter) (:bzbug:`726484`) * overrides: warn on instantiation of Gio.VolumeMonitor (Christoph Reiter) (:bzbug:`744690`) * Remove gi.overrides.overridefunc (Christoph Reiter) (:bzbug:`686835`) * tests: Reduce usage of timeout_add() and sleep() (Christoph Reiter) (:bzbug:`698548`) * tests: Remove TestMainLoop.test_concurrency (Christoph Reiter) (:bzbug:`698548`) * Update .gitignore: add ``*.dll``, ``*.dylib``, ``.DS_STORE`` (Christoph Reiter) * tests: Make test suite run on Windows (Christoph Reiter) (:bzbug:`780396`) * tests: Make test suite run on macOS (Christoph Reiter) (:bzbug:`780396`) * Fix various compiler warnings for 32bit builds (Christoph Reiter) (:bzbug:`780409`) * pep8 fix (Christoph Reiter) * testhelper: only link against libpython on Windows (Christoph Reiter) (:bzbug:`773803`) * overrides: Fix Gtk.TextBuffer.insert_with_tags_by_name() with no tags (Garrett Regier) (:bzbug:`772896`) * Make use of instance-argument annotations (Christoph Reiter) (:bzbug:`735076`) * Remove pyglib_gil_state_ensure/pyglib_gil_state_release (Christoph Reiter) (:bzbug:`699440`) * Remove support for building without threads (Christoph Reiter) (:bzbug:`699440`) * pygtkcompat: Allow multiple calls to enable(), enable_gtk() as long as the version matches (Christoph Reiter) (:bzbug:`759009`) * tests: Update Makefile for building tests on OS X (Simon Feltman) (:bzbug:`762176`) * testhelper: propagate exception if _gobject could not be imported (Mikhail Fludkov) (:bzbug:`772949`) * pygi-info: initialize GIArgument before passing it to g_constant_info_get_value (Christoph Reiter) (:bzbug:`772949`) * tests: build libregress with disabled cairo (Mikhail Fludkov) (:bzbug:`772949`) * tests: use g-ir utils found by pkg-config (Mikhail Fludkov) (:bzbug:`772949`) * Add a foreign type for cairo_region_t. (Shyouzou Sugitani) (:bzbug:`667959`) * aclocal: make local file discover by reading AC_CONFIG_MACRO_DIR work (Christoph Reiter) (:bzbug:`777713`) * Port from gnome-common to autoconf-archive (Christoph Reiter) (:bzbug:`777713`) * Fix various potential compiler warnings (Christoph Reiter) (:bzbug:`777713`) * configure.ac: post-release version bump to 3.25.0 (Christoph Reiter) * Remove egg make target (Christoph Reiter) (:bzbug:`777719`) * Remove legacy docs (Christoph Reiter) (:bzbug:`777719`) 3.24.1 - 2017-04-10 ------------------- * pygi-info: initialize GIArgument before passing it to g_constant_info_get_value (Christoph Reiter) (:bzbug:`772949`) * configure.ac: post-release version bump to 3.24.1 (Christoph Reiter) 3.24.0 - 2017-03-20 ------------------- * configure.ac: pre-release version bump to 3.24.0 (Christoph Reiter) 3.23.92 - 2017-03-13 -------------------- * overrides: Update for Gdk-4.0 and Gtk+-4.0 (Fabian Orccon) (:bzbug:`777680`) * Disable -Werror=missing-prototypes (Christoph Reiter) (:bzbug:`777534`) * Fix new PEP8 errors (Christoph Reiter) (:bzbug:`776009`) * Move pep8/pyflakes tests from 'make check' to 'make check.quality' (Christoph Reiter) (:bzbug:`764087`) * overrides: Update for Gtk-4.0 (Christoph Reiter) (:bzbug:`773315`) * Handle exception unreffing Variant at exit (Dan Nicholson) (:bzbug:`776092`) * Handle multiple deinit of callable cache (Dan Nicholson) (:bzbug:`776092`) * configure.ac: post-release version bump to 3.23.0 (Christoph Reiter) 3.22.0 - 2016-09-19 ------------------- * configure.ac: pre-release version bump to 3.22.0 (Christoph Reiter) 3.21.92 - 2016-09-11 -------------------- * Handle nullable filename parameters (Christoph Reiter) (:bzbug:`770821`) * Fix list/hashtable enum <-> hash conversion on 64-bit big endian (Aurelien Jarno) (:bzbug:`770608`) * Allow passing sockets to io_add_watch on win32 (Lukas K) (:bzbug:`766396`) * tests: use dbus-run-session instead of dbus-launch to run tests (Michael Biebl) (:bzbug:`770798`) * configure.ac: post-release version bump to 3.21.92 (Christoph Reiter) 3.21.91 - 2016-08-25 -------------------- * Allow installing with pip (Mathieu Bridon) (:bzbug:`767988`) * Skip a test with older glib (Christoph Reiter) (:bzbug:`740301`) * Fix a test with Python 3.1/3.2 (Arfrever Frehtes Taifersar Arahesis, Christoph Reiter) (:bzbug:`740324`) * tests: Use places kwarg for assertAlmostEqual (Arfrever Frehtes Taifersar Arahesis, Christoph Reiter) (:bzbug:`740337`) * Print exception if marshalling a signal argument fails (Christoph Reiter) (:bzbug:`748198`) * overrides: allow treemodel sequence shorthands (Marinus Schraal) (:bzbug:`766580`) * Remove pygobject-external.h (Christoph Reiter) (:bzbug:`767084`) * Remove pygobject-private.h and rename pygobject.c to pygobject-object.c (Christoph Reiter) (:bzbug:`767084`) * Merge pyglib-private.h into pyglib.h (Christoph Reiter) (:bzbug:`767084`) * Remove pygi.h and pygi-private.h (Christoph Reiter) (:bzbug:`767084`) * configure.ac: post-release version bump to 3.21.1 (Simon Feltman) 3.21.0 - 2016-04-24 ------------------- * gi: Add require_versions() function (Dustin Falgout) (:bzbug:`761141`) * test_gerror_novalue: Don't assign the error to a variable (Iain Lane) (:bzbug:`764165`) * build: Do not enable code coverage based on lcov (Emmanuele Bassi) (:bzbug:`764075`) 3.20.1 - 2016-04-24 ------------------- * test_gerror_novalue: Don't assign the error to a variable (Iain Lane) (:bzbug:`764165`) 3.20.0 - 2016-03-21 ------------------- 3.19.92 - 2016-03-15 -------------------- 3.19.91 - 2016-03-01 -------------------- * Fix marshaling of GError stored in GValue (Simon Feltman) (Thibault Saunier) (:bzbug:`761592`) * Fix marshaling or GError from Python to C from function calls (Simon Feltman) (:bzbug:`685197`) * Error handling/reporting fixes (Christoph Reiter) (:bzbug:`751956`) * Fix crash due to GVariant implemented as PyGBoxed not PyGIStruct (Christoph Reiter) (:bzbug:`751956`) * Fix crash with GValueArray stored in GValue (Mikhail Fludkov) (:bzbug:`754359`) 3.19.90 - 2016-02-20 -------------------- * tests: Set the active style context state before retrieving values (Simon Feltman) * tests: Fix crash with empty drag source icon names (Simon Feltman) (:bzbug:`762392`) * Try to import GdkX11 in Gdk overrides (Christoph Reiter) (:bzbug:`673396`) * Fix import warnings pointing to the wrong code with CPython 3.3/3.5 (Christoph Reiter) (:bzbug:`757184`) 3.19.2 - 2015-10-31 ------------------- * tests: Fix failure due to new GTK+ warning regarding size_allocate() (Simon Feltman) * Fix build warnings regarding _POSIX_C_SOURCE redefinition (Simon Feltman) * Drop -std=c90 for now (Matthias Clasen) 3.19.1 - 2015-10-30 ------------------- * Use a named tuple for returning multiple values (Christoph Reiter) (:bzbug:`727374`) * enum/flags: use gir info for type names and __repr__ instead of the gtype name (Christoph Reiter) (:bzbug:`657915`) * Improve and unify __repr__ format for PyGObject, PyGBoxed and PyGIStruct (Christoph Reiter) (:bzbug:`657915`) * Don't leak internal RepositoryError on import. (Christoph Reiter) (:bzbug:`756033`) * Import dependencies when importing typelibs from gi.repository (Christoph Reiter) (:bzbug:`656314`) * Fix Gdk.rectangle_intersect/rectangle_union missing with GTK+ 3.18 (Christoph Reiter) (:bzbug:`756364`) * Don't import inspect at module level (Christoph Reiter) * invoke state: add a free memory cache for PyGIInvokeArgState (Christoph Reiter) (:bzbug:`750658`) * invoke/closure: reduce g_slice_alloc usage (Christoph Reiter) (:bzbug:`750658`) * pep8: ignore new errors reported by pep8 1.6 (Christoph Reiter) * Bump g-i dependency to latest stable (Garrett Regier) * Avoid calling g_slist_length() during invoke (Garrett Regier) * Simplify closure_convert_arguments() (Garrett Regier) * Remove a level of indentation in convert_ffi_arguments() (Garrett Regier) * Prevent passing the user data multiple times to callbacks (Garrett Regier) (:bzbug:`750347`) * Support throwing exceptions in closures (Garrett Regier) (:bzbug:`710671`) * Don't emit require_version warning if namespace was loaded previously using g_irepository_require (Christoph Reiter) (:bzbug:`754491`) * configure.ac: post release version bump to 3.19.1 (Garrett Regier) 3.18.2 - 2015-10-24 ------------------- * configure.ac: post release version bump to 3.18.2 (Christoph Reiter) 3.18.1 - 2015-10-23 ------------------- * Fix Gdk.rectangle_intersect/rectangle_union missing with GTK+ 3.18 (Christoph Reiter) (:bzbug:`756364`) * pep8: ignore new errors reported by pep8 1.6 (Christoph Reiter) * Don't emit require_version warning if namespace was loaded previously using g_irepository_require (Christoph Reiter) (:bzbug:`754491`) * configure.ac: post release version bump to 3.18.1 (Garrett Regier) 3.18.0 - 2015-09-22 ------------------- 3.17.90 - 2015-08-19 -------------------- * Allow passing unicode lists to GStrv properties on Python 2 (Christoph Reiter) (:bzbug:`744745`) * Avoid a silent long to int truncation (Rui Matos) (:bzbug:`749698`) * Handle gtype marshalling (Mathieu Bridon) (:bzbug:`749696`) * pygi-foreign-cairo.c: fix include for py3cairo.h (Daniel Hahler) (:bzbug:`746742`) * tests: Silence various error messages and warnings (Christoph Reiter) (:bzbug:`751156`) * Fix test regression when xdg-user-dirs is not installed (Christoph Reiter) (:bzbug:`751299`) * Explicitly check if an override exists instead of ImportError (Garrett Regier) (:bzbug:`749532`) 3.17.1 - 2015-06-15 ------------------- * Add gi.PyGIWarning used when import version is not specified (Christoph Reiter) (:bzbug:`727379`) * Remove Gdk.Rectangle alias with newer gobject-introspection and GTK+ (Christoph Reiter) (:bzbug:`749625`) * overrides: Provide _overrides_module attribute (Christoph Reiter) (:bzbug:`736678`) * overrides: Conditionalize touch override support in Gdk (Simon Feltman) (:bzbug:`747717`) * Field setters: Remove unneeded type/range checks and unused code (Christoph Reiter) (:bzbug:`746985`) * pygi-argument: Remove unused imports/includes (Christoph Reiter) (:bzbug:`746985`) * Improve test coverage for field setters/getters (Christoph Reiter) (:bzbug:`746985`) 3.16.2 - 2015-06-15 ------------------- * overrides: Provide _overrides_module attribute (Christoph Reiter) (:bzbug:`736678`) 3.16.1 - 2015-04-13 ------------------- * overrides: Conditionalize touch override support in Gdk (Simon Feltman) (:bzbug:`747717`) 3.16.0 - 2015-03-24 ------------------- 3.15.91 - 2015-03-05 -------------------- * tests: Don't use deprecated override attributes (Christoph Reiter) (:bzbug:`743514`) * Add GLib.MINFLOAT etc. and mark GObject.G_MINFLOAT etc. deprecated (Christoph Reiter) (:bzbug:`743514`) * Emit PyGIDeprecationWarning when accessing deprecated override attributes (Christoph Reiter) (:bzbug:`743514`) * Add namespace and container name to all warnings/error messages (Christoph Reiter) (:bzbug:`743468`) * tests: Add test for GIRepository.UnionInfo.get_size() (Garrett Regier) (:bzbug:`745362`) * Avoid duping filenames when marshalling from Python to C (Garrett Regier) (:bzbug:`744719`) 3.15.0 - 2015-02-20 ------------------- * Avoid copying bytearrays from Python to C when transfer nothing (Garrett Regier) (:bzbug:`743278`) * Allows passing arguments to opaque Boxed types (Garrett Regier) (:bzbug:`743214`) * Emit ImportWarning when gi.require_version() is not used (Christoph Reiter) (:bzbug:`727379`) * Refactor overrides import/modules (Christoph Reiter) (:bzbug:`736678`) * Replace statically bound GLib.Variant.new_tuple() with GI (Simon Feltman) (:bzbug:`735199`) * overrides: Add Gdk.EventTouch union discrimination (Simon Feltman) (:bzbug:`736380`) * PyGObjectFlags: Remove a trailing comma on the enum. (Murray Cumming) * Remove redefinitions of function and vfunc cache typedefs (Simon Feltman) (:bzbug:`737874`) 3.14.0 - 2014-09-22 ------------------- * configure.ac: pre release version bump to 3.14.0 (Simon Feltman) 3.13.92 - 2014-09-15 -------------------- * tests: Add test for Gio.Application.add_main_option() (Simon Feltman) * tests: Split up various test cases (Simon Feltman) (:bzbug:`735193`) * Fix invalid read error in argument cleanup code (Simon Feltman) * Fix memory management problems with struct arguments to signals (Simon Feltman) (:bzbug:`736175`) 3.13.91 - 2014-09-01 -------------------- * docs: Fix return types in auto-generated doc strings (Simon Feltman) * Special case signal output arguments which are structs as pass-by-reference (Simon Feltman) (:bzbug:`735486`) * Ignore closure callbacks when Python is not initialized (Simon Feltman) (:bzbug:`722562`) * Change boxed init with args to warn instead of raise (Christoph Reiter) (:bzbug:`727810`) * Fix crash in GList/GSList marshaling error handling path. (Christoph Reiter) (:bzbug:`735201`) * Fix reference counting problems with GLib.Variant.new_tuple() (Simon Feltman) (:bzbug:`735166`) * Skip marshalling NULL output arguments in Python closures (Simon Feltman) (:bzbug:`735090`) 3.13.90 - 2014-08-18 -------------------- * Support array lengths on struct fields (Simon Feltman) (:bzbug:`688792`) * Fast path Python property get access (Simon Feltman) (:bzbug:`723872`) * Unify accessing properties through props and get_property() (Simon Feltman) (:bzbug:`726999`) * Refactor boxed wrapper memory management strategy (Simon Feltman) (:bzbug:`726999`) * Replace GObject.signal_query with introspected version (Simon Feltman) (:bzbug:`688792`) * Fix memory leak with unboxed caller allocated structs (Simon Feltman) * tests: Add failing tests for GObject sub-class doc-strings (Piotr Iwaniuk) (:bzbug:`731452`) * Don't mask GObject sub-class doc strings in meta-class (Tobias Mueller) (:bzbug:`731452`) 3.13.4 - 2014-08-14 ------------------- * Marshaling cache refactor and cache usage in vfuncs (Garrett Regier) (:bzbug:`727004`) * Fix array argument out and inout marshaling from vfuncs (Garrett Regier) (:bzbug:`702508`) * Cleanup input args when marshaling in closures (Garrett Regier) (:bzbug:`727004`) * Add deprecation warning for connect_object() with non-GObject argument (Simon Feltman) (:bzbug:`688064`) * Add Python implementation of Object.connect_data() (Simon Feltman) (:bzbug:`701843`) * Add GClosure marshaling cleanup (Simon Feltman) (:bzbug:`695128`) * Fix GCallback Python wrapper leak (Simon Feltman) (:bzbug:`695130`) * tests: Add failing test for marshaling an array of GValues through signals (Martin Pitt) (:bzbug:`669496`) * Add protection against attempts at importing static bindings (Simon Feltman) (:bzbug:`709183`) * Update and deprecate gi.overrides.keysyms (Simon Feltman) (:bzbug:`721295`) * Generate .dll libraries on windows (Ignacio Casal Quinteiro) (:bzbug:`734288`) * Windows build fixes (Alexey Pavlov) (:bzbug:`734284`, :bzbug:`734289`, :bzbug:`734286`, :bzbug:`734287`) 3.13.3 - 2014-06-23 ------------------- * demos: Cleanup CSS accordion demo to use a loop for adding buttons (Simon Feltman) * refactor: Move builder connection utilities outside of Builder class (Simon Feltman) (:bzbug:`701843`) * tests: Move TestSignals from test_everything into test_signal (Simon Feltman) (:bzbug:`701843`) 3.13.2 - 2014-05-26 ------------------- * Python 3.4 make check fixes (Simon Feltman) (:bzbug:`730411`) * overrides: Add Gtk.Container.child_get/set overrides (Simon Feltman) (:bzbug:`685076`) * overrides: Make value argument to Widget.style_get_property optional (Simon Feltman) (:bzbug:`685076`) * overrides: Make value argument to Container.child_get_property optional (Simon Feltman) (:bzbug:`685076`) * Add GTypeClass methods as Python GObject class methods (Johan Dahlin) (:bzbug:`685218`) * Add marshalling coercion for Python classes and instances to GTypeClass (Simon Feltman) (:bzbug:`685218`) * Replace direct parent class call by super() (Andrew Grigorev) (:bzbug:`729970`) * Add cairo marshaling support for non-introspected signals (Simon Feltman) (:bzbug:`694604`) * [New API] Add gi.require_foreign (Simon Feltman) (:bzbug:`707735`) * Initialize the foreign API at PyGI load time (Simon Feltman) (:bzbug:`694604`) * Move pygi foreign API into pygi-foreign-api.h (Simon Feltman) (:bzbug:`694604`) * Unify GLib.GError and GLib.Error (Simon Feltman) (:bzbug:`712519`) * PEP8 fixes (Simon Feltman) 3.12.2 - 2014-05-26 ------------------- * PEP8 fixes (Simon Feltman) * Python 3.4 make check fixes (Simon Feltman) (:bzbug:`730411`) 3.13.1 - 2014-04-28 ------------------- * Raise TypeError if arguments are passed to Boxed.__init__ (Christoph Reiter) (:bzbug:`727810`) * Gdk.Event: Override __setattr__ to set fields based on the event type (Christoph Reiter) (:bzbug:`727810`) * Gdk.Event: Include GdkEventType in __repr__ (Christoph Reiter) (:bzbug:`727810`) * Fix crash with type checking for GObject arguments (Simon Feltman) (:bzbug:`727604`) * Do not leak info of destroy notify (Paolo Borelli) * Ignore GValueArray deprecations (Simon Feltman) * Raise ImportError when importing modules not found in repository (Simon Feltman) (:bzbug:`726877`) * tests: Rename test_overrides to test_import_machinery (Simon Feltman) (:bzbug:`726877`) 3.12.1 - 2014-04-14 ------------------- * Fix crash with type checking invalid GObject arguments (Simon Feltman) (:bzbug:`727604`) * Do not leak info of destroy notify (Paolo Borelli) 3.12.0 - 2014-03-24 ------------------- 3.11.92 - 2014-03-17 -------------------- * configure.ac: Remove option to build without libffi (Simon Feltman) * docs: Standardize Python doc strings (Simon Feltman) * Fix reference leaks with (transfer full) foreign struct returns (Owen W. Taylor) (:bzbug:`726206`) 3.11.91 - 2014-03-03 -------------------- * Use ffi_call directly instead of g_callable_info_invoke (Simon Feltman) (:bzbug:`723642`) * configure.ac: Use -std=c90 and error on declaration-after-statement (Simon Feltman) * Fix Build on Visual Studio (Chun-wei Fan) (:bzbug:`725122`) 3.11.90 - 2014-02-17 -------------------- * Use GObject type checking for instance arguments (Simon Feltman) (:bzbug:`724009`) * configure.ac: post release version bump to 3.11.90 (Simon Feltman) 3.11.5 - 2014-02-03 ------------------- * cache refactoring: Move all cache marshalers into files based on type (Simon Feltman) (:bzbug:`709700`) * tests: Add test for an owned boxed struct passed in a callback (Mike Gorse) (:bzbug:`722899`) * build: Add --without-common configure option for package maintainers (Patrick Welche) (:bzbug:`721646`) * demo: Add TreeModel interface implementation demonstration (Simon Feltman) * build: Set PLATFORM_VERSION again to 3.0 (Colin Walters) * tests: Run PyFlakes and PEP8 only on SUBDIRS (Simon Feltman) * Merge static PyGLib and PyGObject modules into PyGI (Simon Feltman) (:bzbug:`712197`) * Add test for callback user data arguments with following arguments (Martin Pitt) (:bzbug:`722104`) 3.11.4 - 2014-01-13 ------------------- * overrides: Fix __repr__ for various Gdk structs (Simon Feltman) * Add enum and flags member methods (Simon Feltman) (:bzbug:`693099`) * python.m4: g/c JD_PYTHON_CHECK_VERSION (Patrick Welche) (:bzbug:`721662`) * Support union creation with PyGIStruct (Simon Feltman) * docs: List constructors in object and struct doc strings (Simon Feltman) (:bzbug:`708060`) * docs: Fix array length argument skipping with preceding out arguments * docs: Add return values and skip implicit out arguments in functions (Simon Feltman) (:bzbug:`697356`) * docs: Skip implicit array length args when building function doc strings (Simon Feltman) (:bzbug:`697356`) * gtk-demo: Add CSS demos (Gian Mario Tagliaretti) (:bzbug:`719722`) * build: Avoid clash between gi/types.py and stdlib (Colin Watson) (:bzbug:`721025`) 3.11.3 - 2013-12-16 ------------------- * Replace usage of PyGIBoxed_Type with PyGIStruct_Type (Simon Feltman) (:bzbug:`581525`) 3.11.2 - 2013-11-17 ------------------- * gkt-demo: Change main info/source notebook into a GtkStack (Simon Feltman) * Add deprecation warnings and cleanup class initializer overrides (Simon Feltman) (:bzbug:`705810`) * Fix dir method for static GParamSpec in Python 3 (Simon Feltman) * Remove overzealous argument checking for callback userdata (Simon Feltman) (:bzbug:`711173`) 3.10.2 - 2013-11-11 ------------------- * Fix thread safety problems by always enabling the GIL (Simon Feltman) (:bzbug:`709223`, :bzbug:`710447`) 3.11.1 - 2013-10-28 ------------------- * Fix toggleref safety problems by always enabling the GIL (Simon Feltman) (:bzbug:`709223`) * Add consistent GLib.MainLoop SIGINT cleanup (Simon Feltman) (:bzbug:`710978`) * docs: Add a keyword value of None for allow-none annotations (Simon Feltman) (:bzbug:`640812`) * Remove overrides for supporting pre-3.10 GObject signal functions (Simon Feltman) * Add threads_init back as a requirement for non-Python threaded repos (Simon Feltman) (:bzbug:`710447`) * Add dir method to GObject props accessor (Simon Feltman) (:bzbug:`705754`) * Remove PyGObjectWeakRef now that g_binding_unbind exists (Simon Feltman) (:bzbug:`699571`) * Fix lots of memory leaks leaks (Simon Feltman) (:bzbug:`693402`, :bzbug:`709397`) * Add support for variable user data arguments (Simon Feltman) (:bzbug:`640812`) * Bump glib and g-i dependencies to latest stable. (Martin Pitt) * Fix TypeError when setting drag target_list to None (Nuno Araujo) (:bzbug:`709926`) * Use qdata for wrapper retrieval in toggle reference notifications (Simon Feltman) (:bzbug:`709223`) * Expose all GI enum and flags types (Simon Feltman) (:bzbug:`709008`) * Add support for default arguments annotated with allow-none (Simon Feltman) (:bzbug:`640812`) * Refactor argument cache handling (Simon Feltman) (:bzbug:`640812`) * Remove support for allowing PyObjects as void pointers (Simon Feltman) (:bzbug:`688081`) 3.10.1 - 2013-10-14 ------------------- * Fix TypeError when setting drag target_list to None (Nuno Araujo) (:bzbug:`709926`) * Use qdata for wrapper retrieval in toggle reference notifications (Simon Feltman) (:bzbug:`709223`) * Fix memory leak for caller allocated GValue out arguments (Simon Feltman) (:bzbug:`709397`) 3.10.0 - 2013-09-23 ------------------- * Fix test_gi.TestProjectVersion.test_version_str() (Martin Pitt) 3.9.92 - 2013-09-16 ------------------- * Fix union argument regression when marshaling from python (Simon Feltman) (:bzbug:`703873`) * Fix GLib.Source sub-classing with initializer args (Simon Feltman) (:bzbug:`707904`) * Copy __doc__ when wrapping function (Vratislav Podzimek) 3.9.91 - 2013-09-02 ------------------- * Fix GObject signal methods to work with new annotations (Simon Feltman) (:bzbug:`707280`) * Fix build on C89 Compilers (Chun-wei Fan) (:bzbug:`707264`) * Change boxed type checking in marshaling to use __gtype__ attribute (Simon Feltman) (:bzbug:`707140`) * Use G_IS_VALUE for checking return values in closure marshaling (Simon Feltman) (:bzbug:`707170`) * Fix PEP-8 errors in propertyhelper.py (Yanko Kaneti) (:bzbug:`706319`) 3.9.90 - 2013-08-19 ------------------- * Create GLib.Pid in the same way on python 2 and 3 (Benjamin Berg) (:bzbug:`705451`) * Use PyLong_Type.tp_new for GLib.Pid (Benjamin Berg) (:bzbug:`705451`) * Add accumulator and accu_data arguments to GObject.Signal decorator (Simon Feltman) (:bzbug:`705533`) * Pass return values through the GObject.Signal.emit wrapper (Simon Feltman) (:bzbug:`705530`) 3.9.5 - 2013-07-29 ------------------ * Ensure exceptions set in closure out argument marshaling are printed (Simon Feltman) (:bzbug:`705064`) * Always raise OverflowError for marshaling integers from Python (not ValueError or OverflowError) (Simon Feltman) (:bzbug:`705057`) * Cleanup invoke args and kwargs combiner code (Simon Feltman) (:bzbug:`640812`) * gtk-demo: Change demo to use Gtk.Application (Simon Feltman) (:bzbug:`698547`) * Add callable and descriptor protocols to PyGICallableInfo (Simon Feltman) (:bzbug:`704037`) * Unify basic type argument marshaling for methods, closures, and properties (Simon Feltman) (:bzbug:`693405`) * Override GValue.set/get_boxed with static C marshaler (Simon Feltman) (:bzbug:`688081`, :bzbug:`693405`) * Add deprecation warning for marshaling arbitrary objects as pointers (Simon Feltman) (:bzbug:`688081`) * Replace usage of __import__ with importlib.import_module (Simon Feltman) (:bzbug:`682320`) * Always unref the GiTypeInfo when generating an argument cache (Mike Gorse) (:bzbug:`703973`) * Unref interface info when fetching enums or flags (Mike Gorse) (:bzbug:`703960`) * Speed up MRO calculation (Daniel Drake) (:bzbug:`703829`) * Add GIL safety to pyobject_copy for copying boxed PyObjects (Simon Feltman) (:bzbug:`688081`) * Add marshaling of GI_TYPE_TAG_VOID held in a GValue to int (Simon Feltman) (:bzbug:`694233`) * GTK overrides: Make connect_signals handle tuple (Cole Robinson) (:bzbug:`693994`) * Re-add support for passing GValue's by reference (Simon Feltman) (:bzbug:`701058`) * Clear return value of closures to zero when an exception occurs (Simon Feltman) (:bzbug:`702552`) * Don't use doctest syntax in docstrings for examples (Martin Pitt) (:bzbug:`701009`) * Add support for properties of type GInterface (Garrett Regier) (:bzbug:`703456`) * pygtkcompat: Fix for missing methods on Windows (Martin Pitt) (:bzbug:`702787`) * gi/pygi-info.c: Avoid C99-style variable declaration (Chun-wei Fan) (:bzbug:`702786`) 3.8.3 - 2013-07-05 ------------------ * Add marshalling of GI_TYPE_TAG_VOID held in a GValue to int. While not particularly useful this allows some callbacks in WebKit to function without causing a segfault. (Simon Feltman) (:bzbug:`694233`) * pygtkcompat: Fix for missing methods on Windows (Martin Pitt) (:bzbug:`702787`) * gi/pygi-info.c: Avoid C99-style variable declaration (Chun-wei Fan) (:bzbug:`702786`) * Clear return value of closures to zero when an exception occures (Simon Feltman) (:bzbug:`702552`) * Re-add support for passing GValue's by reference (Simon Feltman) (:bzbug:`701058`) * Don't use doctest syntax in docstrings for examples, to fix test failures with pyflakes 0.7.x (Martin Pitt) (:bzbug:`701009`) * examples/option.py: Port to GI and Python 3 (Martin Pitt) 3.9.2 - 2013-05-28 ------------------ * examples/option.py: Port to GI and Python 3 (Martin Pitt) * Fix vfunc info search for classes with multiple inheritance (Simon Feltman) (:bzbug:`700092`) * Fix closure argument conversion for enum and flag in args (Simon Feltman) * Fix marshaling Python to FFI return value for enum and flags (Simon Feltman) * Remove half implemented GC in PyGIBaseInfo, PyGIStruct, and PyGIBoxed (Simon Feltman) (:bzbug:`677091`) * Replace usage of pyg_begin_allow_threads with Py_BEGIN_ALLOW_THREADS (Simon Feltman) (:bzbug:`699440`) * Remove and deprecate API for setting of thread blocking functions (Simon Feltman) (:bzbug:`699440`) 3.8.2 - 2013-05-13 ------------------ * Fix vfunc info search for classes with multiple inheritance (Simon Feltman) (:bzbug:`700092`) * Fix closure argument conversion for enum and flag in args (Simon Feltman) * Fix marshaling Python to FFI return value for enum and flags (Simon Feltman) * Use correct class for GtkEditable's get_selection_bounds() function (Mike Ruprecht) (:bzbug:`699096`) * Test results of g_base_info_get_name for NULL (Simon Feltman) (:bzbug:`698829`) * Change interpretation of NULL pointer field from None to 0 (Simon Feltman) (:bzbug:`698366`) * Remove Python keyword escapement in Repository.find_by_name (Simon Feltman) (:bzbug:`697363`) 3.9.1 - 2013-04-30 ------------------ * gtk-demo: Wrap description strings at 80 characters (Simon Feltman) (:bzbug:`698547`) * gtk-demo: Use textwrap to reformat description for Gtk.TextView (Simon Feltman) (:bzbug:`698547`) * gtk-demo: Use GtkSource.View for showing source code (Simon Feltman) (:bzbug:`698547`) * Use correct class for GtkEditable's get_selection_bounds() function (Mike Ruprecht) (:bzbug:`699096`) * Test results of g_base_info_get_name for NULL (Simon Feltman) (:bzbug:`698829`) * Add ObjectInfo.get_class_struct() (Johan Dahlin) (:bzbug:`685218`) * Change interpretation of NULL pointer field from None to 0 (Simon Feltman) (:bzbug:`698366`) * Do not build tests until needed (Sobhan Mohammadpour) (:bzbug:`698444`) * pygi-convert: Support toolbar styles (Kai Willadsen) (:bzbug:`698477`) * pygi-convert: Support new-style constructors for Gio.File (Kai Willadsen) (:bzbug:`698477`) * pygi-convert: Add some support for recent manager constructs (Kai Willadsen) (:bzbug:`698477`) * pygi-convert: Don't transform arbitrary keysym imports (Kai Willadsen) (:bzbug:`698477`) * Remove Python keyword escapement in Repository.find_by_name (Simon Feltman) (:bzbug:`697363`) * Optimize signal lookup in gi repository (Daniel Drake) (:bzbug:`696143`) * Optimize connection of Python-implemented signals (Daniel Drake) (:bzbug:`696143`) * Consolidate signal connection code (Daniel Drake) (:bzbug:`696143`) * Fix setting of struct property values (Daniel Drake) * Optimize property get/set when using GObject.props (Daniel Drake) (:bzbug:`696143`) * configure.ac: Fix PYTHON_SO with Python3.3 (Christoph Reiter) (:bzbug:`696646`) * Simplify registration of custom types (Daniel Drake) (:bzbug:`696143`) * pygi-convert.sh: Add GStreamer rules (Christoph Reiter) (:bzbug:`697951`) * pygi-convert: Add rule for TreeModelFlags (Jussi Kukkonen) * Unify GI marshalling code (Simon Feltman) (:bzbug:`693405`) * Use distutils.sysconfig to retrieve the python include path. (Christoph Reiter) (:bzbug:`696648`) * Support PEP 3149 (ABI version tagged .so files) (Christoph Reiter) (:bzbug:`696646`) * Fix stack corruption due to incorrect format for argument parser (Simon Feltman) (:bzbug:`696892`) * Deprecate GLib and GObject threads_init (Simon Feltman) (:bzbug:`686914`) * Drop support for Python 2.6 (Martin Pitt) * Remove static PollFD bindings (Martin Pitt) (:bzbug:`686795`) * Drop test skipping due to too old g-i (Martin Pitt) * Bump glib and g-i dependencies (Martin Pitt) 3.8.1 - 2013-04-15 ------------------ * pygi-convert.sh: Add GStreamer rules (Christoph Reiter) (:bzbug:`697951`) * pygi-convert: Add rule for TreeModelFlags (Jussi Kukkonen) * Fix enum and flags marshaling type assumptions (Simon Feltman) * Use g_strdup() consistently (Martin Pitt) (:bzbug:`696650`) * Fix stack corruption due to incorrect format for argument parser (Simon Feltman) (:bzbug:`696892`) 3.8.0 - 2013-03-25 ------------------ * tests: Fix incorrect assumption when testing pyglib version (Simon Feltman) 3.7.92 - 2013-03-18 ------------------- * Fix stack smasher when marshaling enums as a vfunc return value (Simon Feltman) (:bzbug:`637832`) * Change base class of PyGIDeprecationWarning based on minor version (Simon Feltman) (:bzbug:`696011`) * autogen.sh: Source gnome-autogen to fix out of source builddir (Alban Browaeys) (:bzbug:`694889`) * pygtkcompat: Make gdk.Window.get_geometry return tuple of 5 (Simon Feltman) * pygtkcompat: Initialize hint to zero in set_geometry_hints (Simon Feltman) * Remove incorrect bounds check with property helper flags (Simon Feltman) * Fix crash when setting property of type object to an incorrect type (Simon Feltman) (:bzbug:`695420`) * Give more informative error when setting property to incorrect type (Simon Feltman) (:bzbug:`695420`) 3.7.91.1 - 2013-03-05 --------------------- * Revert "Drop gi.overrides.overridefunc()" (Martin Pitt) (:bzbug:`695199`) 3.7.91 - 2013-03-04 ------------------- * Fix many memory leaks (:bzbug:`675726`, :bzbug:`693402`, :bzbug:`691501`, :bzbug:`510511`, :bzbug:`691501`, :bzbug:`672224`, and several more which are detected by our test suite) (Martin Pitt) * Dot not clobber original Gdk/Gtk functions with overrides (Martin Pitt) (:bzbug:`686835`) * Optimize GValue.get/set_value by setting GValue.g_type to a local (Simon Feltman) (:bzbug:`694857`) * Run tests with G_SLICE=debug_blocks (Martin Pitt) (:bzbug:`691501`) * Add override helper for stripping boolean returns (Martin Pitt) (:bzbug:`694431`) * Drop obsolete pygobject_register_sinkfunc() declaration (Martin Pitt) (:bzbug:`639849`) * Fix marshalling of C arrays with explicit length in signal arguments (Martin Pitt) (:bzbug:`662241`) * Fix signedness, overflow checking, and 32 bit overflow of GFlags (Martin Pitt) (:bzbug:`693121`) * gi/pygi-marshal-from-py.c: Fix build on Visual C++ (Chun-wei Fan) (:bzbug:`692856`) * Raise DeprecationWarning on deprecated callables (Martin Pitt) (:bzbug:`665084`) * pygtkcompat: Add Widget.window, scroll_to_mark, and window methods (Simon Feltman) (:bzbug:`694067`) * pygtkcompat: Add Gtk.Window.set_geometry_hints which accepts keyword arguments (Simon Feltman) (:bzbug:`694067`) * Ship pygobject.doap for autogen.sh (Martin Pitt) (:bzbug:`694591`) * Fix crashes in various GObject signal handler functions (Simon Feltman) (:bzbug:`633927`) * pygi-closure: Protect the GSList prepend with the GIL (Olivier Crête) (:bzbug:`684060`) * generictreemodel: Fix bad default return type for get_column_type (Simon Feltman) 3.7.90 - 2013-02-19 ------------------- * overrides: Fix inconsistencies with drag and drop target list API (Simon Feltman) (:bzbug:`680640`) * pygtkcompat: Add pygtk compatible GenericTreeModel implementation (Simon Feltman) (:bzbug:`682933`) * overrides: Add support for iterables besides tuples for TreePath creation (Simon Feltman) (:bzbug:`682933`) * Prefix __module__ attribute of function objects with gi.repository (Niklas Koep) (:bzbug:`693839`) * configure.ac: only enable code coverage when available, to fix autogen.sh with older gnome-commons (Jonathan Ballet) (:bzbug:`693328`) * Correctly set properties on object with statically defined properties (Jonathan Ballet) (:bzbug:`693618`) * autogen.sh: Use gnome-autogen.sh (Martin Pitt) (:bzbug:`693328`) * Fix reference leaks with transient floating objects (Simon Feltman) (:bzbug:`687522`) 3.7.5.1 - 2013-02-05 -------------------- * Fix ABI break with pygobject.h from 3.7.5 (Simon Feltman) (:bzbug:`675726`) 3.7.5 - 2013-02-04 ------------------ * Move various signal methods from static bindings to GI (Simon Feltman) (:bzbug:`692918`) * GLib overrides: Support unpacking 'maybe' variants (Paolo Borelli) (:bzbug:`693032`) * Fix ref count leak when creating pygobject wrappers for input args (Mike Gorse) (:bzbug:`675726`) * Prefix names of typeless enums and flags for GType registration (Simon Feltman) (:bzbug:`692515`) * Fix compilation with non-C99 compilers such as Visual C++ (Chun-wei Fan) (:bzbug:`692856`) * gi/overrides/Glib.py: Fix running on Windows/non-Unix (Chun-wei Fan) * Do not immediately initialize Gdk and Gtk on import (Martin Pitt) (:bzbug:`692300`) * Accept ±inf and NaN as float and double values (Martin Pitt) (:bzbug:`692381`) * Fix repr() of GLib.Variant (Martin Pitt) * Fix gtk-demo for Python 3 (Martin Pitt) * Define GObject.TYPE_VALUE gtype constant (Martin Pitt) * gobject: Go through introspection on property setting (Olivier Crête) (:bzbug:`684062`) * Clean up caller-allocated GValues and their memory (Mike Gorse) (:bzbug:`691820`) * Use GNOME_COMPILE_WARNINGS from gnome-common (Martin Pitt) 3.7.4 - 2013-01-14 ------------------ * Allow setting values through GtkTreeModelFilter (Simonas Kazlauskas) (:bzbug:`689624`) * Support GParamSpec signal arguments from Python (Martin Pitt) (:bzbug:`683099`) * pygobject_emit(): Fix cleanup on error (Martin Pitt) * Add signal emission methods to TreeModel which coerce the path argument (Simon Feltman) (:bzbug:`682933`) * Add override for GValue (Bastian Winkler) (:bzbug:`677473`) * Mark caller-allocated boxed structures as having a slice allocated (Mike Gorse) (:bzbug:`699501`) * pygi-property: Support boxed GSList/GList types (Olivier Crête) (:bzbug:`684059`) * tests: Add missing backwards compat methods for Python 2.6 (Martin Pitt) (:bzbug:`691646`) * Allow setting TreeModel values to None (Simon Feltman) (:bzbug:`684094`) * Set clean-up handler for marshalled arrays (Mike Gorse) (:bzbug:`691509`) * Support setting string fields in structs (Vadim Rutkovsky) (:bzbug:`678401`) * Permit plain integers for "gchar" values (Martin Pitt) * Allow single byte values for int8 types (Martin Pitt) (:bzbug:`691524`) * Fix invalid memory access handling errors when registering an enum type (Mike Gorse) * Fix (out) arguments in callbacks (Martin Pitt) * Fix C to Python marshalling of struct pointer arrays (Martin Pitt) * Don't let Property.setter() method names define property names (Martin Pitt) (:bzbug:`688971`) * Use g-i stack allocation API (Martin Pitt) (:bzbug:`615982`) * pyg_value_from_pyobject: support GArray (Ray Strode) (:bzbug:`690514`) * Fix obsolete automake macros (Marko Lindqvist) (:bzbug:`691101`) * Change dynamic enum and flag gtype creation to use namespaced naming (Simon Feltman) (:bzbug:`690455`) * Fix Gtk.UIManager.add_ui_from_string() override for non-ASCII chars (Jonathan Ballet) (:bzbug:`690329`) * Don't dup strings before passing them to type registration functions (Mike Gorse) (:bzbug:`690532`) * Fix marshalling of arrays of boxed struct values (Carlos Garnacho) (:bzbug:`656312`) 3.7.3 - 2012-12-17 ------------------ * Add support for caller-allocated GArray out arguments (Martin Pitt) (:bzbug:`690041`) * [API add] Re-support calling GLib.io_add_watch with an fd or Python file (Martin Pitt) * pygtkcompat: Work around IndexError on large flags (Martin Pitt) * Fix pyg_value_from_pyobject() range check for uint (Martin Pitt) * Fix tests to work with g-i 1.34.2 (Martin Pitt) * Fix wrong refcount for GVariant property defaults (Martin Pitt) (:bzbug:`689267`) * Fix array arguments on 32 bit architectures (Martin Pitt) * Add backwards compatible API for GLib.unix_signal_add_full() (Martin Pitt) * Drop MININT64/MAXUINT64 workaround, current g-i gets this right now (Martin Pitt) * Fix maximum and minimum ranges of TYPE_(U)INT64 properties (Simonas Kazlauskas) (:bzbug:`688949`) * Ship pygi-convert.sh in tarballs (Martin Pitt) (:bzbug:`688697`) 3.7.2 - 2012-11-19 ------------------ * [API change] Drop almost all static GLib bindings and replace them with proper introspection. This gets rid of several cases where the PyGObject API was not matching the real GLib API, makes the full GLib API available through introspection, and makes the code smaller, easier to maintain. For backwards compatibility, overrides are provided to emulate the old static binding API, but this will throw a PyGIDeprecationWarning for the cases that diverge from the official API (in particular, GLib.io_add_watch() and GLib.child_watch_add() being called without a priority argument). (Martin Pitt, Simon Feltman) * [API change] Deprecate calling GLib API through the GObject namespace. This has always been a misnomer with introspection, and will be removed in a later version; for now this throws a PyGIDeprecationWarning. * [API change] Do not bind gobject_get_data() and gobject_set_data(). These have been deprecated for a cycle, now dropped entirely. (Steve Frécinaux) (:bzbug:`641944`) * [API change] Deprecate void pointer fields as general PyObject storage. (Simon Feltman) (:bzbug:`683599`) * Add support for GVariant properties (Martin Pitt) * Add type checking to GVariant argument assignment (Martin Pitt) * Fix marshalling of arrays of struct pointers to Python (Carlos Garnacho) (:bzbug:`678620`) * Fix Gdk.Atom to have a proper str() and repr() (Martin Pitt) (:bzbug:`678620`) * Make sure g_value_set_boxed does not cause a buffer overrun with GStrvs (Simon Feltman) (:bzbug:`688232`) * Fix leaks with GValues holding boxed and object types (Simon Feltman) (:bzbug:`688137`) * Add doc strings showing method signatures for gi methods (Simon Feltman) (:bzbug:`681967`) * Set Property instance doc string and blurb to getter doc string (Simon Feltman) (:bzbug:`688025`) * Add GObject.G_MINSSIZE (Martin Pitt) * Fix marshalling of GByteArrays (Martin Pitt) * Fix marshalling of ssize_t to smaller ints (Martin Pitt) * Add support for lcov code coverage, and add a lot of missing GIMarshallingTests and g-i Regress tests. (Martin Pitt) * pygi-convert: remove deprecated GLib → GObject conversions (Jose Rostagno) * Add support for overriding GObject.Object (Simon Feltman) (:bzbug:`672727`) * Add --with-python configure option (Martin Pitt) * Do not prefer unversioned "python" when configuring, as some distros have "python" as Python 3. Use Python 3 by default if available. Add --with-python configure option as an alternative to setting $PYTHON, whic is more discoverable. (Martin Pitt) * Fix property lookup in class hierarchy (Daniel Drake) (:bzbug:`686942`) * Move property and signal creation into _class_init() (Martin Pitt) (:bzbug:`686149`) * Fix duplicate symbols error on OSX (John Ralls) * [API add] Add get_introspection_module for getting un-overridden modules (Simon Feltman) (:bzbug:`686828`) * Work around wrong 64 bit constants in GLib Gir (Martin Pitt) (:bzbug:`685022`) * Mark GLib.Source.get_current_time() as deprecated (Martin Pitt) * Fix OverflowError in source_remove() (Martin Pitt) (:bzbug:`684526`) 3.4.2 - 2012-11-12 ------------------ * Fix marshalling of GByteArrays (Martin Pitt) * Fix marshalling of ssize_t to smaller ints (Martin Pitt) * Fix crash with GLib.child_watch_add (Daniel Narvaez) (:bzbug:`688067`) * Fix various bugs in GLib.IOChannel (Martin Pitt) * Work around wrong 64 bit constants in GLib Gir (Martin Pitt) (:bzbug:`685022`) * Fix OverflowError in source_remove() (Martin Pitt) (:bzbug:`684526`) * Fix Signal decorator to not use base class gsignals dict (Simon Feltman) (:bzbug:`686496`) 3.7.1 - 2012-10-22 ------------------ * Bump version to 3.7.1; let's follow the real GNOME versioning from now on (Martin Pitt) * Change install_properties to not use getattr on classes (Simon Feltman) (:bzbug:`686559`) * Move property install function into propertyhelper.py (Simon Feltman) (:bzbug:`686559`) * Fix Signal decorator to not use base class gsignals dict (Simon Feltman) (:bzbug:`686496`) * tests: Consistently use GLib.MainLoop (Martin Pitt) * Install the .egg-info files into correct multilib directory (Kalev Lember) (:bzbug:`686315`) * Fix leaked vfunc return values (Simon Feltman) (:bzbug:`686140`) * Skip Regress tests with --disable-cairo (Martin Pitt) (:bzbug:`685094`) * Fix leak with python callables as closure argument. (Simon Feltman) (:bzbug:`685598`) * Gio overrides: Handle setting GSettings enum keys (Martin Pitt) (:bzbug:`685947`) * tests: Check reading GSettings enums in Gio overrides (Martin Pitt) * Fix unsigned values in GArray/GList/GSList/GHash (Martin Pitt) (:bzbug:`685860`) * _pygi_marshal_from_py_uint64(): Use correct data type in py2.7 check (Alban Browaeys) (:bzbug:`685000`) * Install an .egg-info file (Johan Dahlin) (:bzbug:`680138`) * PyGProps_getattro(): Fix GObjectClass leak (Johan Dahlin) (:bzbug:`685218`) * pygobject.c: Don't leak GObjectClass reference (Olivier Crête) (:bzbug:`684062`) * Fix memory leak in _pygi_argument_to_array() (Alban Browaeys) (:bzbug:`685082`) * Fix error messages for out of range numbers (Martin Pitt) (:bzbug:`684314`) * Kill dbus-daemon after running tests (Martin Pitt) (:bzbug:`685009`) * GVariant overrides: Support empty tuple arrays (Martin Pitt) (:bzbug:`684928`) * tests: Fix wrong return type in test_int64_callback() (Martin Pitt) (:bzbug:`684700`) * Fix GValue marshalling of long and unsigned long (Giovanni Campagna) (:bzbug:`684331`) * Clean up deprecation message for assigning gpointers to objects. (Simon Feltman) (:bzbug:`683599`) * pygi-property: Lookup property in base classes of non-introspected types (Olivier Crête) (:bzbug:`684058`) 3.4.1.1 - 2012-10-17 -------------------- * Bump g-i dependency to >= 1.34.1.1 (Paolo Borelli) * Fix leaked vfunc return values (Simon Feltman) (:bzbug:`686140`) * Install egg-info files in the right dir Kalev Lember) (:bzbug:`686315`) 3.4.1 - 2012-10-15 ------------------ * Skip Regress tests with --disable-cairo (Martin Pitt) (:bzbug:`685094`) * Fix leak with python callables as closure argument. (Simon Feltman) (:bzbug:`685598`) * Gio overrides: Handle setting GSettings enum keys (Martin Pitt) (:bzbug:`685947`) * Fix unsigned values in GArray/GList/GSList/GHash (Martin Pitt) (:bzbug:`685860`) * _pygi_marshal_from_py_uint64(): Use correct data type in py2.7 check (Alban Browaeys) (:bzbug:`685000`) * Install an .egg-info file (Johan Dahlin) (:bzbug:`680138`) * PyGProps_getattro(): Fix GObjectClass leak (Johan Dahlin) (:bzbug:`685218`) * pygobject.c: Don't leak GObjectClass reference (Olivier Crête) (:bzbug:`684062`) * Fix memory leak in _pygi_argument_to_array() (Alban Browaeys) (:bzbug:`685082`) * Fix error messages for out of range numbers (Martin Pitt) (:bzbug:`684314`) * Kill dbus-daemon after running tests (Martin Pitt) (:bzbug:`685009`) * GVariant overrides: Support empty tuple arrays (Martin Pitt) (:bzbug:`684928`) * tests: Fix wrong return type in test_int64_callback() (Martin Pitt) (:bzbug:`684700`) * Fix GValue marshalling of long and unsigned long (Giovanni Campagna) (:bzbug:`684331`) * Clean up deprecation message for assigning gpointers to objects. (Simon Feltman) (:bzbug:`683599`) * pygi-property: Lookup property in base classes of non-introspected types (Olivier Crête) (:bzbug:`684058`) 3.4.0 - 2012-09-24 ------------------ * Bump g-i dependency to 1.33.14 (Martin Pitt) 3.3.92 - 2012-09-17 ------------------- * [API add] Add ObjectInfo.get_abstract method (Simon Feltman) (:bzbug:`675581`) * Add deprecation warning when setting gpointers to anything other than int. (Simon Feltman) (:bzbug:`683599`) * argument: Fix 64bit integer convertion from GValue (Nicolas Dufresne) (:bzbug:`683596`) * Improve setting pointer fields/arguments to NULL using None (Simon Feltman) (:bzbug:`683150`) * Bump g-i dependency to 1.33.10 (Martin Pitt) * Fix -uninstalled.pc.in file (Thibault Saunier) (:bzbug:`683379`) * Various test suite additions and improvements (Martin Pitt) 3.3.91 - 2012-09-03 ------------------- * Fix exception test case for Python 2 (Martin Pitt) * Bump g-i dependency to >= 1.3.9 (Martin Pitt) * Show proper exception when trying to allocate a disguised struct (Martin Pitt) (:bzbug:`639972`) * Support marshalling GParamSpec signal arguments (Mark Nauwelaerts) (:bzbug:`683099`) * Add test for a signal that returns a GParamSpec (Martin Pitt) (:bzbug:`683265`) * [API add] Add Signal class for adding and connecting custom signals. (Simon Feltman) (:bzbug:`434924`) * Fix pygtkcompat's Gtk.TreeView.insert_column_with_attributes() (Martin Pitt) * Add override for Gtk.TreeView.insert_column_with_attributes() (Marta Maria Casetti) (:bzbug:`679415`) * .gitignore: Add missing built files (Martin Pitt) * Ship tests/gi in tarball (Martin Pitt) * Split test_overrides.py (Martin Pitt) (:bzbug:`683188`) * _pygi_argument_to_object(): Clean up array unmarshalling (Martin Pitt) * Fix memory leak in _pygi_argument_to_object() (Alban Browaeys) (:bzbug:`682979`) * Fix setting pointer fields/arguments to NULL using None. (Simon Feltman) (:bzbug:`683150`) * Fix for python 2.6, officially drop support for < 2.6 (Martin Pitt) (:bzbug:`682422`) * Allow overrides in other directories than gi itself (Thibault Saunier) (:bzbug:`680913`) * Clean up sys.path handling in tests (Simon Feltman) (:bzbug:`680913`) * Fix dynamic creation of enum and flag gi types for Python 3.3 (Simon Feltman) (:bzbug:`682323`) * [API add] Override g_menu_item_set_attribute (Paolo Borelli) (:bzbug:`682436`) 3.3.90 - 2012-08-20 ------------------- * Implement marshalling for GParamSpec (Mathieu Duponchelle) (:bzbug:`681565`) * Fix erronous import statements for Python 3.3 (Simon Feltman) (:bzbug:`682051`) * Do not fail tests if pyflakes or pep8 are not installed (Martin Pitt) * Fix PEP-8 whitespace checking and issues in the code (Martin Pitt) * Fix unmarshalling of gssize (David Malcolm) (:bzbug:`680693`) * Fix various endianess errors (David Malcolm) (:bzbug:`680692`) * Gtk overrides: Add TreeModelSort.__init__(self, model) (Simon Feltman) (:bzbug:`681477`) * Convert Gtk.CellRendererState in the pygi-convert script (Manuel Quiñones) (:bzbug:`681596`) 3.3.5 - 2012-08-06 ------------------ * Fix list marshalling on big-endian machines (Martin Pitt) (:bzbug:`680693`) * Beautify class/interface type mismatch error messages (Martin Pitt) * Skip instead of fail tests which need Pango, Atk, Gdk, Gtk (Martin Pitt) * [API add] pygtkcompat: Add more pixbuf creation functions (Simon Feltman) (:bzbug:`680814`) * Fix error messages on interface/class type mismatches (Martin Pitt) * Fix crash when returning (False, None) from Gtk.TreeModel.do_get_iter() (Simon Feltman) (:bzbug:`680812`) * Add test case for Gtk.TextIter.forward_search() (Martin Pitt) (:bzbug:`679415`) * pygi-info.c: Robustify pointer arithmetic (Martin Pitt) * Add set_attributes() override to Gtk.TreeViewColumn (Manuel Quiñones) * Gtk overrides: Add TreePath.__getitem__() (Simon Feltman) (:bzbug:`680353`) * Fix property type mapping from int to TYPE_INT for python3. (Simon Feltman) (:bzbug:`679939`) * Convert Gtk.DestDefaults constants in pygi-convert.sh script (Manuel Quiñones) (:bzbug:`680259`) * Convert all Gdk.WindowState constants in pygi-convert.sh (Manuel Quiñones) (:bzbug:`680257`) * [API add] Add API for checking pygobject's version (Joe R. Nassimian) (:bzbug:`680176`) * pygi-convert.sh: Add some missing Gdk.CursorTypes (Manuel Quiñones) (:bzbug:`680050`) * pygi-convert.sh: convert rsvg.Handle(data=...) (Manuel Kaufmann) (:bzbug:`680092`) 3.3.4 - 2012-07-16 ------------------ * pygi-convert.sh: Drop bogus filter_new() conversion (Martin Pitt) (:bzbug:`679999`) * Fix help() for GI modules (Martin Pitt) (:bzbug:`679804`) * Skip gi.CallbackInfo objects from a module's dir() (Martin Pitt) (:bzbug:`679804`) * Fix __path__ module attribute (Martin Pitt) * pygi-convert.sh: Fix some child → getChild() false positives (Joe R. Nassimian) (:bzbug:`680004`) * Fix array handling for interfaces, properties, and signals (Mikkel Kamstrup Erlandsen) (:bzbug:`667244`) * Add conversion of the Gdk.PropMode constants to pygi-convert.sh script (Manuel Quiñones) (:bzbug:`679775`) * Add the same rules for pack_start to convert pack_end (Manuel Quiñones) (:bzbug:`679760`) * Add error-checking for the case where _arg_cache_new() fails (Dave Malcolm) (:bzbug:`678914`) * Add conversion of the Gdk.NotifyType constants to pygi-convert.sh script (Manuel Quiñones) (:bzbug:`679754`) * Fix PyObject_Repr and PyObject_Str reference leaks (Simon Feltman) (:bzbug:`675857`) * [API add] Gtk overrides: Add TreePath.__len__() (Martin Pitt) (:bzbug:`679199`) * GLib.Variant: Fix repr(), add proper str() (Martin Pitt) (:bzbug:`679336`) * m4/python.m4: Update Python version list (Martin Pitt) * Remove "label" property from Gtk.MenuItem if it is not set (Micah Carrick) (:bzbug:`670575`) 3.3.3.1 - 2012-06-25 -------------------- * Do not escape enum and flag names that are Python keywords (Martin Pitt) 3.3.3 - 2012-06-25 ------------------ * Remove obsolete release-tag make target (Martin Pitt) * Do not do any python calls when GObjects are destroyed after the python interpreter has been finalized (Simon Schampijer) (:bzbug:`678046`) * Do not change constructor-only "type" Window property (Martin Pitt) (:bzbug:`678510`) * Escape identifiers which are Python keywords (Martin Pitt) (:bzbug:`676746`) * Fix code for PEP-8 violations detected by the latest pep8 checker. (Martin Pitt) * Fix crash in GLib.find_program_in_path() (Martin Pitt) (:bzbug:`678119`) * Revert "Do not bind gobject_get_data() and gobject_set_data()" (Martin Pitt) (:bzbug:`641944`) * GVariant: Raise proper TypeError on invalid tuple input (David Keijser) (:bzbug:`678317`) 3.3.2 - 2012-06-05 ------------------ * foreign: Register cairo.Path and cairo.FontOptions foreign structs (Bastian Winkler) (:bzbug:`677388`) * Check types in GBoxed assignments (Marien Zwart) (:bzbug:`676603`) * [API add] Gtk overrides: Add TreeModelRow.get_previous() (Bastian Winkler) (:bzbug:`677389`) * [API add] Add missing GObject.TYPE_VARIANT (Bastian Winkler) (:bzbug:`677387`) * Fix boxed type equality (Jasper St. Pierre) (:bzbug:`677249`) * Fix TestProperties.testBoxed test (Jose Rostagno) (:bzbug:`676644`) * Fix handling of by-reference structs as out parameters (Carlos Garnacho) (:bzbug:`653151`) * tests: Add more vfunc checks for GIMarshallingTestsObject (Martin Pitt) * Test caller-allocated GValue out parameter (Martin Pitt) (:bzbug:`653151`) * GObject.bind_property: Support transform functions (Bastian Winkler) (:bzbug:`676169`) * Fix lookup of vfuncs in parent classes (Carlos Garnacho) (:bzbug:`672864`) * tests/test_properties.py: Fix whitespace (Martin Pitt) * gi: Support zero-terminated arrays with length arguments (Jasper St. Pierre) (:bzbug:`677124`) * [API add] Add GObject.bind_property method (Simon Feltman) (:bzbug:`675582`) * pygtkcompat: Correctly set flags (Jose Rostagno) (:bzbug:`675911`) * Gtk overrides: Implement __delitem__ on TreeModel (Jose Rostagno) (:bzbug:`675892`) * Gdk Color override should support red/green/blue_float properties (Simon Feltman) (:bzbug:`675579`) * Support marshalling of GVariants for closures (Martin Pitt) (:bzbug:`656554`) * _pygi_argument_from_object(): Check for compatible data type (Martin Pitt) * pygtkcompat: Fix color conversion (Martin Pitt) * test_gi: Check setting properties in constructor (Martin Pitt) * Support getting and setting GStrv properties (Martin Pitt) * Support defining GStrv properties from Python (Martin Pitt) * Add GObject.TYPE_STRV constant (Martin Pitt) * Unref GVariants when destroying the wrapper (Martin Pitt) (:bzbug:`675472`) * Fix TestArrayGVariant test cases (Martin Pitt) * pygtkcompat: Add gdk.pixbuf_get_formats compat code (Jose Rostagno) (:bzbug:`675489`) * pygtkcompat: Add some more compat functions (Jose Rostagno) (:bzbug:`675489`) * Fix tests for Python 3 (Martin Pitt) * Fix building with --disable-cairo (Martin Pitt) * tests: Fix deprecated assertions (Martin Pitt) * Run tests with ``MALLOC_PERTURB_`` (Martin Pitt) 3.2.2 - 2012-05-14 ------------------ * pygtkcompat: Correctly set flags (Jose Rostagno) (:bzbug:`675911`) * Gtk overrides: Implement __delitem__ on TreeModel (Jose Rostagno) (:bzbug:`675892`) 3.2.1 - 2012-05-10 ------------------ * Reindent files in tests to use 4-space indentation (Sebastian Pölsterl * Add missing override for TreeModel.iter_previous() (Martin Pitt) * GSettings: allow extra keyword arguments (Giovanni Campagna) * pygtkcompat: Correct Userlist module use (Jose Rostagno) * test_gdbus: Call GetConnectionUnixProcessID() with correct signature (Martin Pitt) * GTK overrides: Add missing keyword arguments (Martin Pitt) * pygi-convert.py: Drop obsolete drag method conversions (Martin Pitt) * Fix len_arg_index for array arguments (Bastian Winkler) * Add missing GObject.TYPE_GTYPE (Martin Pitt) * Fix "distcheck" and tests with out-of-tree builds (Martin Pitt) * Add GtkComboBoxEntry compatibility (Paolo Borelli) 3.3.1 - 2012-04-30 ------------------ * GSettings: allow extra keyword arguments (Giovanni Campagna) (:bzbug:`675105`) * pygtkcompat: Correct Userlist module use (Jose Rostagno) (:bzbug:`675084`) * Add release-news make rule (Martin Pitt) * Add "make check.nemiver" target (Martin Pitt) * Test flags and enums in GHash values (Martin Pitt) (:bzbug:`637466`) * tests: Activate test_hash_in and apply workaround (Martin Pitt) (:bzbug:`666636`) * Add special case for Gdk.Atom array entries from Python (Martin Pitt) (:bzbug:`661709`) * test_gdbus: Call GetConnectionUnixProcessID() with correct signature (Martin Pitt) (:bzbug:`667954`) * Add test case for Gtk.ListStore custom sort (Martin Pitt) (:bzbug:`674475`) * GTK overrides: Add missing keyword arguments (Martin Pitt) (:bzbug:`660018`) * [API change] Add missing override for TreeModel.iter_previous() (Martin Pitt) (:bzbug:`660018`) * pygi-convert.py: Drop obsolete drag method conversions (Martin Pitt) (:bzbug:`652860`) * tests: Replace deprecated assertEquals() with assertEqual() (Martin Pitt) * Plug tiny leak in constant_info_get_value (Paolo Borelli) (:bzbug:`642754`) * Fix len_arg_index for array arguments (Bastian Winkler) (:bzbug:`674271`) * Support defining GType properties from Python (Martin Pitt) (:bzbug:`674351`) * Handle GType properties correctly (Bastian Winkler) (:bzbug:`674351`) * Add missing GObject.TYPE_GTYPE (Martin Pitt) * Fix test_mainloop.py for Python 3 (Martin Pitt) * Make callback exception propagation test stricter (Martin Pitt) (:bzbug:`616279`) * [API add] Add context management to freeze_notify() and handler_block(). (Simon Feltman) (:bzbug:`672324`) * Add support for GFlags properties (Martin Pitt) (:bzbug:`620943`) * [API add] Wrap GLib.Source.is_destroyed() method (Martin Pitt) (:bzbug:`524719`) * Fix error message when trying to override a non-GI class (Martin Pitt) (:bzbug:`646667`) * Fix segfault when accessing __grefcount__ before creating the GObject (Steve Frécinaux) (:bzbug:`640434`) * [API change] Do not bind gobject_get_data() and gobject_set_data() (Steve Frécinaux) (:bzbug:`641944`) * Add test case for multiple GLib.MainLoop instances (Martin Pitt) (:bzbug:`663068`) * Add a ccallback type which is used to invoke callbacks passed to a vfunc (John (J5) Palmieri) (:bzbug:`644926`) * Regression test: marshalling GValues in GHashTable (Alberto Mardegan) (:bzbug:`668903`) * Update .gitignore (Martin Pitt) * Fix "distcheck" and tests with out-of-tree builds (Martin Pitt) * Add a pep8 check to the makefile (Johan Dahlin) (:bzbug:`672627`) * PEP8 whitespace fixes (Johan Dahlin) (:bzbug:`672627`) * PEP8: Remove trailing ; (Johan Dahlin) (:bzbug:`672627`) * tests: Replace deprecated Python API (Martin Pitt) * Fail tests if they use or encounter deprecations (Martin Pitt) * Do not run tests in two phases any more (Martin Pitt) * test_overrides: Find local gsettings schema with current glib (Martin Pitt) * Add GtkComboBoxEntry compatibility (Paolo Borelli) (:bzbug:`672589`) * Correct review comments from Martin (Johan Dahlin) (:bzbug:`672578`) * Correct pyflakes warnings/errors (Johan Dahlin) (:bzbug:`672578`) * Make tests fail on CRITICAL logs, too, and apply to all tests (Martin Pitt) * Support marshalling GI_TYPE_TAG_INTERFACE (Alberto Mardegan) (:bzbug:`668903`) * Fix warnings on None values in added tree/list store rows (Martin Pitt) (:bzbug:`672463`) * pygtkcompat test: Properly clean up PixbufLoader (Martin Pitt) 3.2.0 - 2012-03-26 ------------------ * No changes since 3.1.93 except version number. 3.1.93 - 2012-03-22 ------------------- * Fix warnings on None values in added tree/list store rows. (:bzbug:`672463`, Martin Pitt) * Support marshalling GI_TYPE_TAG_INTERFACE (:bzbug:`668903`, Alberto Mardegan) * test_overrides: Find local gsettings schema with current glib (Martin Pitt) * pygtkcompat test: Properly clean up PixbufLoader (Martin Pitt) 3.1.92 - 2012-03-19 ------------------- * Correct Gtk.TreePath.__iter__ to work with Python 3 (Johan Dahlin) * Fix test_everything.TestSignals.test_object_param_signal test case (Martin Pitt) * Add a PyGTK compatibility layer (Johan Dahlin) * pygtkcompat: Remove first argument for get_origin() (Johan Dahlin) * Fix pygtkcompat.py to work with Python 3 (Martin Pitt) * GtkViewport: Add a default values for the adjustment constructor parameters (Johan Dahlin) * GtkIconSet: Add a default value for the pixbuf constructor parameter (Johan Dahlin) * PangoLayout: Add a default value for set_markup() (Johan Dahlin) * Gtk[HV]Scrollbar: Add a default value for the adjustment constructor parameter (Johan Dahlin) * GtkToolButton: Add a default value for the stock_id constructor parameter (Johan Dahlin) * GtkIconView: Add a default value for the model constructor parameter (Johan Dahlin) * Add a default value for column in Gtk.TreeView.get_cell_area() (Johan Dahlin) * Atomic inserts in Gtk.{List,Tree}Store overrides (Martin Pitt) * Fix Gtk.Button constructor to accept use_stock parameter (Martin Pitt) * Correct bad rebase, remove duplicate Window (Johan Dahlin) * Add bw-compatible arguments to Gtk.Adjustment (Johan Dahlin) * GtkTreePath: make it iterable (Johan Dahlin) * Add a default argument to TreeModelFilter.set_visible_func() (Johan Dahlin) * Add a default argument to Gtk.TreeView.set_cursor (Johan Dahlin) * Add a default argument to Pango.Context.get_metrics() (Johan Dahlin) * Fix double-freeing GValues in arrays (Martin Pitt) * Renamed "property" class to "Property" (Simon Feltman) * Fix Python to C marshalling of GValue arrays (Martin Pitt) * Correct the Gtk.Window hierarchy (Johan Dahlin) * Renamed getter/setter instance attributes to fget/fset respectively. (Simon Feltman) * Add Gtk.Arrow/Gtk.Window constructor override (Johan Dahlin) * Fix marshalling to/from Python to work on big endian machines. (Michel Dänzer) * Use gi_cclosure_marshal_generic instead of duplicating it. (Michel Dänzer) * Override Gtk.TreeView.get_visible_range to fix return (René Stadler) * Plug memory leak in _is_union_member (Paolo Borelli) * tests: Split TestInterfaces into separate tests (Sebastian Pölsterl) * README: Update current maintainers (Martin Pitt) 3.1.1 - 2012-02-20 ------------------ * Don't use C99 style (Sebastian Pölsterl) * Add test for GPtrArray with transfer full (Martin Pitt) * Drop obsolete g_thread_init() (Martin Pitt) * Fix deprecated g_source_get_current_time() (Martin Pitt) * Fix deprecated g_value_[gs]et_char() (Martin Pitt) * Make pygiconvert.sh correctly convert gtk.gdk.x11_* (Simon Schampijer) * Raise required glib version to 2.31 because of g_value_(get|set)_schar (Sebastian Pölsterl) * Fix cset_first typo (Dieter Verfaillie) * pygi-convert: Handle Clutter and Cogl (Bastian Winkler) * Provide access to gpointer struct values (Cédric Krier) * Add some GType tests (Paolo Borelli) * Split GStrv and array variant tests in their own classes (Paolo Borelli) * Add unit test for builder's connect_after (Paolo Borelli) * fix GtkBuilder signal connection 'after' logic (Ryan Lortie) * test(1) uses '=' to test if strings are identical (Patrick Welche) * pygspawn: improve error checking (Ryan Lortie) 3.0.4 - 2012-02-09 ------------------ * Revert "Convert all strings to utf-8 encoding when retrieving from TreeModel" (Martin Pitt) * Fixed bug where GObject.property did not respect minimum and maximum values (Sebastian Pölsterl) * Remove mention of removed option --enable-docs (Tomeu Vizoso) 3.1.0 - 2012-02-06 ------------------ * Updated DOAP file to only include people currently actively working on the project (Sebastian Pölsterl) * Revert "Convert all strings to utf-8 encoding when retrieving from TreeModel" (Sebastian Pölsterl) * tests: Fixed issues with python3 (Sebastian Pölsterl) * Properly distinguish between different integer types for properties (Sebastian Pölsterl) * Distinguish between GArray and GPtrArray when cleaning up (Sebastian Pölsterl) * Add null_gerror_callback unit test (Paolo Borelli) * pyglib_error_check: Re-add missing NULL check (Martin Pitt) * Add tests/runtests-windows.py to source tarball (Michael Culbertson) * Don't issue a depreciation warning for GtkDialog's NO_SEPARATOR flag, even when unused (Sebastian Pölsterl) * Fix bool() operations on GLib.Variant objects (Nirbheek Chauhan) * Fix hash() and __eq__() for GLib.Variant objects (Nirbheek Chauhan) * Fix method names of callback tests (Martin Pitt) * Cairo: add missing braces around array-of-struct definition (Will Thompson) * g_instance_init: cast to PyGObject * as needed (Will Thompson) * Fix a few set-but-not-used warnings. (Will Thompson) * pygmainloop: allow for extra arguments in 'quit' method (Stefano Facchini) * Fix bytearray test compatibility with python3 (Alexandre Rostovtsev) * Respect transfer-type when demarshalling GErrors (Alberto Mardegan) * Support GHashTable and GError as callback/closure arguments (Alberto Mardegan) * Don't leak when marshalling GErrors to C (Will Thompson) * Support functions which return GError (Will Thompson) * Fix indentation of _pygi_argument_to_object() (Alberto Mardegan) * Avoid C99 syntax. (Paolo Borelli) * Connect to first action of a radio group. (Paolo Borelli) * Use g_slist_free_full in pygi-closure. (Paolo Borelli) * Avoid O(n^2) behavior when marshalling lists (Paolo Borelli) * Handle NULL as a valid case of a char** array (Paolo Borelli) * Branching, bump version to 3.1.0 (Tomeu Vizoso) * Add notes about branching to HACKING (Tomeu Vizoso) * Fixed bug where GObject.property did not respect minimum and maximum values (Sebastian Pölsterl) * Remove mention of removed option --enable-docs (Tomeu Vizoso) * Fix sebp's name in NEWS (Tomeu Vizoso) 3.0.3 - 2011-12-12 ------------------ * Convert all modifier constants to Gdk.ModifierType (Manuel Quiñones) * Convert all strings to utf-8 encoding when retrieving from TreeModel (Sebastian Pölsterl) * add test for bytearray variants (John (J5) Palmieri) * handle NULL arrays correctly for each array type (John (J5) Palmieri) * Revert "Revert "Fix array termination and size calculation"" (John (J5) Palmieri) * pygmainloop: avoid lockups if multiple glib.MainLoop exist (Owen W. Taylor) * Properly chain up to the class that implements a given vfunc. (Tomeu Vizoso) * Revert "Fix array termination and size calculation" (Tomeu Vizoso) * Fix array termination and size calculation (Holger Berndt) * pygi-convert: fix for Pango.Alignment (Daniel Drake) * pygi-convert: fix for Gtk.Orientation (Daniel Drake) * Add tests for calling closures (Martin Pitt) * fix marshaling of arrays of GVariants (Mikkel Kamstrup Erlandsen) 3.0.2 - 2011-10-21 ------------------ * Add tests for boxed properties. (Ignacio Casal Quinteiro) * Allow GBoxed types as property (Timo Vanwynsberghe) * when converting an object with transfer none, make sure the wrapper owns a ref (John (J5) Palmieri) * unit test for checking ref count of object param in signals (John (J5) Palmieri) * Gdk overrides: Unbreak for Gdk-2.0 (Martin Pitt) * Do union member checks for unions that are parameters (John (J5) Palmieri) 3.0.1 - 2011-09-30 ------------------ * when checking instances union members are same type as parent * add a floating flag to pygobjects * Revert "Fix refcount bug by not creating python wrapper during gobject init stage" 3.0.0 - 2011-09-19 ------------------ * up version required of gobject-introspection to 1.29.0 (John (J5) Palmieri) * fix most warnings (John (J5) Palmieri) 2.90.4 - 2011-09-15 (3.0 pre-release) ------------------------------------- * do not pass in len(str) to the length argument of gtk_test_buffer_insert* apis (John (J5) Palmieri) * Switch tarball compression format to tar.xz only. (Dieter Verfaillie) * Remove pygtk_version attribute from internal gi._gobject module. (Dieter Verfaillie) * remove overridesdir from the .pc file and add it to the gi module (John (J5) Palmieri) * fix tests to correctly construct a dummy Gtk.TargetEntry (John (J5) Palmieri) * we now assume that C arrays of structs are flat so memcpy them when marshalling (John (J5) Palmieri) * only update the arg counts once if child arg comes before parent arg (John (J5) Palmieri) * Fix refcount bug by not creating python wrapper during gobject init stage (John (J5) Palmieri) * don't destroy just created wrapper when object is created via g_object_new (John (J5) Palmieri) * Remove deprecated API from pygobject.h (Steve Frécinaux) * Convert gtk.TRUE/FALSE to Python True/False. (Marcin Owsiany) * Drop legacy __gobject_init__ method of GObject.Object. (Steve Frécinaux) * AM_CHECK_PYTHON_LIBS does not work for lib64 (Dieter Verfaillie) * Remove common_ldflags from Makefile.am as it is no longer used. (Dieter Verfaillie) * check if object is actually a PyGFlag before trying to access g_type (John (J5) Palmieri) * fix regression - add instance type checks since Py3 no longer does this for us (John (J5) Palmieri) * refactor in/out marshalling to be to_py/from_py (John (J5) Palmieri) * Examples: fix cairo-demo.py imports (Dieter Verfaillie) * Fix paths and add missing overridesdir variable used in uninstalled pkgconfig file (Dieter Verfaillie) * Remove no longer used variables from pkgconfig files (Dieter Verfaillie) * docs/Makefile.am and m4/python.m4: Python3 portability fixes (Dieter Verfaillie) * Refactor and clean Makefile.am files (Dieter Verfaillie) * Remove all PLATFORM_VERSION = 2.0 traces (Dieter Verfaillie) * Remove gi/tests/ directory as all the tests now live in tests/ (Dieter Verfaillie) * autogen.sh: Use autoreconf instead of a custom script and honor ACLOCAL_FLAGS (Dieter Verfaillie) * use improved python.m4 macros to search for Python headers and libs (Dieter Verfaillie) * Make maintiner mode enabled by default (Javier Jardón) * Disable documentation for now since they are completely wrong for GI. (Dieter Verfaillie) * Fix documentation installation directory (Dieter Verfaillie) * Remove distutils based build system. (Dieter Verfaillie) * [gtk-demo] Fix syntax highlighter encoding issue (Dieter Verfaillie) * overrides: add constants for atoms (Ignacio Casal Quinteiro) * Drop pygobject_construct() from public API. (Steve Frécinaux) 2.90.3 - 2011-08-31(3.0 pre-release) ------------------------------------ * support skip annotation for return values (John (J5) Palmieri) * Test GPtrArray regression (Xavier Claessens) * Drop support for old constructor style. (Steve Frécinaux) * Drop support for sink functions. (Steve Frécinaux) * Reinstate copying of in-line structs in arrays (Mike Gorse) * fix inline struct array handling (John (J5) Palmieri) * fix on demos (Dieter Verfaillie) * Added support for __setitem__ to TreeModel and support for slices to TreeModelRow (Sebastian Pölsterl) * Convert ACCEL_* constants into Gtk.AccelFlags. (Olav Vitters) * Convert TREE_VIEW_DROP_* constants into Gtk.TreeViewDropPosition (Olav Vitters) 2.90.2 - 2011-08-18 (3.0 pre-release) ------------------------------------- * remove tests that were removed from gi (John (J5) Palmieri) * don't calculate item_size using is_pointer (John (J5) Palmieri) * Updated signal example to use GObject introspection (Timo Vanwynsberghe) * Updated properties example to use GObject introspection (Timo Vanwynsberghe) * Add override for GLib.Variant.split_signature() (Martin Pitt) * [pygi-convert.sh] Handle the import of pygtk and require Gtk 3.0 (Timo Vanwynsberghe) * Install pygobject.h again. (Ignacio Casal Quinteiro) * update the doap file (John (J5) Palmieri) 2.90.1 - 2011-08-14 (3.0 pre-release) ------------------------------------- * pass exta keywords to the Box constructor (John (J5) Palmieri) * add (Tree|List)Store set method override (John (J5) Palmieri) * add test for object arrays (John (J5) Palmieri) * only support C pointer arrays for structs and objects (John (J5) Palmieri) * revert Gtk.Window override because it causes issues with subclasses (John (J5) Palmieri) * take GIL in _pygi_invoke_closure_free (bug :bzbug:`647016`) (Jonathan Matthew) * Add a default parameter to GtkTreeModel.filter_new (Johan Dahlin) * Add vbox/action_area properties (Johan Dahlin) * Add a couple of constructors (Johan Dahlin) * Do not always pass in user_data to callbacks. (Johan Dahlin) * Add a default detail value for Widget.render_icon (Johan Dahlin) * Add an override for Gdk.color_parse() (Johan Dahlin) * Support function calling with keyword arguments in invoke. (Laszlo Pandy) * remove references to deprecated GI_INFO_TYPE_ERROR_DOMAIN (John (J5) Palmieri) * Fix gobject vs. gi.repository warning (Martin Pitt) * make GObject and GLib able to take overrides (John (J5) Palmieri) * avoid dependency issue by importing the internal gobject (John (J5) Palmieri) * fix tests to use the new GLib module (John (J5) Palmieri) * add DynamicGLibModule which works like DynamicGObjectModule (John (J5) Palmieri) * refactor, add objects and types to the correct internal module (John (J5) Palmieri) * rename the pyglib shared library so we don't load the old one (John (J5) Palmieri) * refactor tests to only use PyGObject 3 syntax (John (J5) Palmieri) * refactor the internal _glib module to import correct modules (John (J5) Palmieri) * refactor to use the new internal _glib and _gobject modules (John (J5) Palmieri) * refactor gi module to import and use internal _gobject module (John (J5) Palmieri) * move the static bits internal to gi and refactor build files (John (J5) Palmieri) * remove pygtk.py (John (J5) Palmieri) * introspection is no longer optional (John (J5) Palmieri) * up platform version to 3.0 (John (J5) Palmieri) * [gi] Handle GVariants from callback return values (Martin Pitt) * Handle GVariants for callback arguments (Martin Pitt) * [gi] Fix crash: check return value of _invoke_state_init_from_callable_cache() before continuing. (Laszlo Pandy) * [gi] Pass gtype as first parameter to vfuncs (instead of using kwargs). (Laszlo Pandy) * remove codegen (John (J5) Palmieri) * remove some left over ifdefs to complete merge of the invoke-rewrite branch (John (J5) Palmieri) * rename pygi-invoke-ng to pygi-invoke (John (J5) Palmieri) * make invoke-ng the only invoker (John (J5) Palmieri) * Merge branch 'master' into invoke-rewrite (John (J5) Palmieri) * Merge branch 'master' into invoke-rewrite (John (J5) Palmieri) * split the marshalling routines into two source files (John (J5) Palmieri) * Ship tests/te_ST@nouppera in release tarballs for tests to succeed (Martin Pitt) * [invoke] break out caller_allocates allocating into its own function (John (J5) Palmieri) * [invoke] missed a bit when removing constructor_class usage (John (J5) Palmieri) * [invoke] don't hold on to the constructor class, just add a TODO (John (J5) Palmieri) * [gi] Port test_properties from static gio to GI Gio (Martin Pitt) * [python3] Fix maketrans import (Martin Pitt) * [caching] remove all inline compiler flags (John (J5) Palmieri) * [caching] refactor function names to be less confusing (John (J5) Palmieri) * [overrides] deprecate the use of type keyword MessageDialog constructor (John (J5) Palmieri) * gdbus tests: Fix hang if test case fails (Martin Pitt) * use an enum instead of booleans to denote function type (John (J5) Palmieri) * rename aux arguments to child arguments to make their purpose clearer (John (J5) Palmieri) * Fixed the cairo example (Timo Vanwynsberghe) * Add override binding for Gtk.ListStore.prepend(). (Adam Dingle) * Fix crash in Gtk.TextIter overrides (Martin Pitt) * use gssize instead of int for arg indexes (John (J5) Palmieri) * [cache] remove refrence to default value as it is not implemented yet (John (J5) Palmieri) * Handle arguments that are flags correctly (Sebastian Pölsterl) * correctly initialize the _gi_cairo_functions array to be zero filled (John (J5) Palmieri) * correctly initialize the _gi_cairo_functions array to be zero filled (John (J5) Palmieri) * pass in the address of the gerror, not the gerror itself (John (J5) Palmieri) * [gi] handle marshalling gerrors arguments for signals (John (J5) Palmieri) * [gi-invoke-ng] fix NULL check to check before we access the cache struct (John (J5) Palmieri) * [gi-tests] add test for PyGObject->PyObject TreeModel storage (John (J5) Palmieri) * [gtk-overrides] special case TreeModel columns of PYGOBJECT types (John (J5) Palmieri) * [gi-invoke-ng] copy structs when transfer is full for array (John (J5) Palmieri) * [gtk-override] print warning if user imports Gtk 2.0 (John (J5) Palmieri) * [gtk-overrides] allow the message_type keyword to be used for MessageDialogs (John (J5) Palmieri) * Add support for enums in gobject.property (Johan Dahlin) * Add support for enums in gobject.property (Johan Dahlin) * [gi-invoke-ng] use g_slice for allocating GValues that are caller allocated (John (J5) Palmieri) * [gi-invoke-ng] Convert Overflow errors to ValueErrors when marshalling integers (John (J5) Palmieri) * [gi-invoke-ng] only cache caller allocates for interfaces as some API are broken (John (J5) Palmieri) * [gi-invoke-ng] handle in pointer array marshalling (John (J5) Palmieri) * Adding GPtrArray tests (Alex Eftimie) * [gi-invoke-ng] fix array element offset calculations (John (J5) Palmieri) * [gi] don't clean up arguments that weren't yet processed during in arg failure (John (J5) Palmieri) * [gi-overrides] use new instead of init when constructing a GLib.VariantBuilder (John (J5) Palmieri) * [gi-invoke-ng] actual code to import overrides (John (J5) Palmieri) * [gi-invoke-ng] import pytypes so we get overrides (John (J5) Palmieri) * [gi-invoke-ng] handle gvariants now that they are not foreign (John (J5) Palmieri) * [gi-invoke-ng] do not try to clean up NULL arguments (John (J5) Palmieri) * Merge branch 'master' into invoke-rewrite (John (J5) Palmieri) * Merge branch 'master' into invoke-rewrite (John (J5) Palmieri) * closure: avoid double free crash (Ignacio Casal Quinteiro) * Added __eq__ method for Gdk.Color and Gdk.RGBA (Jason Siefken) * closure: Check the out arg is not null. Fixes bug :bzbug:`651812` (Ignacio Casal Quinteiro) * Use constants instead of literals (Tomeu Vizoso) * GVariant has now a GType, take that into account (Tomeu Vizoso) * GVariantType is a boxed struct (Tomeu Vizoso) * Use _gi.Struct to wrap fundamentals (Tomeu Vizoso) * Merge gi/HACKING into /HACKING (Tomeu Vizoso) * Fix GC-related crash during PyGObject deallocation (Daniel Drake) * [gi-invoke-ng] enable invoke-ng by default (John (J5) Palmieri) * [gi-invoke-ng] add code to clean up when input values fail to marshal (John (J5) Palmieri) * [gi-invoke-ng] add hash cleanup routines (John (J5) Palmieri) * [gi-invoke-ng] handle arrays with transfers of GI_TRANSFER_CONTAINER (John (J5) Palmieri) * [gi-invoke-ng] add list cleanup routines (John (J5) Palmieri) * indentation fix (John (J5) Palmieri) * [gi-invoke-ng] add out array cleanup (John (J5) Palmieri) * [gi-invoke-ng] do not allocate null terminator for garray (John (J5) Palmieri) * [gi-invoke-ng] add array cleanup for in arrays (John (J5) Palmieri) * [gi-invoke-ng] remove remaining bits of the invoke stage state machine (John (J5) Palmieri) * [gi-invoke-ng] revamp cleanup framework to be orthogonal to cache setup (John (J5) Palmieri) * [gi-invoke-ng] stub out a cleaner way of cleaning up after ourselves (John (J5) Palmieri) * Doc Extractor: Correct the logic of the --no-since option. (José Alburquerque) * Doc Extractor: Add a --no-since option. (José Alburquerque) * [gi-invoke-ng] tweek cleanup routines (John (J5) Palmieri) * Fix symbol names to be locale independent (Martin Pitt) * [gi] pygi-convert.sh: Convert gtk.gdk.CROSSHAIR (Martin Pitt) * [gi-invoke-ng] handle filename cleanup with the utf8 cleanup function (John (J5) Palmieri) * [gi-invoke-ng] handle caller allocates cleanup (John (J5) Palmieri) * [gi-invoke-ng] refactor the cleanup code and add utf8 cleanup as initial test (John (J5) Palmieri) * use PyCapsule when importing pycairo/require pycairo 1.10.0 for python3 builds (John (J5) Palmieri) * [python3] fix build. PYcairo_IMPORT doesn't exists anymore (Ignacio Casal Quinteiro) * Updated DOAP file (Sebastian Pölsterl) * [gi] Don't create variant twice (Sebastian Pölsterl) * pygi-convert.sh: Make sure the uppercase GObject module is imported instead of the lowercase (Sebastian Pölsterl) * [gi] Removed hack to avoid using GLib.Variant.new_variant. (Sebastian Pölsterl) * [gi] Added additional test case for GVariant handling (Sebastian Pölsterl) * [gi] Added support for GVariant arguments (Sebastian Pölsterl) * fix static ABI for setting string gvalues from python objects (John (J5) Palmieri) * dsextras.py: ensure eol characters are preserved when writing template files (so \n does not become \r\n) (Dieter Verfaillie) * dsextras.py: remove \r as wel as \n character (Dieter Verfaillie) * use PyCapsule when importing pycairo/require pycairo 1.10.0 for python3 builds (John (J5) Palmieri) * [python3] fix build. PYcairo_IMPORT doesn't exists anymore (Ignacio Casal Quinteiro) * Updated DOAP file (Sebastian Pölsterl) * [gi] Don't create variant twice (Sebastian Pölsterl) * pygi-convert.sh: Make sure the uppercase GObject module is imported instead of the lowercase (Sebastian Pölsterl) * [gi] Removed hack to avoid using GLib.Variant.new_variant. (Sebastian Pölsterl) * [gi] Added additional test case for GVariant handling (Sebastian Pölsterl) * [gi-invoke-ng] fix prototype (John (J5) Palmieri) * [gi-invoke-ng] create new framework for cleaning up args (John (J5) Palmieri) * [gi] Added support for GVariant arguments (Sebastian Pölsterl) * [gi-invoke-ng] fix marshal header that is no longer part of pygi-arguments.h (John (J5) Palmieri) * [gi-invoke-ng] code style space fixes (John (J5) Palmieri) * [gi-invoke-ng] don't decref value taken from a dict as it is borrowed (John (J5) Palmieri) * [gi-invoke-ng] return None when appropriate so we don't crash (John (J5) Palmieri) * [gi-invoke-ng] fix aux value caching (John (J5) Palmieri) * [gi-invoke-ng] backport handling flags with no gtype (John (J5) Palmieri) * [gi-invoke-ng] backport raw gvalue handling (John (J5) Palmieri) * [gi-invoke-ng] marshal instances seperately since they differ slightly from other args (John (J5) Palmieri) * [gi-invoke-ng] refactor FunctionCache to be more generic CallableCache (John (J5) Palmieri) * [gi-invoke-rewrite] backport glib error handling (John (J5) Palmieri) * [gi-invoke-ng] backport closure passing from invoke (John (J5) Palmieri) * [gi-invoke-ng] handle vfuncs and fix cosntrutors (John (J5) Palmieri) * [gi-invoke-ng] handle foreign types correctly (John (J5) Palmieri) * [gi] remove the class parameter from the argument list of constructors (John (J5) Palmieri) * fix static ABI for setting string gvalues from python objects (John (J5) Palmieri) * dsextras.py: ensure eol characters are preserved when writing template files (so \n does not become \r\n) (Dieter Verfaillie) * dsextras.py: remove \r as wel as \n character (Dieter Verfaillie) * [gi] make new invoke-ng codepath compile correctly (John (J5) Palmieri) * [gi] conditionalize invoke code paths (John (J5) Palmieri) * [gi] revert back to the type.py from master (John (J5) Palmieri) * [gi] revert pygi-argument.h and move the invoke-ng code to pygi-marshal.h (John (J5) Palmieri) * Merge branch 'master' into invoke-rewrite (John (J5) Palmieri) * [gi] foreign types now take interface infos instead of type infos (John (J5) Palmieri) * Fix GSchema tests for separate build tree (Martin Pitt) * [gi] start of merge from master (John (J5) Palmieri) * [gi] marshal raw closures (John (J5) Palmieri) * pygi-convert.sh add GObject.xxx and webkit (John Stowers) * pygi-convert.sh remove gobject tests, GObject works now (John Stowers) * [gi-demos] add pickers demo (John (J5) Palmieri) * [gi-demos] add menu demo (John (J5) Palmieri) * [gi-overrides] fix exception block so it works in Python 2.5 (John (J5) Palmieri) * Revert "Deduce PYTHON_LIBS in addition to PYTHON_INCLUDES" (Martin Pitt) * setup.py: fix user_access_control option (Dieter Verfaillie) * [gi] Respect the MessageType for Gtk.MessageDialog (Martin Pitt) * [gi] Do not require signature for D-BUS methods without arguments (Martin Pitt) * [gi-overrides] TreeViewColumn.set_cell_data_func func_data can be None (John Stowers) * [gi-demos] dont try and run demos that represent directories (John Stowers) * [gi-demos] some python 3 compat fixes (John (J5) Palmieri) * [gi-demos] add liststore demo (John (J5) Palmieri) * [gi-demos] catch the correct error class (John (J5) Palmieri) * Do not leak python references when using the gobject.property() helper. (Steve Frécinaux) * handle uchar as bytes, not strings in python 3 (John (J5) Palmieri) * [gi-overrides] handle unichar gvalues when setting treemodels (John (J5) Palmieri) * [gi-overrides] special case python 2 keywords that crept in (John (J5) Palmieri) * check for the py3 _thread module in configure.ac if thread is not found (John (J5) Palmieri) * [gi-demos] add iconview demo (John (J5) Palmieri) * [gi] wrap the keyword argument in a dict so we don't break Python 2.5 (John (J5) Palmieri) * [gi-demos] add the combobox with string ids section to the demos (John (J5) Palmieri) * [gi-overrides] add an override for Gdk.RGBA (John (J5) Palmieri) * [gi-demos] fix up search-entry to reflect annotations fixed in Gtk+ master (John (J5) Palmieri) * [gi-demos] add search entry demo (John (J5) Palmieri) * [gi] wrap map in a list for Python 3 compat (John (J5) Palmieri) * [gi-demos] fix up the validation combobox (John (J5) Palmieri) * add overridesdir variable in the .pc file for 3rd party overrides (John (J5) Palmieri) * setup.py: Set bdist_wininst user-access-control property (Dieter Verfaillie) * Fix uninitialized variable in gi.require_version() (Martin Pitt) * Run tests with LC_MESSAGES="C" (Martin Pitt) * [gi-overrides] override Gtk.stock_lookup to not return success (John (J5) Palmieri) 2.28.6 - 2011-06-11 ------------------- * closure: avoid double free crash (Ignacio Casal Quinteiro) * [gi] backport of "GVariant has a GType" fe386a (John (J5) Palmieri) * [gi] fixes to backport commit 6b5a65 - in older glib GVariants are still structs (John (J5) Palmieri) * GVariantType is a boxed struct (Tomeu Vizoso) * Use _gi.Struct to wrap fundamentals (Tomeu Vizoso) * Added __eq__ method for Gdk.Color and Gdk.RGBA (Jason Siefken) * Remove useless import (Ignacio Casal Quinteiro) * Revert "[gi] Removed hack to avoid using GLib.Variant.new_variant." (Ignacio Casal Quinteiro) * closure: Check the out arg is not null. Fixes bug :bzbug:`651812` (Ignacio Casal Quinteiro) * Fix GC-related crash during PyGObject deallocation (Daniel Drake) * Fix symbol names to be locale independent (Martin Pitt) * Updated DOAP file (Sebastian Pölsterl) 2.28.4 - 2011-04-18 ------------------- * Version bump to 2.24.4 (Sebastian Pölsterl) * [gi] Don't create variant twice (Sebastian Pölsterl) * pygi-convert.sh: Make sure the uppercase GObject module is imported instead of the lowercase (Sebastian Pölsterl) * [gi] Removed hack to avoid using GLib.Variant.new_variant. (Sebastian Pölsterl) * [gi] Added additional test case for GVariant handling (Sebastian Pölsterl) * [gi] Added support for GVariant arguments (Sebastian Pölsterl) * Fix ABI break in old static bindings. (Steve Frécinaux) * fetch size from an enum type (Mike Gorse) * dsextras.py: ensure eol characters are preserved when writing template files (so \n does not become \r\n) (Dieter Verfaillie) 2.28.3 - 2011-03-23 ------------------- * fix a typo when converting objects to strings gvalues (John (J5) Palmieri) 2.28.2 - 2011-03-22 ------------------- * fix static ABI for setting string gvalues from python objects (John (J5) Palmieri) * Fix GSchema tests for separate build tree (Martin Pitt) * GIO tests: Fix remaining test case for separate build tree (Martin Pit * GIO tests: Fix for separate build tree (Martin Pitt) 2.28.1 - 2011-03-21 ------------------- * pygi-convert.sh remove gobject tests, GObject works now (John Stowers) * pygi-convert.sh add GObject.xxx and webkit (John Stowers) * [gi] marshal raw closures (John (J5) Palmieri) * Revert "Deduce PYTHON_LIBS in addition to PYTHON_INCLUDES" (Martin Pitt) * setup.py: fix user_access_control option (Dieter Verfaillie) * [gi-overrides] fix marshalling pygobjects in treemodels (John (J5) Palmieri) * [gi] Respect the MessageType for Gtk.MessageDialog (Martin Pitt) * [gi] Do not require signature for D-BUS methods without arguments (Martin Pitt) * [gi-demos] add pickers demo (John (J5) Palmieri) * [gi-demos] add menu demo (John (J5) Palmieri) * [gi-overrides] TreeViewColumn.set_cell_data_func func_data can be None * [gi-demos] dont try and run demos that represent directories (John Stowers) * [gi-overrides] fix exception block so it works in Python 2.5 (John (J5) Palmieri) 2.28.0 - 2011-03-08 ------------------- * [gi-demos] some python 3 compat fixes (John (J5) Palmieri) * [gi-demos] catch the correct error class (John (J5) Palmieri) * Try not to sink objects returned by C functions. (Steve Frécinaux) * Do not leak python references when using the gobject.property() helper. (Steve Frécinaux) * [gi] fix try except blocks so they work in Python 2.5 (John (J5) Palmieri) * handle uchar as bytes, not strings in python 3 (John (J5) Palmieri) * [gi-overrides] handle unichar gvalues when setting treemodels (John (J5) Palmieri) * [gi-overrides] special case python 2 keywords that crept in (John (J5) Palmieri) * check for the py3 _thread module in configure.ac if thread is not found (John (J5) Palmieri) * [gi-demos] add iconview demo (John (J5) Palmieri) * [gi] wrap the keyword argument in a dict so we don't break Python 2.5 (John (J5) Palmieri) * [gi-demos] add the combobox with string ids section to the demos (John (J5) Palmieri) * [gi-overrides] add an override for Gdk.RGBA (John (J5) Palmieri) * [gi-demos] fix up search-entry to reflect annotations fixed in Gtk+ master (John (J5) Palmieri) * [gi-demos] add search entry demo (John (J5) Palmieri) * [gi] wrap map in a list for Python 3 compat (John (J5) Palmieri) * [gi-demos] fix up the validation combobox (John (J5) Palmieri) * add overridesdir variable in the .pc file for 3rd party overrides (John (J5) Palmieri) * [gi] remove unref for closures since they are floating objects that get sunk (John (J5) Palmieri) * setup.py: Set bdist_wininst user-access-control property (Dieter Verfaillie) * Fix uninitialized variable in gi.require_version() (Martin Pitt) * Run tests with LC_MESSAGES="C" (Martin Pitt) * [gi-overrides] override Gtk.stock_lookup to not return success (John (J5) Palmieri) 2.27.91 - 2011-02-28 (2.28 pre-release) --------------------------------------- * [gi-tests] use Gdk.test_simulate_button instead of emitting event ourselves (John (J5) Palmieri) * [gi-tests] tests for EventButton override. (Laszlo Pandy) * Skip interfaces when checking for conflicts in the MRO (Tomeu Vizoso) * [gi-overrides] Add event methods to all event union members (John (J5) Palmieri) * [gi] check to see if object is a member of a union when validating paramaters (John (J5) Palmieri) * [gi] Remove DyanmicModule.load() to _load() to prevent overriding GI attrs. (Laszlo Pandy) * Test case with John's fix for crash with C arrays and a GError is set. (Laszlo Pandy) * [gi-overrides] fix setting rows in treeview to accept None as a value (John (J5) Palmieri) * [gi] Add value_name for enum and flags from introspection "c:identifier" (if attr is available). (Laszlo Pandy) * Don't force loading of DynamicModule until set in sys.modules (Laszlo Pandy) * Fix flags with multiple names for the same value. (Laszlo Pandy) * [gi-demos] add liststore demo (John (J5) Palmieri) * [gi-demos] run through the demos and remove the FIXMEs that have been fixed (John (J5) Palmieri) * Load typelibs at import time, add gi.require_version() (Tomeu Vizoso) * use GValue support to marshal GtkTreeModel values correctly (John (J5) Palmieri) * [gi] pass raw GValues instead of trying to marshal them (John (J5) Palmieri) * [gi-demos] add icon view edit and drag-and-drop demo (John (J5) Palmieri) * [gi] Register GType for non-GType enums and flags at runtime. (Laszlo Pandy) * [gi-demos] add info bars demo (John (J5) Palmieri) * tests/runtests.py: Add missing "import sys" (Martin Pitt) * [gi] Add Pythonic gdbus method invocation (Martin Pitt) * Skip GError out parameters in Python closure. (Laszlo Pandy) * [gi-demos] added rotate text demo (John (J5) Palmieri) * [gi-demos] add images demo (John (J5) Palmieri) * [gi-demos] add pixbuf demo (John (J5) Palmieri) * [gi-demos] remove fixmes from print demo, fixed in pango (John (J5) Palmieri) * [gi-demos] add printing demo (John (J5) Palmieri) * [gi-overrides] add cursor overrides (John (J5) Palmieri) * [gi-demos] add the links demo (John (J5) Palmieri) * [gi-demos] add expander demo (John (J5) Palmieri) * [gi-overrides] use pop instead of del and add extra tests for Gtk.Table kwargs (John (J5) Palmieri) * [tests] Separate processes for GI and static binding tests. (Laszlo Pandy) * [GI] Remove implicit loading of gi module preserve the code path for static bindings. (Laszlo Pandy) * [gi-demos] add dialogs demo (John (J5) Palmieri) * [gi-overrides] fix typo in GtkTable constructor (John (J5) Palmieri) * [gi-demos] keep popup menu from destroying itself by holding a ref in app class (John (J5) Palmieri) * [gi-overrides] add a Gtk.Menu override for the popup method (John (J5) Palmieri) * [gi-demos] fix the about dialog in appwindow demo (John (J5) Palmieri) * [gi-demos] fix clipboard demo so DnD works (John (J5) Palmieri) * [gi-demos] fix clipboard demo to reflect new API (John (J5) Palmieri) * [gi-demo] Fix color dialog demo to run with new draw, style and color apis (John (J5) Palmieri) * [gi-demos] fix most of the combobox app (John (J5) Palmieri) * Use PyGI type conversion (to fix foreign types) for signal callbacks. (Laszlo Pandy) * [gi-demos] fix drawingarea app to use the new draw api (John (J5) Palmieri) * [gi-overrides] for Gtk 3 alias Gdk.Rectangle to cairo.RectangleInt (John (J5) Palmieri) * [gi-overrides] let user set the proper property names in Gtk.Table (John (J5) Palmieri) * [gi-demos] get appwindow demo working again (John (J5) Palmieri) * [gi-demos] fixed use of tree_iter_get (John (J5) Palmieri) 2.27.90 - 2011-02-11 (2.28 pre-release) --------------------------------------- * fix build to correctly use python-config (John (J5) Palmieri) * Run gio tests separately when enabled (Martin Pitt) * Revert "Remove gio static bindings" (Martin Pitt) * Decrease the refcount for GInitiallyUnowned constructors. (Steve Frécinaux) * Ensure the sink functions are only ran once. (Steve Frécinaux) * Revert "Fix wrong refcount when calling introspected widget constructors" (Steve Frécinaux) * Revert "Fix reference leaks for GInitiallyUnowned objects" (Steve Frécinaux) * Run test suite under dbus-launch (Martin Pitt) * Fix test_gdbus.py to be Python3 friendly (Martin Pitt) * [gi] Provide comfortable GSettings API (Martin Pitt) * Fix vfunc search bug when using GInterfaces and a do_* method. (Laszlo Pandy) * [GI] Add tests for Gtk.Widget.drag_* methods. (Laszlo Pandy) * [python 3] use the right syntaxis to raise exceptions (Ignacio Casal Quinteiro) * [gi] return PYGLIB_MODULE_ERROR_RETURN on error and use pygobject_init (Ignacio Casal Quinteiro) * [gi] return PYGLIB_MODULE_ERROR_RETURN on error (Ignacio Casal Quinteiro) * Fix wrong refcount when calling introspected widget constructors (Steve Frécinaux) * Gdk.Window: Map the standard constructor to the *new* constructor (Simon Schampijer) * Ship tests/org.gnome.test.gschema.xml in dist tarballs (Martin Pitt) * [gi] Add GSettings tests (Martin Pitt) * [gi] Provide GtkTextBuffer.insert_with_tags_by_name() (Martin Pitt) * [gi] Support tag names in GtkTextBuffer.insert_with_tags() (Martin Pitt) * Add MAINTAINERCLEANFILES (Ignacio Casal Quinteiro) * Remove .gitignore files and use git.mk (Ignacio Casal Quinteiro) * pygi-convert.sh: Convert Pango.TabAlign.* (Martin Pitt) * pygi-convert.sh: Drop window -> get_window() conversion (Martin Pitt) * pygi-convert.sh: Don't convert self.window assignments (Martin Pitt) * Fix leaked python reference in python-defined subclasses (Steve Frécinaux) * Add some tests for the number of python refs held at creation time (Steve Frécinaux) * Factor out parameter marshalling from construction functions. (Steve Frécinaux) * [gi] in python 3 an array of uint8 can be bytes but not string (John (J5) Palmieri) * [gi] fix Gio.FileEnumerator to reflect the Python 3 iter protocol (John (J5) Palmieri) * [gi] python 3 fixes (John (J5) Palmieri) * [gi] fix try/except blocks using depricated raise format (John (J5) Palmieri) * [gi] Add docstring to GLib.Variant constructor (Martin Pitt) * [gi] update gdbus test cases for previous GVariant change (Martin Pitt) * [gi] Accept only a single object in GLib.Variant constructor (Martin Pitt) * Speed up _setup_native_vfuncs() (Laszlo Pandy) * Speed up class creation: rewrite _setup_vfuncs() to be much more efficient. (Laszlo Pandy) * pygi-convert.sh: Convert gtk.UI_MANAGER_* (Sebastian Pölsterl) * pygi-convert.sh: Convert gdk.GRAB_* (Sebastian Pölsterl) * [gi] set the gtype GValue correctly (Ignacio Casal Quinteiro) * [gi] use the right argument type for callback (Ignacio Casal Quinteiro) * [gi] Add test cases for GDBus client operations (Martin Pitt) * [gi] Add Variant construction/unpack support for boxed Variants (Martin Pitt) * Merge branch 'windows-setup-fixes' (Dieter Verfaillie) * pygi-convert.sh: GdkPixbuf methods (Thomas Hindoe Paaboel Andersen) * pygi-convert.sh: Gdk.COLORSPACE_RGB (Thomas Hindoe Paaboel Andersen) * [gi] Support nested objects and empty sequences in GLib.Variant building (Martin Pitt) * Uncomment test_gi.TestInterfaceClash (Tomeu Vizoso) * Fix reference leaks for GInitiallyUnowned objects (Steve Frécinaux) * Add tests for refcount of a GObject owned by a library (Steve Frécinaux) * Add a test to check for regular object reference count (Steve Frécinaux) * [gi] Update TreeView.enable_model_drag_{source,dest} to current GTK (Martin Pitt) * Fix a typo in a private symbol name. (Steve Frécinaux) * pygi-convert.sh: Convert glib.source_remove() (Martin Pitt) * Fix typo in previous commit to actually convert glib.GError (Martin Pitt) * pygi-convert.sh: Move some glib bits which are better handled by gobject (Martin Pitt) * Modify override for Gtk.Adjustment to allow position or keyword arguments in __init__(). (Laszlo Pandy) * [gi] Fix small typo in previous commit (Martin Pitt) * [gi] Add pythonic iterator and indexing for string GVariants (Martin Pitt) * Construct structs using default API constructor (Tomeu Vizoso) * pygi-convert.sh: Migrate Gdk.Cursor constructor, and some cursor names (Martin Pitt) * pygi-convert.sh: Handle .window attributes (Martin Pitt) * Also deal with foreign boxed structs (Tomeu Vizoso) * [gi] Convert GErrors to GObject.GError exceptions, and throw them upon returning from calling the C function. (Laszlo Pandy) * pygi-convert.sh: Don't convert glib -> GLib for now (Martin Pitt) * Link libregress.so to GIO_LIBS again (Tomeu Vizoso) * Fix attributes 2BUTTON_PRESS and 3BUTTON_PRESS of Gdk.EventType. (Laszlo Pandy) * [gi] Fixed typo in exception (Sebastian Pölsterl) * [gi] Enable handling of Gdk.EventType.2BUTTON_PRESS and 3BUTTON_PRESS (Sebastian Pölsterl) * Revert "Fix Pango FontDescription override" (Martin Pitt) * Python iterator interface support for GFileEnumerator. (Tony Young) * Remove gio static bindings (Tomeu Vizoso) * [gi] set length when marshalling guint8 erases (Ignacio Casal Quinteiro) * Convert Gdk.Pixbuf to GdkPixbuf.Pixbuf (Sebastian Pölsterl) * Disable calls to PyGILState_* when threads are disabled (Arnaud Charlet) * pygi-convert.sh: Do not comment out set_cell_data_func() calls; these should be ported properly (Martin Pitt) * pygi-convert.sh: Fix match for adding missing imports (Martin Pitt) * pygi-convert.sh: Fix Gtk.Label handling to be idempotent (Martin Pitt) * Remove trailing whitespace from gi/overrides/Gtk.py (Laszlo Pandy) * Fix Pango FontDescription override (Martin Pitt) * tests: Respect existing $GI_TYPELIB_PATH (Martin Pitt) * Merge branch 'value' (Sebastian Pölsterl) * GTK overrides: Do type conversion to column types of ListStore and TreeStore in set_value (Sebastian Pölsterl) * Always register a new GType when a GObject class is subclassed (Steve Frécinaux) * Raise required versions of GLib and GObject-Introspection (Simon van der Linden) * pygi-convert.sh: Handle keysyms (Martin Pitt) * GLib overrides: Add test case for array variant building (Martin Pitt) * Remove cairo.RectangleInt from the foreign module (Tomeu Vizoso) * Dont try to guess the transfer if its a boxed (Tomeu Vizoso) * The tags can be Empty not None. (Ignacio Casal Quinteiro) * Add Pythonic iterators and indexing to GVariant (Martin Pitt) * Add GLib.Variant.unpack() (Martin Pitt) * Add override for gtk_text_buffer_insert_with_tags (Ignacio Casal Quinteiro) * Deduce PYTHON_LIBS in addition to PYTHON_INCLUDES (Simon van der Linden) * Kill JD_CHECK_PYTHON_HEADERS (Simon van der Linden) * Revert "Override Gtk.Box.pack_start and pack_end to set default values to be compliant with pygtk" (Sebastian Pölsterl) * Revert "Override Gtk.CellLayout.pack_start and pack_end to add default values to be compliant with pygtk" (Sebastian Pölsterl) * Revert "Override Gtk.TreeViewColumn.pack_start, pack_end and set_cell_data_func to add default values to be compliant with pygtk" (Sebastian Pölsterl) * pygi-convert.sh: Handle gtk.combo_box_new_text() (Martin Pitt) * Override TreeSortable.set_sort_func and set_default_sort_func to add default values to be pygtk compliant (Sebastian Pölsterl) * Override Gtk.TreeViewColumn.pack_start, pack_end and set_cell_data_func to add default values to be compliant with pygtk (Sebastian Pölsterl) * Override Gtk.CellLayout.pack_start and pack_end to add default values to be compliant with pygtk (Sebastian Pölsterl) * Override Gtk.Paned pack1 and pack2 to add default values to be compliant with pygtk (Sebastian Pölsterl) * Override Gtk.Box.pack_start and pack_end to set default values to be compliant with pygtk (Sebastian Pölsterl) * Handle GObject subclasses in the property helper. (Steve Frécinaux) * Fix handling of unicode for GtkTreeModels (Martin Pitt) * In IntrospectionModule and DynamicModule classes, make all instance attributes start with an underscore. (Laszlo Pandy) * Amend previous enum wrapping commit to remove redundant setting of __info__ attribute. (Laszlo Pandy) * pygi-convert.sh: Handle GdkPixbuf.InterpType (Martin Pitt) * Fix wrapping of enums: Create new Python type for each non-gtype enum. (Laszlo Pandy) * Use g_vfunc_info_invoke for chaining up in vfuncs (Tomeu Vizoso) * Move pyglib_{main_context, option_context, option_group}_new into _PyGLib_API (Simon van der Linden) * pygi-convert.sh: Handle Gdk.DragAction (Martin Pitt) * pygi-convert.sh: Generalize Gtk.Settings migration (Martin Pitt) * pygi-convert.sh: Don't change the name of "glib" submodules (Martin Pitt) * Plug another memory leak (Paolo Borelli) * Plug a small memory leak. (Paolo Borelli) * Override Table.attach() to behave like pygtk (Paolo Borelli) * pygi-convert.sh: Convert Pango.WrapMode (Martin Pitt) * pygi-convert.sh: Don't change the name of "gtk" submodules (Martin Pitt) * Fix the __dir__() methods on DynamicModule and IntrospectionModule (Laszlo Pandy) * pygi-convert.sh: handle ReliefStyle (Paolo Borelli) * setup.py: fix the provides keyword argument (Dieter Verfaillie) * setup.py: use the same spaces-less format for all setup() parameters (Dieter Verfaillie) * Add a __repr__() method to DynamicModule. (Laszlo Pandy) * Go back to using getattr() in DynamicModule.__getattr__ (Tomeu Vizoso) * Change __dir__() to report all the attributes that __getattr__ supports (Laszlo Pandy) * Bump the minimum gio dependency (Emilio Pozuelo Monfort) * Add test for incorrect attributes in Gdk.Event (Tomeu Vizoso) * Don't call getattr again in gi.overrides.Gdk.Event.__getattr__ (Simon van der Linden) * Release allocated array of arguments when handling closures (Mike Gorse) * Release GIValueInfo when checking an enum argument (Mike Gorse) * Respect different type lengths when assigning out-argument pointers. (Eitan Isaacson) * Fix stupid name clash (Tomeu Vizoso) * Add /usr/share to XDG_DATA_DIRS when running the tests (Tomeu Vizoso) * Comment out tests that require SRV lookups (Tomeu Vizoso) * Use suppresion file when running valgrind (Tomeu Vizoso) * Fix warnings. (Ignacio Casal Quinteiro) * Allow comparing Gtk.TreePath to None (Jesse van den Kieboom) * handle unicode objects in properties (John (J5) Palmieri) * dsextras.py: check if gcc is there when platform is win32 and compiler is mingw32 (Dieter Verfaillie) * dsextras.py: be consistent in how distutils imports are done (Dieter Verfaillie) * dsextras.py: add have_gcc() function (Dieter Verfaillie) * dsextras.py: use distutils.spawn.find_executable for have_pkgconfig() (Dieter Verfaillie) * setup.py: fix another case of use True/False instead of 1/0 (Dieter Verfaillie) * pygi-convert.sh: improve GtkSourceView conversion (Paolo Borelli) * pygi-convert.sh: Gtk.DialogFlags conversion (Paolo Borelli) * Doc Extractor: Print the gtk-doc blocks sorted by function name. (José Alburquerque) * pygi-convert.sh: add more Gtk conversions and sort (Paolo Borelli) * pygi-convert.sh: convert Atk (Paolo Borelli) * pygi-convert.sh: convert a few more Gio types (Paolo Borelli) * pygi-convert.sh: more GLib conversion (Paolo Borelli) * pygi-convert.sh: remove two cases handled by overrides (Paolo Borelli) * Override Gtk.ScrolledWindow constructor (Paolo Borelli) * pygi-convert.sh: Fix 'find' syntax (Paolo Borelli) * pygi-convert.sh: start handling Gio and GLib (Paolo Borelli) * pygi-convert.sh: convert Gdk.ScrollDirection. (Paolo Borelli) * Override Pango.Layout constructor. (Paolo Borelli) * Remove Pango.FontDescription() conversion. (Paolo Borelli) * Override GtkAction and GtkRadioAction constructors. (Paolo Borelli) * Override Adjustment constructor to behave like pygtk (Dmitrijs Ledkovs) * add secondary_text apis to MessageDialog (John (J5) Palmieri) * [gi] get rid of some debug prints and fix error messages (John (J5) Palmieri) * Fix demo for override changes. (Paolo Borelli) * Override Pango.FontDescription. (Paolo Borelli) * Stop checking that all vfuncs are implemented (Tomeu Vizoso) * Fix usage of TreeIter api that is now an override. (Paolo Borelli) * Fix Gtk.Label(label="Foo") (Paolo Borelli) * Fix typo when raising an exception (Paolo Borelli) * pygi-convert.sh: Added more conversions (Sebastian Pölsterl) * Override LinkButton constructor to make 'uri' mandatory (Paolo Borelli) * Container should be iterable. (Dmitry Morozov) * No need to import Gdk (Paolo Borelli) * Remove semicolumns (Paolo Borelli) * [gi] make sure Gtk.Button override passes all keywords to parent constructor (John (J5) Palmieri) * Fix cut&paste error in the Label override (Paolo Borelli) * pygi-convert.sh: handle TextWindowType (Paolo Borelli) * Override Label constructor to behave like pygtk (Paolo Borelli) * Override GtkTable constructor to behave like pygtk (Paolo Borelli) * pygi-convert.sh: convert MovementStep (Paolo Borelli) * Update Gdk overrides to work with latest Gtk+ 3 (Paolo Borelli) * Gtk: add an override for Gtk.main_quit (Johan Dahlin) * [gi] handle subtypes when inserting into tree models (John (J5) Palmieri) * Override TreeSelection.select_path and TreeView.scroll_to_cell (Paolo Borelli) * Override TreePath.__new__ (Paolo Borelli) * Override Container to behave like a sequence (Paolo Borelli) * refactor Jonathan Matthew recurse vfunc patch so it applys and clean up a bit (John (J5) Palmieri) * Recurse up through base classes when setting up vfuncs (Jonathan Matthew) * add a profiling torture test for when we fix up invoke (John (J5) Palmieri) * moved dynamic and base modules outside of gtk-2.0 directory (John (J5) Palmieri) * add test for inout argument count (John (J5) Palmieri) * [gi] add check for UNICHAR (John (J5) Palmieri) * Support gunichar (Paolo Borelli) * pygi-convert.sh: gtk.accel_map -> Gtk.AccelMap._ (Paolo Borelli) * pygi-convert.sh: handle "from gtk import gdk" (Paolo Borelli) * pygi-convert.sh: add some Pango special cases (Paolo Borelli) * Override TextIter (begins|ends|toggles)_tag() (Paolo Borelli) * Override TextBuffer.set_text() to make length optional (Paolo Borelli) * Override TextBuffer.create_mark() (Paolo Borelli) * Fix TextBuffer.get_selection_bounds() override (Paolo Borelli) * [gi] fix ActionGroup constructor to allow other keyword properties to be set (John (J5) Palmieri) * [gi] require the name parameter when creatin a Gtk.ActionGroup (John (J5) Palmieri) * Override UIManager.insert_action_group (Paolo Borelli) * Override TreeModel.get() to return a tuple (Paolo Borelli) * Make TreeSelection.get_selected_rows compatible with PyGtk (Paolo Borelli) * [gi] switch to using sequences/tuples when marshalling cairo_rectangle_int_t (John (J5) Palmieri) * [gi] overrides for treeview Drag and Drop (John (J5) Palmieri) * [gi] when encountering guint8 arrays treat them as byte arrays (John (J5) Palmieri) * pygi-convert.sh: Add pynotify -> Notify (Martin Pitt) * pygi-convert.sh: Remove sugar specifics, and allow command line file list (Martin Pitt) * pygi-convert.sh: Cover Message and Buttons types (Martin Pitt) * [gi] fix actiongroup test since actions are hashed (John (J5) Palmieri) * [gi] when converting to UTF-8 accept Python Unicode objects as input (Python 2) (John (J5) Palmieri) * Correct a bug in the freeing of memory in pygi-invoke.c. (Damien Caliste) * update news for release (John (J5) Palmieri) * Implement richcompare for GIBaseInfo (Jonathan Matthew) * [gi] add the rectangle_int_t forign cairo type (John (J5) Palmieri) * add a foreign type for cairo_rectangle_int_t and allow it to be caller-allocated (John (J5) Palmieri) * [gi] add overrides to Gtk.Editable (John (J5) Palmieri) * [gi] handle virtual invokers (John (J5) Palmieri) * add overrides for the insert* apis of list_store and tree_store (John (J5) Palmieri) * fix dialogs overrides which were relying on broken inheritance behavior (John (J5) Palmieri) * Add a overrides registry so we can refrence overrides inside the module (John (J5) Palmieri) * Merge remote branch 'dieterv/setup-fixes-for-merge' (John Stowers) * setup.py: ease maintenance burden for tests installation (Dieter Verfaillie) * fix inheritence issues in overrides (John (J5) Palmieri) * tests: add runtests-windows.py script (Dieter Verfaillie) * pygobject_postinstall.py: remove pygobject-2.0.pc treatment from postinstall as pkg-config on windows figures out the correct prefix at runtime (Dieter Verfaillie) * pygobject_postinstall.py: remove shortcut creation (Dieter Verfaillie) * setup.py: formatting cleanup, makes things readable (Dieter Verfaillie) * setup.py: build and install tests (Dieter Verfaillie) * setup.py: install documentation when available on build system (Dieter Verfaillie) * setup.py: install pygobject-codegen script (Dieter Verfaillie) * setup.py: install fixxref.py script (Dieter Verfaillie) * setup.py: rearrange constants (Dieter Verfaillie) * setup.py: check python version and pkgconig availability before anything else (Dieter Verfaillie) * setup.py: simplify sys.platform != 'win32' detection and error reporting (Dieter Verfaillie) * setup.py: rearrange imports (Dieter Verfaillie) * README.win32: update build instructions (Dieter Verfaillie) * dsextras.py: formatting cleanup, makes things readable (Dieter Verfaillie) * dsextras.py: add ggc4 to MSVC compatible struct packing comment (Dieter Verfaillie) * dsextras.py: use the ``pkgc_`` functions instead of repeating pgk-config incantations all over the place (Dieter Verfaillie) * dsextras.py: add pkgc_get_version and pkgc_get_defs_dir functions (Dieter Verfaillie) * dsextras.py: PEP8: Comparisons to singletons like None should always be done with 'is' or 'is not', never the equality operators. (Dieter Verfaillie) * dsextras.py: use True/False instead of 1/0 (Dieter Verfaillie) * dsextras.py: rearrange imports (Dieter Verfaillie) * Add distutils generated build/dist directories and eclipse configuration files to .gitignore (Dieter Verfaillie) * [gi] add tests for calling dir on a dynamic module (John (J5) Palmieri) * [gi] dir() now works for modules (Deepankar Sharma) * Don't check the inner type when comparing gpointers (Simón Pena) * Release GIL when calling into C functions (John (J5) Palmieri) * _gi.Repository : Implement missing info bindings. (José Aliste) * include Python.h so that PY_VERSION_HEX gets defined (John (J5) Palmieri) * [gi] make overrides work for python 3.x protocols and alias for python 2.x (John (J5) Palmieri) * Override Gtk.Widget.translate_coordinates to not return success value (Sebastian Pölsterl) * Override Gtk.TreeViewColumn.cell_get_position to not return success value (Sebastian Pölsterl) * Override get_path_at_pos and get_dest_row_at_pos of Gtk.TreeView to not return success value (Sebastian Pölsterl) * Override Gtk.TreeSortable.get_sort_column_id to not return success value (Sebastian Pölsterl) * Override forward_search and backward_search of Gtk.TextIter to not return success value (Sebastian Pölsterl) * Override Gtk.TextBuffer.get_selection_bounds to not return success value (Sebastian Pölsterl) * Override Gtk.RecentInfo.get_application_info to not return success value (Sebastian Pölsterl) * Override Gtk.IMContext.get_surrounding to not return success value (Sebastian Pölsterl) * Override get_item_at_pos, get_visible_range, get_dest_item_at_pos of Gtk.IconView to not return success value (Sebastian Pölsterl) * Override Gtk.Container.get_focus_chain to not return success value (Sebastian Pölsterl) * Override Gtk.ComboBox.get_active_iter to not return success value (Sebastian Pölsterl) * [gi] make parameter check less strict when dealing with GValue params (John (J5) Palmieri) * Shortcut removal is not needed on post-uninstall (John Stowers) * Disable shortcut creation in windows installer (John Stowers) * overrides for all subclasses of dialog (John (J5) Palmieri) * Make TreeModel behave like in GTK-2.x (Sebastian Pölsterl) * Correctly build GIO on windows (John Stowers) * Require Python >= 2.6.0 for Windows build (John Stowers) * Fix depreciation warning in dsextras.py (John Stowers) * Fix build on windows (John Stowers) * Support for GCC4 in Windows distutils build - bug 626548 (Michael Culbertson) * Remove obsolete comments in dsextras.py (John Stowers) * Broken dsextras.py pkg-config check error message (John Stowers) * add compat functions for the deprecated PyCObject api (John (J5) Palmieri) * Add __path__ attributes. (Damien Caliste) * Override Gtk.TreeSelection.get_selected to not return success value. (Sebastian Pölsterl) * Make row optional in Gtk.TreeStore/ListStore.append override (Vincent Untz) * Revert "add compat functions for the deprecated PyCObject api" (John (J5) Palmieri) * return NULL instead of -1 which fixes crash when introspection is turned off (John (J5) Palmieri) * add compat functions for the deprecated PyCObject api (John (J5) Palmieri) * fix commit 7fe83108 which didn't use the compat functions for string handling (John (J5) Palmieri) * Python 3 fixes for dsextras and the python.m4 distribution files (John (J5) Palmieri) 2.27.0 - 2010-11-10 ------------------- * Implement richcompare for GIBaseInfo (Jonathan Matthew) * [gi] add the rectangle_int_t forign cairo type (John (J5) Palmieri) * add a foreign type for cairo_rectangle_int_t and allow it to be caller-allocated (John (J5) Palmieri) * [gi] add overrides to Gtk.Editable (John (J5) Palmieri) * [gi] handle virtual invokers (John (J5) Palmieri) * add overrides for the insert* apis of list_store and tree_store (John (J5) Palmieri) * fix dialogs overrides which were relying on broken inheritance behavior (John (J5) Palmieri) * Add a overrides registry so we can refrence overrides inside the module (John (J5) Palmieri) * Merge remote branch 'dieterv/setup-fixes-for-merge' (John Stowers) * setup.py: ease maintenance burden for tests installation (Dieter Verfaillie) * fix inheritence issues in overrides (John (J5) Palmieri) * tests: add runtests-windows.py script (Dieter Verfaillie) * pygobject_postinstall.py: remove pygobject-2.0.pc treatment from postinstall as pkg-config on windows figures out the correct prefix at runtime (Dieter Verfaillie) * pygobject_postinstall.py: remove shortcut creation (Dieter Verfaillie) * setup.py: formatting cleanup, makes things readable (Dieter Verfaillie) * setup.py: build and install tests (Dieter Verfaillie) * setup.py: install documentation when available on build system (Dieter Verfaillie) * setup.py: install pygobject-codegen script (Dieter Verfaillie) * setup.py: install fixxref.py script (Dieter Verfaillie) * setup.py: rearrange constants (Dieter Verfaillie) * setup.py: check python version and pkgconig availability before anything else (Dieter Verfaillie) * setup.py: simplify sys.platform != 'win32' detection and error reporting (Dieter Verfaillie) * setup.py: rearrange imports (Dieter Verfaillie) * README.win32: update build instructions (Dieter Verfaillie) * dsextras.py: formatting cleanup, makes things readable (Dieter Verfaillie) * dsextras.py: add ggc4 to MSVC compatible struct packing comment (Dieter Verfaillie) * dsextras.py: use the ``pkgc_`` functions instead of repeating pgk-config incantations all over the place (Dieter Verfaillie) * dsextras.py: add pkgc_get_version and pkgc_get_defs_dir functions (Dieter Verfaillie) * dsextras.py: PEP8: Comparisons to singletons like None should always be done with 'is' or 'is not', never the equality operators. (Dieter Verfaillie) * dsextras.py: use True/False instead of 1/0 (Dieter Verfaillie) * dsextras.py: rearrange imports (Dieter Verfaillie) * Add distutils generated build/dist directories and eclipse configuration files to .gitignore (Dieter Verfaillie) * [gi] add tests for calling dir on a dynamic module (John (J5) Palmieri) * [gi] dir() now works for modules (Deepankar Sharma) * Don't check the inner type when comparing gpointers (Simón Pena) * Release GIL when calling into C functions (John (J5) Palmieri) * _gi.Repository : Implement missing info bindings. (José Aliste) * include Python.h so that PY_VERSION_HEX gets defined (John (J5) Palmieri) * [gi] make overrides work for python 3.x protocols and alias for python 2.x (John (J5) Palmieri) * Override Gtk.Widget.translate_coordinates to not return success value (Sebastian Pölsterl) * Override Gtk.TreeViewColumn.cell_get_position to not return success value (Sebastian Pölsterl) * Override get_path_at_pos and get_dest_row_at_pos of Gtk.TreeView to not return success value (Sebastian Pölsterl) * Override Gtk.TreeSortable.get_sort_column_id to not return success value (Sebastian Pölsterl) * Override forward_search and backward_search of Gtk.TextIter to not return success value (Sebastian Pölsterl) * Override Gtk.TextBuffer.get_selection_bounds to not return success value (Sebastian Pölsterl) * Override Gtk.RecentInfo.get_application_info to not return success value (Sebastian Pölsterl) * Override Gtk.IMContext.get_surrounding to not return success value (Sebastian Pölsterl) * Override get_item_at_pos, get_visible_range, get_dest_item_at_pos of Gtk.IconView to not return success value (Sebastian Pölsterl) * Override Gtk.Container.get_focus_chain to not return success value (Sebastian Pölsterl) * Override Gtk.ComboBox.get_active_iter to not return success value (Sebastian Pölsterl) * [gi] make parameter check less strict when dealing with GValue params (John (J5) Palmieri) * Shortcut removal is not needed on post-uninstall (John Stowers) * Disable shortcut creation in windows installer (John Stowers) * overrides for all subclasses of dialog (John (J5) Palmieri) * Make TreeModel behave like in GTK-2.x (Sebastian Pölsterl) * Correctly build GIO on windows (John Stowers) * Require Python >= 2.6.0 for Windows build (John Stowers) * Fix depreciation warning in dsextras.py (John Stowers) * Fix build on windows (John Stowers) * Support for GCC4 in Windows distutils build - bug 626548 (Michael Culbertson) * Remove obsolete comments in dsextras.py (John Stowers) * Broken dsextras.py pkg-config check error message (John Stowers) * add compat functions for the deprecated PyCObject api (John (J5) Palmieri) * Add __path__ attributes. (Damien Caliste) * Override Gtk.TreeSelection.get_selected to not return success value. (Sebastian Pölsterl) * Make row optional in Gtk.TreeStore/ListStore.append override (Vincent Untz) * Revert "add compat functions for the deprecated PyCObject api" (John (J5) Palmieri) * return NULL instead of -1 which fixes crash when introspection is turned off (John (J5) Palmieri) * add compat functions for the deprecated PyCObject api (John (J5) Palmieri) * fix commit 7fe83108 which didn't use the compat functions for string handling (John (J5) Palmieri) * Python 3 fixes for dsextras and the python.m4 distribution files (John (J5) Palmieri) 2.26.0 - 2010-09-24 ------------------- * Wrap g_get_system_{config,data}_dirs () (John Strowers) * fixed make check and make dist (John (J5) Palmieri) * Disable GI tests when introspection disabled (John Stowers) * Wrap g_uri_list_extract_uris. Fixes bug :bzbug:`584431` (Tomeu Vizoso) * Fix a few uses of TRUE and FALSE in the docs (Paul Bolle) * pygi: always free the invocation_state struct (Damien Caliste) * Start implementing something equivalent to g_variant_new (Tomeu Vizoso) * fixed typo - missing comma in glib.option module (John (J5) Palmieri) * add checks so we can compile under python 3 by setting PYTHON=python3 (John (J5) Palmieri) * Rename static methods as functions (Tomeu Vizoso) * fix a couple of compiler warnings (John (J5) Palmieri) * remove unused code (John (J5) Palmieri) * Check the type of the instance object (John (J5) Palmieri) * include the correct pycairo version (John (J5) Palmieri) * Use PyMapping_Keys to determine if an object is a dict (py3k fix) (John (J5) Palmieri) * fix handling of UINT64 and INT64 arguments in py3k (John (J5) Palmieri) * properly handle ulongs properties in py3k (John (J5) Palmieri) * Specify encoding of tests/test_gi.py (Tomeu Vizoso) * use actual unicode in the tests on py3k, not the byte representation (John (J5) Palmieri) * s/METH_KEYWORDS/METH_VARARGS|METH_KEYWORDS/ when defining object methods (John (J5) Palmieri) * fix subclassing PyLong by calling __new__ correctly (John (J5) Palmieri) * minor py3k fixups for python modules (John (J5) Palmieri) * minor fixes in tests for py3k compat (John (J5) Palmieri) * compilation: Fix syntax error (Colin Walters) * Add missing file (Tomeu Vizoso) * Add override for GLib.Variant.new_tuple (Tomeu Vizoso) * fix for changes in the gi test libraries (John (J5) Palmieri) * Gtk.DialogFlags.NO_SEPARATOR has been removed in Gtk 3.0 (John (J5) Palmieri) * no need to offset arg positions when is_method is true (John (J5) Palmieri) * gi: Add support for more property types (Tomeu Vizoso) * use PyObject_SetAttrString, not PyDict_SetItemString when setting __gtype__ (John (J5) Palmieri) * Rename GArgument to GIArgument (Tomeu Vizoso) * fix up tests so they run in py3k (John (J5) Palmieri) * tests: Port to new introspection tests (Colin Walters) * we need to specify tp_hash since we overide tp_richcompare (John (J5) Palmieri) * working enum/flags/pid subclasses of long (John Ehresman) * make vfuncs work in py3k (John (J5) Palmieri) * make cairo module compile in py3k (John (J5) Palmieri) * fix exceptions so they work in python 3.x (John (J5) Palmieri) * make the gi module compile under 3.x (John (J5) Palmieri) * fix up testshelper module so it compiles in python 3.x (John (J5) Palmieri) * convert to using PYGLIB_DEFINE_TYPE for module objects (John (J5) Palmieri) * some more p3k PyString and PyInt eradication in GI (John (J5) Palmieri) * pyglib: Fix typo (Leo Singer) (Tomeu Vizoso) * Add defines for size_t and ssize_t conversion functions (Gustavo Noronha Silva) * pyglib: Fix a compiler warning (Colin Walters) * Don't force gtk 2.0 (Tomeu Vizoso) * Fix some ref leaks in hook_up_vfunc_implementation() (Steve Frécinaux) * handle strings correctly in gio (John (J5) Palmieri) * make giomodule compile under py3k (John (J5) Palmieri) * for py3k we need to do some more processing to get bytes from a unicode string (John (J5) Palmieri) * use Bytes instead of Unicode when reading io (John (J5) Palmieri) * prefix compat macros with PYGLIB (John (J5) Palmieri) * Gtk.Button unit tests (John (J5) Palmieri) * [Gtk] Add overrides for Button (Johan Dahlin) * Make Cairo an optional dependency (Simon van der Linden) * Don't import again PyGObject (John Ralls) (Tomeu Vizoso) * move to using richcompare slot instead of compare (John (J5) Palmieri) * Replace autogen.sh by a newer version (Simon van der Linden) * Fix some warnings (Simon van der Linden) * Fix caller-allocates emergency free. (Simon van der Linden) * Remove useless checks. (Simon van der Linden) * Call valgrind with G_SLICE=always-malloc G_DEBUG=gc-friendly (Tomeu Vizoso) * Fix some warnings. (Ignacio Casal Quinteiro) * Add myself as a maintainer (Simon van der Linden) * Properly allocate boxed structs that are (caller-allocates) (Tomeu Vizoso) * override gdk.Event to return attribute from the proper event object (Toms Baugis) * check if z# needs an int or Py_ssize_t (John (J5) Palmieri) * make sure we parse parameters to python object vars not glib vars (John (J5) Palmieri) * Make an example and a demo work out of the box (Paul Bolle) * make sure caller allocated structs are freed when they go out of scope (John (J5) Palmieri) * Revert "override gdk.Event to return attribute from the proper event object." (Tomeu Vizoso) * PyGI: properly quit cairo-demo (Paul Bolle) * override gdk.Event to return attribute from the proper event object. (Toms Baugis) * Clean and improve the test infrastructure (Simon van der Linden) * Add some more transformations to pygi-convert.sh (Tomeu Vizoso) * Adapt to API changes: g_irepository_enumerate_versions (Tomeu Vizoso) * Add GValue<->GArgument marshalling for some more types (Tomeu Vizoso) * Chain up with the non-introspection implementation for properties if needed (Tomeu Vizoso) * Improve error reporting for missing attributes in introspection modules (Tomeu Vizoso) * Implement getting and setting properties using introspection information. (Tomeu Vizoso) * Readd Gdk.Rectangle override for Gtk-2.0 (Tomeu Vizoso) * Allow specifying a version when loading a typelib (Tomeu Vizoso) * treat GFreeFunc as equivalent to GDestroyNotify when scanning callbacks (Jonathan Matthew) * Don't use == to compare doubles, use <= and =>. (Simon van der Linden) * Allow passing ints as enum args (Tomeu Vizoso) * Make error message less ambiguous (Tomeu Vizoso) * fix passing in type names as a GType and add gtype unit tests (John (J5) Palmieri) * Increase a bit verbosity of tests so people know which test failed (Tomeu Vizoso) * Actually add the files for GVariant foreign structs (Tomeu Vizoso) * Add foreign struct support for GVariant (Tomeu Vizoso) 2.21.5 - 2010-07-12 ------------------- * Shut up some compiler warnings (Florian Müllner) * Adjust to API break in GObject-Introspection (Florian Müllner) * pass in the demo app so demos can use utility methods like requesting file paths (John (J5) Palmieri) * demo fixes to keep up with Gtk+ (John (J5) Palmieri) * override test fixes for new GTK+ annotations (John (J5) Palmieri) * Fix warning. (Ignacio Casal Quinteiro) * fix up treeiter usage due to caller-allocates annotations in gtk+ (John (J5) Palmieri) * add entry completion demo (John (J5) Palmieri) * string changes (John (J5) Palmieri) * add the Entry demo directory and the entry_buffer demo (John (J5) Palmieri) * fix loading of demo modules to support sub modules (John (J5) Palmieri) * add the ability to have demos in sub catagories (John (J5) Palmieri) * Add __name__ to DynamicModule class. (Jose Aliste) * Do not override GdkRectangle. (Ignacio Casal Quinteiro) * Add override for TreeModel implementing __len__() (Philip Withnall) 2.21.4 - 2010-06-29 ------------------- * Build the cairo shim as a python module so the _gi module stops linking to it (Tomeu Vizoso) * add drawing area demo (John (J5) Palmieri) * sort the demo list (John (J5) Palmieri) * rename iter to treeiter so we aren't using a python reserved word (John (J5) Palmieri) * Fixup for change in buffer API (John (J5) Palmieri) * add ListStore, TreeStore and TreeViewColumn APIs (John (J5) Palmieri) * Add unit test for add_actions user data. (Ignacio Casal Quinteiro) * Pass user_data param when adding actions (Paolo Borelli) * add an exception type to the try/except block (John (J5) Palmieri) * return PyList instead of PyTuple for array, return empty list for NULL arrays (John (J5) Palmieri) * Fix 'make distcheck' (Tomeu Vizoso) * Allow building pygobject without introspection support by providing --disable-introspection to configure. (Tomeu Vizoso) * Make sure that sys.argv is a list and not a sequence. (Tomeu Vizoso) * Force loading the GObject typelib so we have available the wrappers for base classes such as GInitiallyUnowned. (Tomeu Vizoso) * we shouldn't g_array_free NULL pointers (John (J5) Palmieri) * remove unneeded TextIter creation in the tests (John (J5) Palmieri) * add override for TextBuffer (John (J5) Palmieri) * fix up some build issues (John (J5) Palmieri) * make the overrides file git friendly by appending to __all__ after each override (John (J5) Palmieri) * Override Dialog constructor and add_buttons method (Paolo Borelli) * Merge PyGI (Johan Dahlin) 2.21.3 - 2010-06-21 ------------------- * Proper handling of null-ok in virtual methods (Ludovic L'Hours) * Fall back to use the floating references API in glib if there isn't a sinkfunc defined. (Tomeu Vizoso) * Revert "Drop sinkfuncs." (Tomeu Vizoso) * [giounix] Make it possible to compile on glib 2.20 (Johan Dahlin) * Release the lock when potentially invoking Python code. (Sjoerd Simons) 2.21.2 - 2010-06-10 ------------------- * Drop sinkfuncs. (Tomeu Vizoso) * Clear error if we failed the import (Colin Walters) * Added missing , to keyword list of gio.GFile.set_attribute (John Ehresman) * Fix arg conversion in gio.GFile.set_attribute (John Ehresman) * Set constants under python 2.5 or before (John Ehresman) * Doc Extractor: Use replacements that make sense for &...; expressions. (José Alburquerque) * Add build docs for windows (John Stowers) * Setup.py cosmetic tidy (John Stowers) * Fix crash when importing gio (John Stowers) * Bug 589671 - Dont use generate-constants (John Stowers) * Bug 589671 - Fix setup.py for windows build (John Stowers) * Include pygsource.h (John Stowers) * codegen/docextract_to_xml.py: One more &...; replacement ( ). (José Alburquerque) * codegen/docextract_to_xml.py: Replace some &..; that cause errors. (José Alburquerque) * codegen/docextract_to_xml.py: Handle C++ multi-line comments. (José Alburquerque) * codegen/docextract.py: Stop final section processing on first match. (José Alburquerque) * Update doc extraction tool to handle GObjectIntrospection annotations. (José Alburquerque) * Docs: replace gio.IO_ERROR_* with gio.ERROR_* (Paul Bolle) * Bug 613341 - pygobject tests seem to require pygtk causing a circular (Gian Mario) * Don't raise an error in _pygi_import if pygi support is disabled (Simon van der Linden) * Initialize PyGPollFD_Type.fd_obj to NULL (Tomeu Vizoso) * Bug 605937 - pygobject: Makefile.am sets $TMPDIR, disrupting distcc (Gian Mario) * Wrap gio.Cancellable.make_pollfd() and add a test (Gian Mario) * Make cancellable an optional parameter in many methods (Gian Mario) 2.21.1 - 2010-01-02 ------------------- * Wrap gio.Volume.eject_with_operation (Gian Mario) * Wrap gio.Mount.eject_with_operation (Gian Mario) * Wrap gio.Mount.unmount_mountable_with_operation (Gian Mario) * Wrap File.unmount_mountable_with_operation (Gian Mario) * Wrap gio.File.stop_mountable (Gian Mario) * Wrap gio.File.start_mountable (Gian Mario) * Wrap gio.File.replace_readwrite_async (Gian Mario) * Wrap gio.File.poll_mountable (Gian Mario) * Wrap gio.File.open_readwrite_async (Gian Mario) * Wrap gio.File.eject_mountable_with_operation (Gian Mario) * Wrap gio.File.create_readwrite_async (Gian Mario) * Wrap gio.Drive.stop (Gian Mario) * Wrap gio.Drive.start (Gian Mario) * Wrap gio.SocketListener.accept_socket_async|finish (Gian Mario) * Wrap gio.SocketListener.accept_finish (Gian Mario) * Wrap gio.SocketListener.accept_async (Gian Mario) * Wrap gio.SocketListener.accept_socket (Gian Mario) * Wrap gio.SocketListener.accept (Gian Mario) * Make cancellable optional in gio.SocketClient.connect_to_host (Gian Mario) * Wrap gio.SocketListener.add_address (Gian Mario) * Wrap gio.SocketClient.connect_to_service_async (Gian Mario) * Wrap gio.SocketClient.connect_to_host_async (Gian Mario) * Wrap gio.SocketClient.connect_async (Gian Mario) * Wrap gio.SocketAddressEnumerator.next_async (Gian Mario) * Add a missing object gio.InetSocketAddress new in GIO 2.22 (Gian Mario) * Make cancellable optional for gio.SocketAddressEnumerator.next (Gian Mario) * Wrap gio.Socket.condition_wait (Gian Mario) * Wrap gio.Socket.condition_check (Gian Mario) * Wrap gio.Resolver.lookup_service_finish (Gian Mario) * Wrap gio.Resolver.lookup_service_async (Gian Mario) * Wrap gio.Resolver.lookup_service (Gian Mario) * Wrap gio.Resolver.lookup_by_address_async (Gian Mario) * Wrap gio.Resolver.lookup_by_name_finish (Gian Mario) * Wrap gio.Drive.eject_with_data (Gian Mario) * Deprecate old gio.Drive methods (Gian Mario) * Wrap gio.Resolver.lookup_by_name (Gian Mario) * Make cancellable optional in gio.Resolver.lookup_by_address (Gian Mario) * Strip ``g_`` prefix for many other functions (Gian Mario) * Strip ``g_`` prefix from InetAddress functions (Gian Mario) * Fix function name gio.resolver_get_default (Gian Mario) * Wrap gio.FileIOStream.query_info_async (Gian Mario) * Register enums and flags in PyGI if needed (Tomeu Vizoso, :bzbug:`603534`) * Wrap gio.IOStream.close_async (Gian Mario) * Make cancellable optional in GFile.create_readwrite (Gian Mario) * Remove a duplicate entry in gio.defs (Gian Mario) * Wrap gio.FileInfo.set_modification_time (Gian Mario) * Wrap gio.EmblemedIcon.get_emblems (Gian Mario) * Update Enums and Flags with new API (Gian Mario) * Fix handling of uchar in pyg_value_from_pyobject (Bastian Winkler) 2.21.0 - 2009-12-18 ------------------- * pygmainloop: fix use of PySignal_WakeUpFD API for nested loops (Philippe Normad, :bzbug:`481569`) * Add capabilities to import wrappers from pygi (Simon van der Linden) * Move threads_init() function from 'gobject' to 'glib' (Paul) * Fix wrong minimum checking in float properties (Paul, :bzbug:`587637`) * Wrap new API added in GIO 2.22 (Gian Mario) * Fix bad name when rebuilding the unix source module (Gian Mario) * Add the missing limit constants from glibconfig.h (Tomeu Vizoso, :bzbug:`603244`) * Suppress warnings about format conversion (Simon van der Linden, :bzbug:`603355`) * Properly define Connectable as interface type and not object type (Gian Mario) * Wrap new API added in GIO-UNIX 2.22 (Gian Mario) * Wrap g_find_program_in_path (Gian Mario, :bzbug:`598435`) * Add pygi-external.h into Makefile SOURCES (Gian Mario) 2.20.0 - 2009-09-23 ------------------- * Allow to use automake 1.11 (Paolo Borelli) * Specify programming language in .devhelp file (Frédéric Péters) * Plug reference leak of GSource in pyg_main_loop_init (Paul) * Updated uninstalled.pc file (Brian Cameron) 2.19.0 - 2009-08-10 ------------------- * Add macros to help with Python list to/from GList/GSList conversions. (John Finlay) * GIO docs practically completed (Gian) * GFileInfo.list_attributes should accept None/NULL (Gian) * Strip out Windows DLL API macros (John Finlay) * Document that many functions got moved gobject -> glib (Paul) * Allow h2def.py to work when there are tabs or multiple spaces after the struct keyword. (Murray Cumming) * Fix build when builddir is not the same as srcdir (Theppitak Karoonboonyanan) * Make gio.Emblem constructor new-style (Paul) * Cleanup GIO overrides to use Python function/method names (Paul) * Make codegen report errors using Python function/method names (Paul) * Fix object type in gio.BufferedInputStream_fill_async (Gian) * Wrap gio.BufferedInputStream.fill_async (Gian) * Add gio.BufferedOutputStream which was forgotten in the types (Gian) * Split overrides for gio.MemoryOutputStream (Gian) * Wrap gio.memory_input_stream_new_from_data (Gian) * Introduces the girepository module from the former PyBank (Simon van der Linden) * Add API appeared in 2.20 but not marked as such in gio docs (Gian) * Wrap gio.FileOutputStream.query_info_async (Gian) * Wrap gio.FileInputStream.query_async (Gian) * Install executable codegen parts with executing permissions (Paul) * Wrap gio.DataInputStream.read_line_async and read_until_async (Paul) * Fix gio.OutputStream.splice_async (Paul) * Add GIO 2.20 API and update docs (Gian) 2.18.0 - 2009-05-24 ------------------- * Improve gio docs with some more classes (Gian) * Wrap gio.OutputStream.splice_async() (Gian) * Add Python ver into installed libpyglib name (Emilio Pozuelo Monfort) * Wrap gio.OutputStream.flush_async() (Gian) * Use 'Requires.private' for libffi in '.pc' files (Josselin Mouette) * Add wrapper for gio.FileAttributeMatcher (Gian) * Mark relevant glib.IOChannel methods as METH_NOARGS (Paul) * Retire hand-written ChangeLog; autocreate from Git history (Paul) * Wrap gio.InputStream.skip_async() (Gian) * Add in codegen -n --namespace option and the code to remove dll API in headers, added documentation (Siavash Safi) * Properly mark glib.get_user_special_dir() as a keywords method (Paul) 2.17.0 - 2009-04-30 ------------------- * Write a good part of the docs for gio (Gian) * Wrap g_mount_guess_content_type g_mount_guess_content_type_finish g_mount_guess_content_type_sync (Gian, :bzbug:`580802`) * Swap first two arguments of gio.File.query_info_async (Paul, :bzbug:`580490`) * Fix a crash in pyg_type_add_interfaces (Paul, :bzbug:`566571`) * Remove an empty structure, use sizeof(PyObject) instead (Paul, :bzbug:`560591`) * Wrap four g_get_user_*_dir() functions (Paul, :bzbug:`575999`) * Remove 'ltihooks.py' as using deprecated Python module (Paul) * Code maintenance: add .gitignore files (Paul) * CellRendererPixbuf stock-size property has wrong type (Paul, :bzbug:`568499`) * Add a doap file after git migration (Johan Dahlin) * missing dep on libffi in pygobject-2.0.pc (Götz Waschk, :bzbug:`550231`) * g_volume_monitor_tp_new new function, return the singleton object. (Paul, :bzbug:`555613`) * Remove a DeprecationWarning under python 2.6 (James Westby, :bzbug:`573753`) * several scripts from codegen directory are not distributed (Krzesimir Nowak) * g_file_copy_async change argument order to keep it consistent with the other methods (Gian) * memory leak in gio.File.copy_async (Paul Pogonyshev, :bzbug:`578870`) * g_file_monitor should accept None for cancellable and set the default flag to G_FILE_MONITOR_NONE (Gian) * pyg_notify_free needs to ensure it has GIL before calling Py_XDECREF (Jonathan Matthew) * Wrap g_file_set_display_name_async (Gian) * Add a semi-private method to return the option context C object from an option context wrapper (Tristan Hill) * Converting a negative long Python value to a GUINT64 GValue doesn't error out as it should (Gustavo J. A. M. Carneiro, :bzbug:`577999`) * Wrap g_file_set_attributes_async and g_file_set_attributes_finish (Gian) * g_file_query_filesystem_info_async fix a typo (Gian) * Wrap g_file_query_filesystem_info_async (Gian) * Add missing g_file_query_filesystem_info_async and g_file_query_filesystem_info_finish (Gian) * Wrap g_file_eject_mountable (Gian) * g_file_copy callback cannot be optional (Gian) * Swap various kwargs names to reflect the code (Gian) * Update the address of the FSF (Tobias Mueller, :bzbug:`577134`) * Add g_volume_should_automount (Gian) * Wrap g_drive_enumerate_identifiers and g_volume_enumerate_identifiers (Gian) * Add a couple of convinence functions to convert from/to a python list and an array of strings (Gian) * Allow setting pytype wrapper class (Mark Lee, John Ehresman, :bzbug:`559001`) * Wrap g_file_enumerator_close_async (Gian Mario Tagliaretti) 2.16.1 - 2009-02-22 ------------------- * Apply the patch provided by Cygwin Ports maintainer (Paul Pogonyshev, :bzbug:`564018`) * Bad -I ordering can break build, patch from [dmacks netspace org] (Gian Mario Tagliaretti, :bzbug:`566737`) * Fix keyword list to be in sync with positional arguments (Paul, :bzbug:`566744`) * Add a comment explaining why the two for loops for registering interfaces (Gustavo Carneiro) * Huge cleanup of GIO overrides (Paul, :bzbug:`566706`) * gtk.Buildable interface method override is not recognized (Paul, :bzbug:`566571`) * Do not escape the ampersand "&" in entity references. Replace some unusual entity references in the output with their literal values. (Daniel Elstner, :bzbug:`568485`) * gio.InputStream.read_async can cause memory corruption. (Paul, :bzbug:`567792`) * Inconsistent use of tabs and spaces in pygtk.py (Paul, :bzbug:`569350`) * Huge fix of memory leaks in GIO (Paul, Paolo Borelli, Gian, :bzbug:`568427`) * non-async functions don't release python locks before calling blocking C functions (Gian, Gustavo, :bzbug:`556250`) * Change comment to avoid false positives when grep'ing for deprecated gtk functions (Andre Klapper) * ltihooks.py updating license header from GPL to LGPL (James Henstridge) 2.16.0 - 2009-01-04 ------------------- * gobject.timeout_add_seconds() not found in docs (Paul Pogonyshev, :bzbug:`547119`) * _wrap_g_output_stream_write_async not adding a reference to the buffer passed (Paul, :bzbug:`564102`) * gio.VolumeMonitor segfaults (Gian Mario Tagliaretti, :bzbug:`555613`) * Test if `domain` is not-null before using it to avoids segfaults (Paul, :bzbug:`561826`) * g_output_stream_write_all use gsize instead of gssize (Gian) * add __repr__ to gio.Drive, gio.Mount and gio.Volume (Paul, :bzbug:`530935`) * Missing AC_CONFIG_MACRO_DIR([m4]) (Loïc Minier, :bzbug:`551227`) * Make codegen not import when corresponding argument types are not registered (Paul, :bzbug:`551056`) * Fix typos breaking compilation (Frederic Peters :bzbug:`551212`) * GFile load_contents methods chop data at first \0 (Jonathan Matthew, :bzbug:`551059`) 2.15.4 - 2008-09-03 ------------------- * Fix typo in GPointer type registration (Loïc Minier,:bzbug:`550463`) * support G_TYPE_CLOSURE in codegen (Gian) 2.15.3 - 2008-08-31 ------------------- * Beginning of porting to 3.0. glib & gobject module ported. * Wrap g_app_info_* functions (Gian) * Wrap gio.FileAttributeInfo (Gian) * Wrap g_vfs_get_supported_uri_schemes (Johan, :bzbug:`545846`) * Wrap g_file_info_get_modification_time (Johan, :bzbug:`545861`) * Wrap gio.Volume.mount/eject (Johan) * Wrap gio.File.move (Johan) * Wrap gio.query_writable_namespaces (Gian, :bzbug:`545920`) * Separate glib & gobject documentation * Wrap GFile.append_to_async (Gian, :bzbug:`545959`) * Wrap GFile.create_async (Gian, :bzbug:`546020`) * Change return value from 'gboolean' to 'int' and changed semantics to Pythonic (Paul, :bzbug:`544946`) * Wrap GFile.replace_async and query_info_async (Gian, :bzbug:`546046`) * GIcon and implementations improvements (Paul, :bzbug:`546135`) * Improve __repr__ and richcompare for gio classes (Paul) * Missing Py_INCREFs for some file async methods (Jonathan Matthew, :bzbug:`546734`) * File.copy progress_callback does not work (Paul, :bzbug:`546591`) * add File.replace_contents, replace_contents_async, replace_contents_finish. (Jonathan Matthew, :bzbug:`547067`) * Add GFile.query_default_handler (Gian) * fix docstring line length (Jonathan Matthew, :bzbug:`547134`) * improve runtime type wrapper creation (Paul, :bzbug:`547104`) * make gio.File more Pythonic (Paul, :bzbug:`546120`) * No TypeError raised when type is None (Paul, :bzbug:`540376`) * wrap a few memory stream methods (Paul, :bzbug:`547354`) * wrap gio.DataInputStream.read_line and ...read_until (Paul, :bzbug:`547484`) * wrap four important asynchronous methods in gio.Drive and gio.Mount (Paul, :bzbug:`547495`) * gio.InputStream.read() looks broken (Paul, :bzbug:`547494`) * wrap g_content_types_get_registered() (Paul, :bzbug:`547088`) * cannot create new threads when pygtk is used (Paul, :bzbug:`547633`) * an unitialized variable in PyGLib (Paul, :bzbug:`549351`) * Constructor of gtk.TreeView raises TypeError when model is None (Paul, :bzbug:`549191`) * Fix memory problems reported by valgrind due to invalid tp_basicsize in PyGPropsDescr_Type. (Gustavo, :bzbug:`549945`) 2.15.2 - 2008-07-26 ------------------- * New module: glib, which contains the parts of the old gobject bindings which are in the glib library. MainLoop/MainContext/Sources/GOption and a few others has now moved. * Add a new installed library libpyglib-2.0, which contains the extension API for third-part modules instead of relying on macros which accesses struct fields. * Add bindings for gio.File.enumerate_children_async, gio.FileEnumerator.next_files_async, gio.Mount.mount, gio.File.mount_mountable, gio.File.mount_enclosing_volume, gio.File.unmount_mountable, gio.File.copy. * Add a new api for mapping a GError domain to an exception and register an exception for GIOError. * Remove leading IO_* prefix for the gio flags and register a quark for the domain. * Use GSlice in the glib module and bump required version to 2.14. 2.15.1 - 2008-07-15 ------------------- * Rename pygtk-codegen-2.0 to pygobject-codegen-2.0 to avoid conflicting with PyGTK (Paul Pogonyshev) 2.15.0 - 2008-07-15 ------------------- * Add GIO bindings (Johan, Mario Tagliaretti, Thomas Leonard) * Move codegen from PyGTK (Johan, Paul Pogonyshev, :bzbug:`542821`) * Add more variables to the .pc files (Damien Carbery, Paul, Dan Winship, :bzbug:`486876`) * Add pyg_option_group_new to the public API (Johan) * Add g_get_application_anme and g_get_progname (Sebastian Rittau) * Avoid making wakeups when using Python 2.6 (Johan, Gustavo, Adam Olsen, Josselin Mouette, Philippe Normand, Guido Van Rossum) * Only link against libffi when found (Ed Catmur, :bzbug:`496006`) * Improve gobject.property (Tomeu Vizoso, :bzbug:`523352`) * Improve enum comparision and warnings (Paul, Phil Dumont, :bzbug:`428732`) * Many gobject.Source improvements (Bryan Silverthorn) * Apply some fixes to make pylint happier (Johan, Simon Schampijer, :bzbug:`523821`) * Fix error message in pyg_io_add_watch (Juha Sahkangas) * Improve h2def.py (Oliver Crete, Murray Cumming, Lauro Moura) 2.14.2 - 2008-05-23 ------------------- * Allow gobject.property work with subclasses. (:bzbug:`523352`, Tomeu Vizoso) * Unbreak Source.prepare (:bzbug:`523075`, Bryan Silverthorn) * Never override customly set 'tp_new' and 'tp_alloc' (Paul Pogonyshev) * Don't link against libffi if we cannot find libffi on the system. (:bzbug:`496006`, Ed Catmur) * Dist .m4 files. (:bzbug:`496011`, Ed Catmur) * Don't return NULL after warning of enum comparsion (:bzbug:`519631`, Paul Pogonyshev) 2.14.1 - 2008-01-03 ------------------- * Avoid wakeups when using Python trunk (Johan Dahlin, :bzbug:`481569`) * Add an uninstalled.pc (Damien Carbery, :bzbug:`486876`) 2.14.0 - 2007-09-16 ------------------- * Fix a Python 2.6 deprecation warning (Johannes Hölzl, :bzbug:`342948`) * Wrap g_timeout_add_seconds, when compiling with glib 2.14 (Gustavo) * Always fully initialize the PyGObject (Ed Catmur, :bzbug:`466082`) * Fix compilation in Solaris, again (:bzbug:`339924`, Gustavo) * Fix check for default value in boolean type (Marco Giusti, :bzbug:`470230`) * Fix new style properties with subclasses (Johan Dahlin, :bzbug:`470718`) * Docs generation fixes (John Finlay) 2.13.2 - 2007-07-07 ------------------- * Fix build on opensolaris (Damien Carbery, :bzbug:`339924`) * Proxy GOption exceptions from Python to C (Johannes Hölzl, :bzbug:`342948`) * Support G_TYPE_VALUE boxed args/signals (Ed Catmur, Carlos Martin, :bzbug:`351072`) * pyg_error_exception_check bug fix (Sebastian Granjoux, :bzbug:`449879`) * Toggle references bug fix (:bzbug:`447271`, Gustavo Carneiro) * use python-config to get python includes (:bzbug:`448173`, Sebastien Bacher) * Support GObject properties in new properties API (Gustavo) * generate-constants fixes (Muntyan) * Allow running autogen.sh from outside $srcdir (Muntyan) 2.13.1 - 2007-05-02 ------------------- * Generic CClosure marshaller using libffi (Johan, :bzbug:`353816`) * Uninstalled .pc file (Damien Carbery, :bzbug:`385129`) * Fix leak in GFlags handling (Daniel Berrange, :bzbug:`428726`) * Use dirname in autogen (Loïc Minier, :bzbug:`409234`) * Treat None in a GValueArray as pointer/NULL (Ed Catmur, :bzbug:`352209`) * Toggle reference bug fix in tp_setattro (Gustavo, :bzbug:`434659`) * Add a simplified helper for creating properties (Johan, Gustavo, :bzbug:`338089`) * Avoid throwing an exception in GValue converter (James Livingstone, Ed Catmur, :bzbug:`374653`) * Build fix in .pc file (Luca Ferretti, :bzbug:`435132`) 2.13.0 - 2007-04-23 ------------------- * Release the GIL in g_object_set_property (Edward Hervey, :bzbug:`395048`) * Break PyGObject<->GObject reference cycle (Gustavo Carneiro, :bzbug:`320428`) * use static inline functions for init_pygobject (Gustavo, :bzbug:`419379`) * Wrap g_set_application_name, g_set_prgname (Havoc Pennington, :bzbug:`415853`) * New pyg_gerror_exception_check API (Gustavo, :bzbug:`425242`) * New API to get/set multiple properties (Gian Mario Tagliaretti, :bzbug:`403212`) * Misc. bug fixes. 2.12.3 - 2006-11-18 ------------------- * distutils build fixes (Cedric) * documentation updates (John) * gobject.handler_block_by_func and friends now accept methods (Johan, Dima, :bzbug:`375589`) * avoid truncating of gparamspec (Yevgen Muntyan, :bzbug:`353943`) * set __module__ on gobject derived types (Johan, Osmo Salomaa, :bzbug:`376099`) * Ensure exceptions are raised on errors in gobject.OptionGroup (Johan, Laszlo Pandy, :bzbug:`364576` 2.12.2 - 2006-10-03 ------------------- * Make PyGObject 64-bit safe for Python 2.5 (Gustavo) * All headers are now LGPL and not GPL (Johan) * Remove a couple of GCC warnings (Gustavo) * Revive distutils support (Cedric Gustin) * Emission hook reference count bugfix (Gustavo) * MSVC/ANSI C compilation fix (John Ehresman) * Bump Ctrl-C timeout handler from 100ms to 1000 (Johan) 2.12.1 - 2006-09-04 ------------------- * Corrected version check (Sebastian Dröge, :bzbug:`354364`) 2.12.0 - 2006-09-04 ------------------- * Install the html files even when using --disable-docs (:bzbug:`353159`, Johan, Matthias Clasen) 2.11.4 - 2006-08-27 ------------------- * Include pre-generated html docs in the tarball (Johan) * Fix bug in do_set_property called from constructor (Gustavo, :bzbug:`353039`) * Fix type registration involving interfaces with signals and/or properties (Gustavo) 2.11.3 - 2006-08-21 ------------------- * Documentation updates (John) * Documentation build fixes (Johan, John, Gian Mario Tagliaretti) * PyGObject can now be compiled using a C++ compiler (Murray Cumming) * Type registration bug fix (Gustavo) 2.11.2 - 2006-08-08 ------------------- * Add fixxref.py from PyGTK (Johan) * Fix parallel build (:bzbug:`350225`, Ed Catmur) 2.11.1 - 2006-08-04 ------------------- * Add John Finlay's reference manual (Johan, John) * Fix GOption mem leak (Gustavo) * Infrastructure for lazy type registration (Johan) * Enum/Flags fixes (Gustavo, John) * Eliminate some GCC warnings (Johan) 2.11.0 - 2006-07-12 ------------------- * Add GOption support (:bzbug:`163645`, Johannes Hölzl) * GObject metaclass converted to Python code (Gustavo) * Register GType constants from Python-land (Johan) * Distutils updates (John Ehresman, Cedric Gustin) * Add support for signal emission hooks (:bzbug:`154845`, Johan) * g_spawn_close_pid support (Gustavo) * Add new APIs do add or disable log redirections (Muntyan, :bzbug:`323786`) * "sub-sub-type" bug fixed (Gustavo) * Coverity report code fixes (Johan) * Support retrieving signal and property info from interfaces (Finlay) * Support parameters of type G_TYPE_GSTRING in signals (Gustavo) * Wrap a few g_filename_* APIs (Gustavo) 2.10.1 - 2006-04-11 ------------------- * uint64 property bug fix (Andy Wingo) * Hard code path to 2.0 (Gustavo) * Allow only tuples and lists in strv to value (Gustavo) * Include dsextras.py in the dist (Johan) 2.10.0 - 2006-03-13 ------------------- * enum/leak fix (Michael Smith) 2.9.1 - 2006-01-16 ------------------ 2.9.0 - 2006-01-16 ------------------ * Signal accumulator support (Gustavo) * GObject doc string generation improvements (Gustavo) * Discover GInterfaces in runtime (Gustavo) * Warn if return value in iowatch callback is not bool (Gustavo) * Convert string arrays properly (Christopher Aillon) 2.8.0 - 2006-01-09 ------------------ * Initial release, split of from PyGTK. * Updates for Python 2.5's richcompare (Manish Yosh) * PyFlags bug fixes (Gustavo) * Fix leak in pygobject_new_with_interfaces (Johan) * Undeprecate gobject.type_register (Johan) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/README.rst0000664000000000000000000000322415074674453014036 0ustar00rootroot.. image:: https://gitlab.gnome.org/GNOME/pygobject/-/raw/master/docs/images/pygobject.svg?ref_type=heads :align: center :width: 400px :height: 98px | **PyGObject** is a Python package which provides bindings for `GObject `__ based libraries such as `GTK `__, `GStreamer `__, `WebKitGTK `__, `GLib `__, `GIO `__ and many more. It supports Linux, Windows, and macOS and works with **Python 3.9+** and **PyPy3**. PyGObject, including this documentation, is licensed under the **LGPLv2.1+**. Homepage -------- https://pygobject.gnome.org Installation ------------ The latest version from PyGObject can be installed from `PyPI `__: pip install PyGObject PyGObject is only distributed as source distribution, so you need a C compiler installed on your host. Please have a look at our `Getting Started `__ documentation for OS specific installation instructions. Development ~~~~~~~~~~~ Our website contains instructions on how to `set up a development environment `__. Default branch renamed to ``main`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The default development branch of PyGObject has been renamed to ``main``. To update your local checkout, use:: git checkout master git branch -m master main git fetch git branch --unset-upstream git branch -u origin/main git symbolic-ref refs/remotes/origin/HEAD refs/remotes/origin/main ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/Makefile0000664000000000000000000000060315074674453014735 0ustar00rootrootDIAS = $(wildcard images/*.dia) DIA_SVGS = $(patsubst %.dia,%.svg,$(DIAS)) all: _build images/%.svg: images/%.dia dia $< --export=$@ --filter=dia-svg _build: Makefile *.rst devguide/*.rst guide/*/*.rst guide/*.rst conf.py images/*.png $(DIA_SVGS) ../README.rst ../NEWS python3 -m sphinx -b html . _build linkcheck: python3 -m sphinx -b linkcheck -n . _build clean: rm -R _build ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/bugs_repo.rst0000664000000000000000000000147415074674453016023 0ustar00rootroot========================== Bug Tracker / Git / Source ========================== .. include:: icons.rst |bug-logo| Bug Tracker ---------------------- We use the GNOME GitLab issue tracker: * List of existing issues: https://gitlab.gnome.org/GNOME/pygobject/-/issues * Create a new issue: https://gitlab.gnome.org/GNOME/pygobject/-/issues/new |git-logo| Git Repo ------------------- PyGObject uses `Git `_ for source control and the git repo is hosted on the `GNOME Gitlab instance `__: * https://gitlab.gnome.org/GNOME/pygobject * ``git clone https://gitlab.gnome.org/GNOME/pygobject.git`` |source-logo| Source Tarballs ----------------------------- Release tarballs of all releases can be found on the GNOME server: https://ftp.gnome.org/pub/GNOME/sources/pygobject ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/changelog.rst0000664000000000000000000000047415074674453015764 0ustar00rootrootChangelog ========= Versions with an odd minor version are unstable releases (e.g. 3.27.x) while versions with even minor version are stable releases (e.g. 3.28.x). This list is sorted by release date. For more details see the Git log: https://gitlab.gnome.org/GNOME/pygobject/-/commits/main .. include:: ../NEWS ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/conf.py0000664000000000000000000000315115074674453014575 0ustar00rootrootextensions = [ 'sphinx.ext.todo', 'sphinx.ext.intersphinx', 'sphinx.ext.extlinks', 'sphinx_copybutton', ] intersphinx_mapping = { 'python': ('https://docs.python.org/3', None), 'cairo': ('https://pycairo.readthedocs.io/en/latest', None), 'apidocs': ( 'https://amolenaar.pages.gitlab.gnome.org/pygobject-docs', None, ), } source_suffix = '.rst' master_doc = 'index' exclude_patterns = ['_build', 'README.rst'] pygments_style = 'tango' html_theme = 'furo' html_show_copyright = False html_favicon = "images/favicon.ico" project = "PyGObject" html_title = project html_theme_options = { 'source_edit_link': 'https://gitlab.gnome.org/GNOME/pygobject/-/blob/main/docs/{filename}', } html_context = { 'extra_css_files': [ 'https://quodlibet.github.io/fonts/font-mfizz.css', '_static/extra.css', ], "display_gitlab": True, "gitlab_user": "GNOME", "gitlab_repo": "pygobject", "gitlab_version": "main", "conf_py_path": "/docs/", "gitlab_host": "gitlab.gnome.org", } html_static_path = [ "extra.css", "images/pygobject-small.svg", ] extlinks = { 'bzbug': ('https://bugzilla.gnome.org/show_bug.cgi?id=%s', 'bz#%s'), 'issue': ('https://gitlab.gnome.org/GNOME/pygobject/-/issues/%s', '#%s'), 'commit': ('https://gitlab.gnome.org/GNOME/pygobject/commit/%s', '%s'), 'mr': ( 'https://gitlab.gnome.org/GNOME/pygobject/-/merge_requests/%s', '!%s'), 'user': ('https://gitlab.gnome.org/%s', '%s'), 'devdocs': ('https://developer.gnome.org/documentation/%s.html', None) } suppress_warnings = ["image.nonlocal_uri"] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/contact.rst0000664000000000000000000000176115074674453015470 0ustar00rootroot======= Contact ======= Issue Tracker If you want to file a bug report please file an issue on `GitLab `__. Chat For chatting with the community we are on the GNOME [matrix] instance in the `GNOME Python channel `__. Historical logs for this channel and for the legacy IRC channel are available at https://quodlibet.duckdns.org/irc/pygobject. Forum If you are running in to an issue or want to give feedback, start a discussion with the Python GNOME community by using the `Python` tag at the GNOME Discourse at https://discourse.gnome.org/tag/python. StackOverflow / StackExchange If you have technical questions about PyGObject you can find answers on `Stack Overflow `__. When asking there please use the tag `PyGObject`. If you are unsure which communication channel to use, **please start with discourse**. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/devguide/dev_environ.rst0000664000000000000000000001364215074674453020150 0ustar00rootroot.. include:: ../icons.rst .. _devenv: ################################## Creating a Development Environment ################################## This describes how to setup a development environment for working on a project that uses PyGObject, or for working on PyGObject itself. Please follow the instructions on ":ref:`gettingstarted`" first, as they are a pre-requirement. .. _pipenv-setup: ***************** Environment Setup ***************** .. _install-dependencies: Install Dependencies ==================== In order to compile Python and pip install pygobject, dependencies are need for your operating system. =========================================== ======================================== ============================================== |ubuntu-logo| :ref:`Ubuntu ` |fedora-logo| :ref:`Fedora ` |arch-logo| :ref:`Arch Linux ` |windows-logo| :ref:`Windows ` |macosx-logo| :ref:`macOS ` |opensuse-logo| :ref:`openSUSE ` =========================================== ======================================== ============================================== .. _ubuntu-dep: |ubuntu-logo| Ubuntu / |debian-logo| Debian ------------------------------------------- .. code:: console sudo apt-get install -y python3-venv python3-wheel python3-dev sudo apt-get install -y libgirepository1.0-dev build-essential \ libbz2-dev libreadline-dev libssl-dev zlib1g-dev libsqlite3-dev wget \ curl llvm libncurses5-dev libncursesw5-dev xz-utils tk-dev libcairo2-dev .. _fedora-dep: |fedora-logo| Fedora -------------------- .. code:: console sudo dnf install -y python3-wheel sudo dnf install -y gcc zlib-devel bzip2 bzip2-devel readline-devel \ sqlite sqlite-devel openssl-devel tk-devel git python3-cairo-devel \ cairo-gobject-devel gobject-introspection-devel .. _arch-dep: |arch-logo| Arch Linux ---------------------- .. code:: console sudo pacman -S --noconfirm python-wheel sudo pacman -S --noconfirm base-devel openssl zlib git gobject-introspection .. _opensuse-dep: |opensuse-logo| openSUSE ------------------------ .. code:: console sudo zypper install -y python3-wheel gobject-introspection-devel \ python3-cairo-devel openssl zlib git sudo zypper install --type pattern devel_basis .. _windows-dep: |windows-logo| Windows ---------------------- To develop on Windows you need to have `MSYS2 `_ installed. .. code:: console pacman -S --needed --noconfirm base-devel mingw-w64-ucrt-x86_64-toolchain git \ mingw-w64-ucrt-x86_64-python mingw-w64-ucrt-x86_64-pycairo \ mingw-w64-ucrt-x86_64-gobject-introspection mingw-w64-ucrt-x86_64-libffi .. _macosx-dep: |macosx-logo| macOS ------------------- With homebrew: .. code:: console brew update brew install python3 gobject-introspection libffi export PKG_CONFIG_PATH=/opt/homebrew/opt/libffi/lib/pkgconfig # use /usr/local/ for older Homebrew installs .. _install-pyenv: Install `pyenv`_ (Optional) =========================== `pyenv`_ lets you easily switch between multiple versions of Python. ============================================= ========================================= |linux-logo| :ref:`Linux ` |macosx-logo| :ref:`macOS ` ============================================= ========================================= .. _linux-pyenv: |linux-logo| Linux ------------------ .. code:: console curl https://pyenv.run | bash exec $SHELL pyenv install 3.11 pyenv global 3.11 .. _macosx-pyenv: |macosx-logo| macOS ------------------- .. code:: console brew install pyenv pyenv install 3.11 pyenv global 3.11 .. _projects-pygobject-dependencies: ***************** Work on PyGObject ***************** .. _platform-ind-steps: Platform Independent Steps ========================== First, check out the source code: .. code:: console git clone https://gitlab.gnome.org/GNOME/pygobject.git cd pygobject With a local copy of PyGObject, there's three ways to start developing: 1. PDM, a modern Python package and dependency manager 2. Pip, the default Python package installer 3. Meson, use the Meson build system directly PDM --- Make sure you have `PDM `_ 2.13 or newer installed. Then set up the project by running: .. code:: console pdm install You can run teh unit tests with: .. code:: console pdm run pytest Pip --- It's always a good idea to work from within a Python virtual environment. PyGObject is built with `Meson `_. In order to support `editable installs `_, Meson-python, Meson, and Ninja should be installed in the virtual environment. .. code:: console python3 -m venv .venv source .venv/bin/activate pip install meson-python meson ninja pycairo pytest .. note:: For Python 3.12 and newer, also install ``setuptools``, since distutils is no longer provided in the standard library. Install PyGObject in your local environment with the ``--no-build-isolation`` to allow for dynamic rebuilds .. code:: console pip install --no-build-isolation --config-settings=setup-args="-Dtests=true" -e '.[dev]' By default the C libraries are built in "release" mode (no debug symbols). To compile the C libraries with debug symbols, run .. code:: console pip install --no-build-isolation --config-settings=setup-args="-Dbuildtype=debug" --config-settings=setup-args="-Dtests=true" -e '.[dev]' Open a Python console: .. code:: python from gi.repository import GObject Run the unittests: .. code:: console pytest Meson ----- It's also possible to run the tests from Meson. Tests are still run with Pytest, so it's important that Pytest is installed. .. code:: console meson setup _build # Needed only once meson test -C _build .. _pyenv: https://github.com/pyenv/pyenv././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/devguide/index.rst0000664000000000000000000000025415074674453016734 0ustar00rootroot================= Development Guide ================= .. toctree:: :titlesonly: :maxdepth: 1 overview dev_environ style_guide override_guidelines ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/devguide/override_guidelines.rst0000664000000000000000000000762615074674453021666 0ustar00rootroot========================== Python Override Guidelines ========================== This document serves as a guide for developers creating new PyGObject overrides or modifying existing ones. This document is not intended as hard rules as there may always be pragmatic exceptions to what is listed here. It is also a good idea to study the Zen of Python by Tim Peters in :pep:`20`. In general, overrides should be minimized and preference should always be placed on updating the underlying API to be more bindable, adding features to GI to support the requirement, or adding mechanical features to PyGObject which can apply generically to all overrides (:bzbug:`721226` and :bzbug:`640812`). If a GI feature or more bindable API for a library is in the works, it is a good idea to avoid the temptation to add temporary short term workarounds in overrides. The reason is this can creaste unnecessary conflicts when the bindable API becomes a reality (:bzbug:`707280`). * Minimize class overrides when possible. *Reason*: Class overrides incur a load time performance penalty because they require the classes GType and all of the Python method bindings to be created. See :bzbug:`705810` * Prefer monkey patching methods on repository classes over inheritance. *Reason*: Class overrides add an additional level to the method resolution order (mro) which has a performance penalty. Since overrides are designed for specific repository library APIs, monkey patching is reasonable because it is utilized in a controlled manner by the API designer (as opposed to monkey patching a third-party library which is more fragile). * Avoid overriding ``__init__`` *Reason*: Sub-classing the overridden class then becomes challenging and has the potential to cause bugs (see :bzbug:`711487` and reasoning listed in https://wiki.gnome.org/Projects/PyGObject/InitializerDeprecations). * Unbindable functions which take variadic arguments are generally ok to add Python implementations, but keep in mind the prior noted guidelines. A lot of times adding bindable versions of the functions to the underlying library which take a list is acceptable. For example: :bzbug:`706119`. Another problem here is if an override is added, then later a bindable version of the API is added which takes a list, there is a good chance we have to live with the override forever which masks a working version implemented by GI. * Avoid side effects beyond the intended repositories API in function/method overrides. *Reason*: This conflates the original API and adds a documentation burden on the override maintainer. * Don't change function signatures from the original API and don't add default values. *Reason*: This turns into a documentation discrepancy between the libraries API and the Python version of the API. Default value work should focus on bug :bzbug:`558620`, not cherry-picking individual Python functions and adding defaults. * Avoid implicit side effects to the Python standard library (or anywhere). * Don't modify or use sys.argv *Reason*: sys.argv should only be explicitly controlled by application developers. Otherwise it requires hacks to work around a module modifying or using the developers command line args which they rightfully own. .. code:: python saved_argv = sys.argv.copy() sys.argv = [] from gi.repository import Gtk sys.argv = saved_argv * Never set Pythons default encoding. *Reason*: Read or watch Ned Batchelders "`Pragmatic Unicode `__" * For PyGTK compatibility APIs, add them to PyGTKCompat not overrides. * Prefer adapter patterns over of inheritance and overrides. *Reason*: An adapter allows more flexibility and less dependency on overrides. It allows application developers to use the raw GI API without having to think about if a particular typelibs overrides have been installed or not. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/devguide/overview.rst0000664000000000000000000000056715074674453017502 0ustar00rootroot======== Overview ======== See :doc:`/bugs_repo` for information on where to find the bug tracker and the source code. Continuous Testing ------------------ The test suite gets regularly run on all supported platforms using https://github.com/pygobject/pygobject-ci There is currently no integration with the git repo for this and the status has to be checked manually. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/devguide/style_guide.rst0000664000000000000000000000705215074674453020145 0ustar00rootroot================ Style Guidelines ================ Python Code ----------- * Generally follow Python's :pep:`8` style guidelines. We run the pep8 command to verify this during unittest runs. * Break up logical blocks of related code with a newline. Specifically add a blank newline after conditional or looping blocks. * Don't comment what is obvious. Instead prefer meaningful names of functions and variables: .. code:: python # Get the functions signal annotations <-- this comment is unnecessary return_type, arg_types = get_signal_annotations(func) * Use comments to explain non-obvious blocks and conditionals, magic, workarounds (with bug references), or generally complex pieces of code. Good examples: .. code:: python # If a property was defined with a decorator, it may already have # a name; if it was defined with an assignment (prop = Property(...)) # we set the property's name to the member name if not prop.name: prop.name = name .. code:: python # Python causes MRO's to be calculated starting with the lowest # base class and working towards the descendant, storing the result # 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__)] Python Doc Strings ------------------ * Doc strings should generally follow :pep:`257` unless noted here. * Use `reStructuredText (reST) `__ annotations. * Use three double quotes for doc strings (``"""``). * Use a brief description on the same line as the triple quote. * Include function parameter documentation (including types, returns, and raises) between the brief description and the full description. Use a newline with indentation for the parameters descriptions. .. code:: python def spam(amount): """Creates a Spam object with the given amount. :param int amount: The amount of spam. :returns: A new Spam instance with the given amount set. :rtype: Spam :raises ValueError: If amount is not a numeric type. More complete description. """ * For class documentation, use the classes doc string for an explanation of what the class is used for and how it works, including Python examples. Include ``__init__`` argument documentation after the brief description in the classes doc string. The class ``__init__`` should generally be the first method defined in a class putting it as close as possible (location wise) to the class documentation. .. code:: python class Bacon(CookedFood): """Bacon is a breakfast food. :param CookingType cooking_type: Enum for the type of cooking to use. :param float cooking_time: Amount of time used to cook the Bacon in minutes. Use Bacon in combination with other breakfast foods for a complete breakfast. For example, combine Bacon with other items in a list to make a breakfast: .. code-block:: python breakfast = [Bacon(), Spam(), Spam(), Eggs()] """ def __init__(self, cooking_type=CookingType.BAKE, cooking_time=15.0): super(Bacon, self).__init__(cooking_type, cooking_time) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/extra.css0000664000000000000000000000172115074674453015134 0ustar00rootroot.wy-side-nav-search { background-color: initial; } .wy-nav-top { background-color: #171A2F; } .wy-side-nav-search input[type="text"] { border-color: transparent; } .wy-nav-content { margin: initial; } .wy-nav-side { background-color: #171A2F; } .rst-content div[role=navigation], footer { font-size: 0.85em; color: #999; } .rst-content div[role=navigation] hr { margin-top: 6px; } footer hr { margin-bottom: 6px; } .rst-footer-buttons { display: none; } a.icon-home, a.icon-home:hover { display: inline-block; padding: 4px 4px 4px 21px; background: transparent url(pygobject-small.svg) center left no-repeat; background-size: 1.2em; margin-top: 0.2em; margin-bottom: 1em; } .fa-home::before, .icon-home::before { content: ""; } .wy-nav-top a { margin: -2em; background: transparent url(pygobject-small.svg) center left no-repeat; background-size: 1.2em; padding: 4px 4px 4px 24px; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/further.rst0000664000000000000000000000065615074674453015516 0ustar00rootroot================= Further Resources ================= `GNOME Developer Documentation `__ Tutorials for creating a GNOME application using PyGObject, GTK 4, and Libadwaita. `GNOME Python API documentation `__ Auto generated API documentation for many libraries accessible through PyGObject. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/getting_started.rst0000664000000000000000000001500715074674453017222 0ustar00rootroot.. include:: icons.rst .. _gettingstarted: =============== Getting Started =============== To get things started we will try to run a very simple `GTK `_ based GUI application using the :doc:`PyGObject ` provided Python bindings. First create a small Python script called ``hello.py`` with the following content and save it somewhere: .. code:: python import sys import gi gi.require_version("Gtk", "4.0") from gi.repository import GLib, Gtk class MyApplication(Gtk.Application): def __init__(self): super().__init__(application_id="com.example.MyGtkApplication") GLib.set_application_name('My Gtk Application') def do_activate(self): window = Gtk.ApplicationWindow(application=self, title="Hello World") window.present() app = MyApplication() exit_status = app.run(sys.argv) sys.exit(exit_status) Before we can run the example application we need to install PyGObject, GTK and their dependencies. Follow the instructions for your platform below. ======================================================= ==================================================== ========================================================== |ubuntu-logo| :ref:`Ubuntu ` |fedora-logo| :ref:`Fedora ` |arch-logo| :ref:`Arch Linux ` |windows-logo| :ref:`Windows ` |macosx-logo| :ref:`macOS ` |opensuse-logo| :ref:`openSUSE ` ======================================================= ==================================================== ========================================================== After running the example application have a look at the :doc:`/tutorials/index` for an overview of how to create GTK apps and the `GNOME Python API docs `__ for API documentation for all supported libraries. For full IDE support (incl. autocomplete) you will also need typing stubs available here `PyGObject-stubs `_. .. _windows-getting-started: |windows-logo| Windows ---------------------- #) Go to https://www.msys2.org/ and download the x86_64 installer #) Follow the instructions on the page for setting up the basic environment #) Run ``C:\msys64\ucrt64.exe`` - a terminal window should pop up #) Execute ``pacman -Suy`` #) Execute ``pacman -S mingw-w64-ucrt-x86_64-gtk4 mingw-w64-ucrt-x86_64-python3 mingw-w64-ucrt-x86_64-python3-gobject`` #) To test that GTK is working you can run ``gtk4-demo`` #) Copy the ``hello.py`` script you created to ``C:\msys64\home\`` #) In the mingw32 terminal execute ``python3 hello.py`` - a window should appear. .. figure:: images/start_windows.png :scale: 60% .. _ubuntu-getting-started: |ubuntu-logo| Ubuntu / |debian-logo| Debian ------------------------------------------- Installing the system provided PyGObject: #) Open a terminal #) Execute ``sudo apt install python3-gi python3-gi-cairo gir1.2-gtk-4.0`` #) Change the directory to where your ``hello.py`` script can be found (e.g. ``cd Desktop``) #) Run ``python3 hello.py`` Installing from PyPI with pip: #) Open a terminal and enter your virtual environment #) Execute ``sudo apt install libgirepository1.0-dev gcc libcairo2-dev pkg-config python3-dev gir1.2-gtk-4.0`` to install the build dependencies and GTK #) Execute ``pip3 install pycairo`` to build and install Pycairo #) Execute ``pip3 install PyGObject`` to build and install PyGObject #) Change the working directory to where your ``hello.py`` script can be found #) Run ``python3 hello.py`` .. figure:: images/start_linux.png :scale: 60% .. _fedora-getting-started: |fedora-logo| Fedora -------------------- Installing the system provided PyGObject: #) Open a terminal #) Execute ``sudo dnf install python3-gobject gtk4`` #) Change the working directory to where your ``hello.py`` script can be found #) Run ``python3 hello.py`` Installing from PyPI with pip: #) Open a terminal and enter your virtual environment #) Execute ``sudo dnf install gcc gobject-introspection-devel cairo-gobject-devel pkg-config python3-devel gtk4`` to install the build dependencies and GTK #) Execute ``pip3 install pycairo`` to build and install Pycairo #) Execute ``pip3 install PyGObject`` to build and install PyGObject #) Change the working directory to where your ``hello.py`` script can be found #) Run ``python3 hello.py`` .. _arch-getting-started: |arch-logo| Arch Linux ---------------------- Installing the system provided PyGObject: #) Open a terminal #) Execute ``sudo pacman -S python-gobject gtk4`` #) Change the working directory to where your ``hello.py`` script can be found #) Run ``python3 hello.py`` Installing from PyPI with pip: #) Open a terminal and enter your virtual environment #) Execute ``sudo pacman -S python cairo pkgconf gobject-introspection gtk4`` to install the build dependencies and GTK #) Execute ``pip3 install pycairo`` to build and install Pycairo #) Execute ``pip3 install PyGObject`` to build and install PyGObject #) Change the working directory to where your ``hello.py`` script can be found #) Run ``python3 hello.py`` .. _opensuse-getting-started: |opensuse-logo| openSUSE ------------------------ Installing the system provided PyGObject: #) Open a terminal #) Execute ``sudo zypper install python3-gobject python3-gobject-Gdk typelib-1_0-Gtk-4_0 libgtk-4-1`` #) Change the directory to where your ``hello.py`` script can be found #) Run ``python3 hello.py`` Installing from PyPI with pip: #) Open a terminal and enter your virtual environment #) Execute ``sudo zypper install cairo-devel pkg-config python3-devel gcc gobject-introspection-devel`` to install the build dependencies and GTK #) Execute ``pip3 install pycairo`` to build and install Pycairo #) Execute ``pip3 install PyGObject`` to build and install PyGObject #) Change the working directory to where your ``hello.py`` script can be found #) Run ``python3 hello.py`` .. _macosx-getting-started: |macosx-logo| macOS ------------------- #) Go to https://brew.sh/ and install homebrew #) Open a terminal #) Execute ``brew install pygobject3 gtk4`` #) Change the working directory to where your ``hello.py`` script can be found #) Run ``python3 hello.py`` .. figure:: images/start_macos.png :scale: 70% ---- For more details on how to use a virtualenv with PyGObject, see the ":ref:`devenv`" page. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/guide/api/api.rst0000664000000000000000000000373315074674453016455 0ustar00rootroot.. _guide-api: ================ GI Documentation ================ This is the API provided by the toplevel "gi" package. .. function:: gi.require_version(namespace, version) :param str namespace: The namespace :param str version: The version of the namespace which should be loaded :raises: ..py:exception:: ValueError Ensures the namespace gets loaded with the given version. If the namespace was already loaded with a different version or a different version was required previously raises ValueError. :: import gi gi.require_version('Gtk', '3.0') .. function:: gi.require_foreign(namespace, symbol=None) :param str namespace: Introspection namespace of the foreign module (e.g. "cairo") :param symbol: Optional symbol typename to ensure a converter exists. :type symbol: :obj:`str` or :obj:`None` :raises: ..py:exception:: ImportError Ensure the given foreign marshaling module is available and loaded. Example: .. code-block:: python import gi import cairo gi.require_foreign('cairo') gi.require_foreign('cairo', 'Surface') .. function:: gi.check_version(version) :param tuple version: A version tuple :raises: ..py:exception:: ValueError Compares the passed in version tuple with the gi version and does nothing if gi version is the same or newer. Otherwise raises ValueError. .. function:: gi.get_required_version(namespace) :returns: The version successfully required previously by :func:`gi.require_version` or :obj:`None` :rtype: str or :obj:`None` .. data:: gi.version_info :annotation: = (3, 18, 1) The version of PyGObject .. class:: gi.PyGIDeprecationWarning The warning class used for deprecations in PyGObject and the included Python overrides. It inherits from DeprecationWarning and is hidden by default. .. class:: gi.PyGIWarning Like :class:`gi.PyGIDeprecationWarning` but visible by default. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/guide/api/basic_types.rst0000664000000000000000000000161315074674453020204 0ustar00rootroot=========== Basic Types =========== PyGObject will automatically convert between C types and Python types. In cases where it's appropriate it will use default Python types like :obj:`int`, :obj:`list`, and :obj:`dict`. Number Types ------------ All glib integer types get mapped to :obj:`int` and :obj:`float`. Since the glib integer types are always range limited, conversions from Python int/long can fail with :class:`OverflowError`: .. code:: pycon >>> GLib.random_int_range(0, 2**31-1) 1684142898 >>> GLib.random_int_range(0, 2**31) Traceback (most recent call last): File "", line 1, in OverflowError: 2147483648 not in range -2147483648 to 2147483647 >>> Text Types ---------- Text types are mapped to :obj:`str`. Other Types ----------- * GList <-> :obj:`list` * GSList <-> :obj:`list` * GHashTable <-> :obj:`dict` * arrays <-> :obj:`list` ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/guide/api/error_handling.rst0000664000000000000000000000344615074674453020702 0ustar00rootroot.. currentmodule:: gi.repository ============== Error Handling ============== GLib has its own method of handling errors using :obj:`GLib.Error`. These are raised as Python exceptions, but with a few small differences. It's common in Python for exception subclasses to be used (e.g., :obj:`ValueError` versus :obj:`IOError`) to distinguish different types of errors. Libraries often define their own :obj:`Exception` subclasses, and library users will handle these cases explicitly. In GLib-using libraries, errors are all :obj:`GLib.Error` instances, with no subclassing for different error types. Instead, every :obj:`GLib.Error` instance has attributes that distinguish types of error: * :attr:`GLib.Error.domain` is the error domain, usually a string that you can convert to a ``GLib`` quark with :func:`GLib.quark_from_string` * :attr:`GLib.Error.code` identifies a specific error within the domain * :attr:`GLib.Error.message` is a human-readable description of the error Error domains are defined per-module, and you can get an error domain from ``*_error_quark`` functions on the relevant module. For example, IO errors from ``Gio`` are in the domain returned by :func:`Gio.io_error_quark`, and possible error code values are enumerated in :obj:`Gio.IOErrorEnum`. Once you've caught a :obj:`GLib.Error`, you can call :meth:`GLib.Error.matches` to see whether it matches the specific error you want to handle. Examples -------- Catching a specific error: .. code:: pycon >>> from gi.repository import GLib, Gio >>> f = Gio.File.new_for_path('missing-path') >>> try: ... f.read() ... except GLib.Error as err: ... if err.matches(Gio.io_error_quark(), Gio.IOErrorEnum.NOT_FOUND): ... print('File not found') ... else: ... raise File not found ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/guide/api/flags_enums.rst0000664000000000000000000000207615074674453020206 0ustar00rootroot.. currentmodule:: gi.repository ============= Flags & Enums ============= Flags are subclasses of :class:`GObject.GFlags` and represent bit fields where some bits also have names: .. code:: pycon >>> Gtk.DialogFlags.MODAL >>> Gtk.DialogFlags.MODAL | Gtk.DialogFlags.DESTROY_WITH_PARENT >>> int(_) 3 >>> Gtk.DialogFlags(3) >>> isinstance(Gtk.DialogFlags.MODAL, Gtk.DialogFlags) True >>> Bitwise operations on them will produce a value of the same type. Enums are subclasses of :class:`GObject.GEnum` and represent a list of named constants: .. code:: pycon >>> Gtk.Align.CENTER >>> int(Gtk.Align.CENTER) 3 >>> int(Gtk.Align.END) 2 >>> Gtk.Align(1) >>> isinstance(Gtk.Align.CENTER, Gtk.Align) True ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/guide/api/gobject.rst0000664000000000000000000000432215074674453017314 0ustar00rootroot.. currentmodule:: gi.repository ============== GObject.Object ============== Compare to other types, :obj:`GObject.Object` has the best integration between the GObject and Python type system. 1) It is possible to subclass a :obj:`GObject.Object`. Subclassing creates a new :obj:`GObject.GType` which is connected to the new Python type. This means you can use it with API which takes :obj:`GObject.GType`. 2) The Python wrapper instance for a :obj:`GObject.Object` is always the same. For the same C instance you will always get the same Python instance. In addition :obj:`GObject.Object` has support for :any:`signals ` and :any:`properties ` .. toctree:: :titlesonly: :maxdepth: 1 :hidden: signals properties weakrefs Examples -------- Subclassing: .. code:: pycon >>> from gi.repository import GObject >>> class A(GObject.Object): ... pass ... >>> A() <__main__.A object at 0x7f9113fc3280 (__main__+A at 0x559d9861acc0)> >>> A.__gtype__ >>> A.__gtype__.name '__main__+A' >>> In case you want to specify the GType name we have to provide a ``__gtype_name__``: .. code:: pycon >>> from gi.repository import GObject >>> class B(GObject.Object): ... __gtype_name__ = "MyName" ... >>> B.__gtype__ >>> :obj:`GObject.Object` only supports single inheritance, this means you can only subclass one :obj:`GObject.Object`, but multiple Python classes: .. code:: pycon >>> from gi.repository import GObject >>> class MixinA(object): ... pass ... >>> class MixinB(object): ... pass ... >>> class MyClass(GObject.Object, MixinA, MixinB): ... pass ... >>> instance = MyClass() Here we can see how we create a :obj:`Gio.ListStore` for our new subclass and that we get back the same Python instance we put into it: .. code:: pycon >>> from gi.repository import GObject, Gio >>> class A(GObject.Object): ... pass ... >>> store = Gio.ListStore.new(A) >>> instance = A() >>> store.append(instance) >>> store.get_item(0) is instance True >>> ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/guide/api/index.rst0000664000000000000000000000024215074674453017003 0ustar00rootroot============= API Reference ============= .. toctree:: :titlesonly: :maxdepth: 1 api basic_types flags_enums gobject error_handling ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/guide/api/properties.rst0000664000000000000000000000722615074674453020101 0ustar00rootroot.. currentmodule:: gi.repository ========== Properties ========== Properties are part of a class and are defined through a :obj:`GObject.ParamSpec`, which contains the type, name, value range and so on. To find all the registered properties of a class you can use the :meth:`GObject.Object.list_properties` class method. .. code:: pycon >>> Gio.Application.list_properties() [, , , , , , , ] >>> param = Gio.Application.list_properties()[0] >>> param.name 'application-id' >>> param.owner_type >>> param.value_type >>> The :obj:`GObject.Object` contructor takes multiple properties as keyword arguments. Property names usually contain "-" for seperating words. In Python you can either use "-" or "_". In this case variable names don't allow "-", so we use "_". .. code:: pycon >>> app = Gio.Application(application_id="foo.bar") To get and set the property value see :meth:`GObject.Object.get_property` and :meth:`GObject.Object.set_property`. .. code:: pycon >>> app = Gio.Application(application_id="foo.bar") >>> app >>> app.get_property("application_id") 'foo.bar' >>> app.set_property("application_id", "a.b") >>> app.get_property("application-id") 'a.b' >>> Each instance also has a ``props`` attribute which exposes all properties as instance attributes: .. code:: pycon >>> from gi.repository import Gtk >>> button = Gtk.Button(label="foo") >>> button.props.label 'foo' >>> button.props.label = "bar" >>> button.get_label() 'bar' >>> To track changes of properties, :obj:`GObject.Object` has a special ``notify`` signal with the property name as the detail string. Note that in this case you have to give the real property name and replacing "-" with "_" wont work. .. code:: pycon >>> app = Gio.Application(application_id="foo.bar") >>> def my_func(instance, param): ... print("New value %r" % instance.get_property(param.name)) ... >>> app.connect("notify::application-id", my_func) 11L >>> app.set_property("application-id", "something.different") New value 'something.different' >>> You can define your own properties using the :obj:`GObject.Property` decorator, which can be used similarly to the builtin Python :any:`property` decorator: .. function:: GObject.Property(type=None, default=None, nick='', blurb='', \ flags=GObject.ParamFlags.READWRITE, minimum=None, maximum=None) :param GObject.GType type: Either a GType, a type with a GType or a Python type which maps to a default GType :param object default: A default value :param str nick: Property nickname :param str block: Short description :param GObject.ParamFlags flags: Property configuration flags :param object minimum: Minimum value, depends on the type :param object maximum: Maximum value, depends on the type .. code:: python class AnotherObject(GObject.Object): value = 0 @GObject.Property def prop_pyobj(self): """Read only property.""" return object() @GObject.Property(type=int) def prop_gint(self): """Read-write integer property.""" return self.value @prop_gint.setter def prop_gint(self, value): self.value = value ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/guide/api/signals.rst0000664000000000000000000000547415074674453017350 0ustar00rootroot.. currentmodule:: gi.repository ======= Signals ======= GObject signals are a system for registering callbacks for specific events. To find all signals of a class you can use the :func:`GObject.signal_list_names` function: .. code:: pycon >>> GObject.signal_list_names(Gio.Application) ('activate', 'startup', 'shutdown', 'open', 'command-line', 'handle-local-options') >>> To connect to a signal, use :meth:`GObject.Object.connect`: .. code:: pycon >>> app = Gio.Application() >>> def on_activate(instance): ... print("Activated:", instance) ... >>> app.connect("activate", on_activate) 17L >>> app.run() ('Activated:', ) 0 >>> It returns number which identifies the connection during its lifetime and which can be used to modify the connection. For example it can be used to temporarily ignore signal emissions using :meth:`GObject.Object.handler_block`: .. code:: pycon >>> app = Gio.Application(application_id="foo.bar") >>> def on_change(*args): ... print(args) ... >>> c = app.connect("notify::application-id", on_change) >>> app.props.application_id = "foo.bar" (, ) >>> with app.handler_block(c): ... app.props.application_id = "no.change" ... >>> app.props.application_id = "change.again" (, ) >>> You can define your own signals using the :obj:`GObject.Signal` decorator: .. function:: GObject.Signal(name='', flags=GObject.SignalFlags.RUN_FIRST, \ return_type=None, arg_types=None, accumulator=None, accu_data=None) :param str name: The signal name :param GObject.SignalFlags flags: Signal flags :param GObject.GType return_type: Return type :param list arg_types: List of :class:`GObject.GType` argument types :param accumulator: Accumulator function :type accumulator: :obj:`GObject.SignalAccumulator` :param object accu_data: User data for the accumulator .. code:: python class MyClass(GObject.Object): @GObject.Signal(flags=GObject.SignalFlags.RUN_LAST, return_type=bool, arg_types=(object,), accumulator=GObject.signal_accumulator_true_handled) def test(self, *args): print("Handler", args) @GObject.Signal def noarg_signal(self): print("noarg_signal") instance = MyClass() def test_callback(inst, obj): print "Handled", inst, obj return True instance.connect("test", test_callback) instance.emit("test", object()) instance.emit("noarg_signal") ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/guide/api/weakrefs.rst0000664000000000000000000000172215074674453017507 0ustar00rootrootWeak References =============== While Python has a builtin ``weakref`` module it only allows one to create weak references to Python objects, but with PyGObject the Python object "wrapping" a GObject and the GObject itself might not have the same lifetime. The wrapper can get garbage collected and a new wrapper created again at a later point. If you want to get notified when the underlying GObject gets finalized use :meth:`GObject.Object.weak_ref`: .. method:: GObject.Object.weak_ref(callback, *user_data) Registers a callback to be called when the underlying GObject gets finalized. The callback will receive the give `user_data`. To unregister the callback call the ``unref()`` method of the returned GObjectWeakRef object. :param callback: A callback which will be called when the object is finalized :type callback: :func:`callable` :param user_data: User data that will be passed to the callback :returns: GObjectWeakRef ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/guide/cairo_integration.rst0000664000000000000000000000210315074674453020621 0ustar00rootroot================= Cairo Integration ================= Despite `cairo `__ not being a GObject based library, PyGObject provides special cairo integration through `pycairo `__. Functions returning and taking cairo data types get automatically converted to pycairo objects and vice versa. Some distros ship the PyGObject cairo support in a separate package. If you've followed the instructions on ":ref:`gettingstarted`" you should have everything installed. If your application requires the cairo integration you can use :func:`gi.require_foreign`: .. code:: python try: gi.require_foreign("cairo") except ImportError: print("No pycairo integration :(") Note that PyGObject currently does not support `cairocffi `__, only pycairo. Demo ---- The following example shows a :obj:`Gtk.Window` with a custom drawing in Python using pycairo. .. figure:: images/cairo_integration.png :scale: 75% :align: center .. literalinclude:: code/cairo-demo.py :linenos: ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/guide/code/cairo-demo.py0000775000000000000000000000603115074674453017701 0ustar00rootroot#!/usr/bin/env python3 """ Based on cairo-demo/X11/cairo-demo.c """ import cairo import gi gi.require_version('Gtk', '4.0') from gi.repository import Gtk SIZE = 30 class Application(Gtk.Application): def do_activate(self): window = Gtk.ApplicationWindow(application=self, default_width=450, default_height=600) drawing_area = Gtk.DrawingArea() drawing_area.set_draw_func(self.draw) window.set_child(drawing_area) window.present() def triangle(self, ctx): ctx.move_to(SIZE, 0) ctx.rel_line_to(SIZE, 2 * SIZE) ctx.rel_line_to(-2 * SIZE, 0) ctx.close_path() def square(self, ctx): ctx.move_to(0, 0) ctx.rel_line_to(2 * SIZE, 0) ctx.rel_line_to(0, 2 * SIZE) ctx.rel_line_to(-2 * SIZE, 0) ctx.close_path() def bowtie(self, ctx): ctx.move_to(0, 0) ctx.rel_line_to(2 * SIZE, 2 * SIZE) ctx.rel_line_to(-2 * SIZE, 0) ctx.rel_line_to(2 * SIZE, -2 * SIZE) ctx.close_path() def inf(self, ctx): ctx.move_to(0, SIZE) ctx.rel_curve_to(0, SIZE, SIZE, SIZE, 2 * SIZE, 0) ctx.rel_curve_to(SIZE, -SIZE, 2 * SIZE, -SIZE, 2 * SIZE, 0) ctx.rel_curve_to(0, SIZE, -SIZE, SIZE, - 2 * SIZE, 0) ctx.rel_curve_to(-SIZE, -SIZE, - 2 * SIZE, -SIZE, - 2 * SIZE, 0) ctx.close_path() def draw_shapes(self, ctx, x, y, fill): ctx.save() ctx.new_path() ctx.translate(x + SIZE, y + SIZE) self.bowtie(ctx) if fill: ctx.fill() else: ctx.stroke() ctx.new_path() ctx.translate(3 * SIZE, 0) self.square(ctx) if fill: ctx.fill() else: ctx.stroke() ctx.new_path() ctx.translate(3 * SIZE, 0) self.triangle(ctx) if fill: ctx.fill() else: ctx.stroke() ctx.new_path() ctx.translate(3 * SIZE, 0) self.inf(ctx) if fill: ctx.fill() else: ctx.stroke() ctx.restore() def fill_shapes(self, ctx, x, y): self.draw_shapes(ctx, x, y, True) def stroke_shapes(self, ctx, x, y): self.draw_shapes(ctx, x, y, False) def draw(self, da, ctx, width, height): ctx.set_source_rgb(0, 0, 0) ctx.set_line_width(SIZE / 4) ctx.set_tolerance(0.1) ctx.set_line_join(cairo.LINE_JOIN_ROUND) ctx.set_dash([SIZE / 4.0, SIZE / 4.0], 0) self.stroke_shapes(ctx, 0, 0) ctx.set_dash([], 0) self.stroke_shapes(ctx, 0, 3 * SIZE) ctx.set_line_join(cairo.LINE_JOIN_BEVEL) self.stroke_shapes(ctx, 0, 6 * SIZE) ctx.set_line_join(cairo.LINE_JOIN_MITER) self.stroke_shapes(ctx, 0, 9 * SIZE) self.fill_shapes(ctx, 0, 12 * SIZE) ctx.set_line_join(cairo.LINE_JOIN_BEVEL) self.fill_shapes(ctx, 0, 15 * SIZE) ctx.set_source_rgb(1, 0, 0) self.stroke_shapes(ctx, 0, 15 * SIZE) app = Application() app.run() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/guide/debug_profile.rst0000664000000000000000000000544215074674453017740 0ustar00rootroot===================== Debugging & Profiling ===================== Things can go wrong, these tools may help you find the cause. If you know any more tricks please share them. GObject Instance Count Leak Check --------------------------------- Requires a development (only available in debug mode) version of glib. Jhbuild recommended. :: jhbuild shell GOBJECT_DEBUG=instance-count GTK_DEBUG=interactive ./quodlibet.py * In the GTK Inspector switch to the "Statistics" tab * Sort by "Cumulative" and do the action which you suspect does leak or where you want to make sure it doesn't repeatedly. Like for example opening and closing a window or switching between media files to present. * If something in the "Cumulative" column steadily increases there probably is a leak. cProfile Performance Profiling ------------------------------ * https://docs.python.org/2/library/profile.html * bundled with python :: python -m cProfile -s [sort_order] quodlibet.py > cprof.txt where ``sort_order`` can one of the following: calls, cumulative, file, line, module, name, nfl, pcalls, stdname, time Example output:: 885311 function calls (866204 primitive calls) in 12.110 seconds Ordered by: cumulative time ncalls tottime percall cumtime percall filename:lineno(function) 1 0.002 0.002 12.112 12.112 quodlibet.py:11() 1 0.007 0.007 12.026 12.026 quodlibet.py:25(main) 19392/13067 0.151 0.000 4.342 0.000 __init__.py:639(__get__) 1 0.003 0.003 4.232 4.232 quodlibetwindow.py:121(__init__) 1 0.000 0.000 4.029 4.029 quodlibetwindow.py:549(select_browser) 1 0.002 0.002 4.022 4.022 albums.py:346(__init__) ... ... SnakeViz - cProfile Based Visualization --------------------------------------- * https://jiffyclub.github.io/snakeviz/ * ``pip install snakeviz`` :: python -m cProfile -o prof.out quodlibet.py snakeviz prof.out Sysprof - System-wide Performance Profiler for Linux ---------------------------------------------------- * https://www.sysprof.com/ :: sysprof-cli -c "python quodlibet/quodlibet.py" sysprof capture.syscap GDB --- :: gdb --args python quodlibet/quodlibet.py # type "run" and hit enter Debugging Wayland Issues ------------------------ :: mutter --nested --wayland # start your app, it should show up in the nested mutter :: weston # start your app, it should show up in the nested weston Debugging HiDPI Issue --------------------- :: GDK_SCALE=2 ./quodlibet/quodlibet.py :: MUTTER_DEBUG_NUM_DUMMY_MONITORS=2 MUTTER_DEBUG_DUMMY_MONITOR_SCALES=1,2 mutter --nested --wayland # start your app, it should show up in the nested mutter ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/guide/deploy.rst0000664000000000000000000000503515074674453016424 0ustar00rootroot.. include:: ../icons.rst ====================== Application Deployment ====================== There is currently no nice deployment story, but it's not impossible. This is a list of random notes and examples. |linux-logo| Linux ------------------ On Linux there is no single strategy. Quod Libet uses distutils, MyPaint uses SCons. Gramps uses distutils. |macosx-logo| macOS ------------------- On OSX you can use `gtk-osx `__ which is based on jhbuild and then `gtk-mac-bundler `__ for packaging things up and making libraries relocatable. With macOS bundles you generally have a startup shell script which sets all the various env vars relative to the bundle, similar to jhbuild. |windows-logo| Windows ---------------------- On Windows things are usually build to be relocatable by default, so no env vars are needed. You can build/install through MSYS2, copy the bits you need and you are done. For GUI application you'll also need an exe launcher that links against the python dll. Example Deployments ------------------- * `Quod Libet `__ provides a Windows installer based on MSYS2 and NSIS3. On macOS, jhbuild is used for building, gtk.mac-bundler for packing things up and `dmgbuild `__ for creating a dmg. distutis is used for building/installing the application into the final environment. Most of this is automated and scripts can be found in the git repo. * `MyPaint `__ provides a Windows installer based on MSYS2 and Inno Setup. It uses SCons for building/installing the application. * `Passphraser `__ uses the Hello World GTK template build system (see below). Other options ------------- * `PyInstaller `_ is a program that freezes (packages) Python programs into stand-alone executables, under Windows, Linux, Mac OS X, and more. PyInstaller's packager has built-in support for automatically including PyGObject dependencies with your application without requiring additional configuration. * `Hello World GTK `_ is a template build system for distributing Python-based GTK applications on Windows, macOS, and Linux. First, an application directory is assembled using PyInstaller. Then, a different program is used to package the resulting directory. For Windows, NSIS3 is used. For macOS, the built-in hdiutil is used. For Linux, AppImageKit is used. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/guide/faq.rst0000664000000000000000000000074315074674453015700 0ustar00rootroot========================== Frequently Asked Questions ========================== How can I use PyGObject with the official CPython builds on Windows? -------------------------------------------------------------------- https://sourceforge.net/projects/pygobjectwin32 provides binaries which should be ABI compatible with the official CPython binaries. I'd recommend using msys2 if at all possible, since there are more people involved and it's easier to fix/patch things yourself. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/guide/flatpaking.rst0000664000000000000000000000051715074674453017250 0ustar00rootrootFlatpaking ========== `Flatpak `_ is perfect for packaging applications for Linux. Flatpak comes with `great documentation `_ and a specific guide about using it to package Python applications can be found `here `_. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/guide/gtk_template.rst0000664000000000000000000000567715074674453017624 0ustar00rootroot.. _guide-gtk-template: ============ Gtk.Template ============ A GtkWidget subclass can use a `GtkBuilder UI Definition `__ XML document as a template to create child widgets and set its own properties, without creating a GtkBuilder instance. This is implemented for Python by PyGObject with Gtk.Template. The subclass uses a ``@Gtk.Template`` decorator and declares a class variable ``__gtype_name__`` with the value of the XML ``template`` element ``class`` attribute. Child widgets are declared, typically with the same names as the XML ``object`` element ``id`` attributes, at the class level as instances of ``Gtk.Template.Child``. Signal handler methods, typically with the same names as the XML ``signal`` element ``handler`` attributes, use the ``@Gtk.Template.Callback`` decorator. ``Gtk.Template()`` takes a mandatory keyword argument passing the XML document or its location, either ``string``, ``filename`` or ``resource_path``. ``Gtk.Template.Child()`` and ``Gtk.Template.Callback()`` optionally take a ``name`` argument matching the value of the respective XML attribute, in which case the Python attribute can have a different name. Examples -------- .. code-block:: python xml = """\ """ @Gtk.Template(string=xml) class Foo(Gtk.Box): __gtype_name__ = "example1" hello_button = Gtk.Template.Child() @Gtk.Template.Callback() def hello_button_clicked(self, *args): pass Python attribute names that are different to the XML values: .. code-block:: python @Gtk.Template(string=xml) class Foo(Gtk.Box): __gtype_name__ = "example1" my_button = Gtk.Template.Child("hello_button") @Gtk.Template.Callback("hello_button_clicked") def bar(self, *args): pass Subclasses that declare ``__gtype_name__`` can be used as objects in the XML: .. code-block:: python xml = """\ """ class HelloButton(Gtk.Button): __gtype_name__ = "ExampleButton" @Gtk.Template(string=xml) class Foo(Gtk.Box): __gtype_name__ = "example3" hello_button = Gtk.Template.Child() @Gtk.Template.Callback() def hello_button_clicked(self, *args): pass ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/guide/images/cairo_integration.png0000664000000000000000000005754215074674453022063 0ustar00rootroot‰PNG  IHDRÂKtO–ÈsBIT|dˆtEXtSoftwaregnome-screenshotï¿>^ôIDATxÚí˜E¾ö’%Çˬ"0Ü.ÈÓz?PÝEX¢ WDÆ»Œ. ’Àˆ‚ Iv]{%HÎ.(0 Ä!3CŒèêš®®±¾ó¶s¸ÌépÎéîªêwŸç÷ìàœî®úWŸþÍ¿ºB(ôËÿŠ…©wà 7þøã¨RŠöÿò«¯Ä__CÜ}ogÑ"­èб“xåÕ׌ÿnV¶Ï?ÿ\Œ;N¤Ýþ›¨ޝÂç@™w_WqcÚÍÆ¹_ _ë«Bç¾ôX”¡c—®âÿµï RnjeüÿÚ¿¯»ðùXË{éuPîQ㲌zì?p@\—z£çH ååŸÃùy/R„^pO§ûŒëýî¾.† Ïœ9#îíúû¸ïCŠ(Ë+¯½n|úãâèÑcâtøKñD~?ñ…ÅŽ»ÄgŸ}&þgî<ã³#ÆŒµáÓC†ŠÎŸ¿ðßÿò×Wÿ>:k¼øè£Œkàß‹Yù¦dO+ò¸Â×|íÍ9Æ¿Ÿzf°qÍI“§ÿ~cÎß.+×ËyE|°uëÿýûÏÛ¶ï0~¾óî߯]ÞÈyG†cTø¸ì3ß?úxÆ…ràß/M›nü{¤x?´'ÃkûðCq×=¿½ CüAˆŸÛ¦ß-9B’àÑ®Ã=Æ—`ßþý–ŸýòË/ÏþWûtKž8qâ¢cñ—&þ;¾„ø÷ÑcÇlý 9u\ák"kÿ‘]áßþ}O§Î—•ëܹsâŸÿüü¿Ϟ=gdŽøÙZ¼åœŸ/|\ûßv4þ½1'ç—Þ•.¾øâ‹ Cμ)B?dÐ#’—ŸÏw„$˜4¿ñ&ã‹€ŒïÒß}°m›xð‘GÅÍ¿ù/£k4ò¥ÁÏV"¼ô\©­Ûÿ]„øwDFèvŒÖu„ÿvC«´"+|”›ZÙÕt}ËV¶Ëyé¿í”×ìawéq8_ä3]zôü% |~’ñÿ·µ½ó¢n\BºÍ©S§l0rmü¡vüø Š0#¼ôwè*ÁïV¯]k<Ø?ùäÇB‰€/šU†U”íd„‘:|xü¸í‡Õ¿í”7–Œ,Zºô¢z9Š÷"EèY9Nœ-êKkW„x 3B7aúïî5F¤ZÂD×"ç´¾í7¦Ž…‹—]ލxä±þbÝúwc¡òš‰0Ê )¢…?÷çy£¬—þŽè;mA–r@x…³?ü9JB<™ã¸ùý÷ ²Ø?1n„ê !Á!FÔ"ÓÆ £ ›61n„"$„G„èrÅïÛÜ~‡xkþ|ÆŒP„„BEH!„P„„BEH!„P„„BEH!„P„„BEH!„È/BL’%„B‚JB!A%tøpž „B‚Jhò䉂B *¡>:'!„ BB¡ !„ŠB¡ !„ŠB¡ !„ŠB¡ !„ŠB¡ !„ŠB¡ !„ŠB¡ !„ŠB¡ !„ŠB¡ !„ŠB¡ !„ŠB¡ !„ŠB¡ !„ŠB ¦7oΣGýû÷¿ˆÉ“_4=nüøñ—£Ò±£F4êîwœ ó·¿Í1=‡ŠÇzgBE般¬,Q¢D  ….ãŽ;î0=öÆ[yœÌÇ^qÅ}uG üŒsaüqó›CÑc½Š3!„"tDNNŽéÃY7:´Ècį8A„^ÄY6Þ~{A êKˆ’"D—•ÕƒYF“`ÄÂÏ8A„nÇY&¶jÕʨïÝwß͇!ª‹Q]„x/gUO/к‹pðàgb¾Ž.Œ€®ø÷Þ{—6BTíµ’¡*"\±b¹¨X±bÔc¼î²£õúž:uR¤¥¥E­3³BB$,3r¤½n»±cÇ(Ý5j&Ô”o˜"ÔÈ.Z‘¾ûîz>Ü‘yú„Õû³ªU«ŠwÞyç²ã²³³Å!ƒ‹döì—M¯éDZ¡“®_·ˆVv°páÛÊD¢ûóÒÉÌ QlB}4F“ ªÎ ý`‚sr6‰×^{Uœ;w–Ya8zôˆ§’%KŠJ•*‰:uꈛnºItéÒE 6LÌ›7×ø cõ ùùyFLıB̬æô>œ/NŸ>E:‘¡n,,C  áŠ"Œ·+ôºë®¯¿þš!ÄhY!ÞAwîÜIlß¾-°÷Þ£ÆóÊ,Z´0Ðß«3gN Xàž+^¼x‘1š6-ÛôO>ù¤¨\¹²èÙ³‡X¹rEh%C%8bĈð_D£Œ(BÏ»A#B¼çž{.`ç.^¼ØI{ÿý÷[~öÊ+¯Œzß”-[Vœßºuk±lÙRа(00F5 F^¦Lédˆaõ±.O¦"Ë—/‹ù]¤êc"ó  ]wÝ»wÅŠ»ð½Ü»wé1ÈT¢Åõ–[n1=vÍšÕ†t—¥Õ”·1cF›f”åË—¿ì´QÝ6£cà•W^Ç—F‚d“aPçÕéÞóY бzàë2æzõê9¾×ñ½×?ýéO¦Ç¢«ŸKJªe<“T|Ÿˆ2Ïû–égöìÙµ[<ú袻zõ*S‰&''‹ Þ£J/¶ýtmL2¤ƒ3M"è“çÑZTÖ0&//zÖaö€G·³ÙûÇK³É*UªˆÌÌLqèÐAéc†2¢¬(séÒ¥Åîݹ¦Ÿ¿þúëcüÐC™ŠÏs´Eƒýœ†`5íCR„ÁɃ B«P¡‚éwò™gžŽi°Ì‘#‡£÷׿¾õ8ÈcÐ-([¼0zÙ+ÊX¸Ìýúõ3=nÀ€Që{à 7D=®zõê¦1ž0a»Fã‘ 2Ä_ÞfAFÀ‚!IøK½OŸ>EÞÿN³AßeõîÝËòûˆ‡ññãF=ljÇ8¯[÷wñ “Ä AƒÄ}÷Ýgz]<üÍ®‰LgÏž‘*V˜úРAƒ"Ë[®\¹pæ|Ȳ‹±lÔ¨‘£I“ž7bf–£Û8ZŒð>—ƒe A?døâ‹/˜ÊP–y‚¡^ìÚµó2!b´¨c‘ÙàÁU­Z5íºQ1…óÚÌ–mDÖœÈîJ¼Ó2{a oÉ'¼CF¨Y¹1ÍÁìÌXx«]p\‡.ºVjjª­é-aHã­þ⃘¼Ü„5š eš,OêÉÎ; !â¡f%µˆñÈ©¿ûÝï¤.ûsÏ=gºåvIqr¾¾}¶|faã\º’ÍÖ1íÚµ+E˜( ZÉðÁ´¼©T›"Ám˜ÔÚ†)Z6ÈÁ-ÿǵ×6‰Ÿìlù»1¶«û\Zv¼Ós:jªþã?þÃô™…ka€Žj™~aÐæ¡£ Æy¦4nB3ª8OÓ 8ÝA'0-¡T©RQc¤Ê>ŒÈ̱Æf¤ÜÍš5‹yâÿÖ­)ÖÈ:žªô ‰Ö®hs«))a ]œÑ$M†ªN–§Õï·~ýë_34K(F‹OÅŠ•«ÏèÑ£Œ×-xh糞ŸÂKËaÍUœ[µx  ·)’š&Mšˆ;î¸ÃÓ¬V›w„f2´À¥2TyÅŠP-0Ý{õë×÷<\¹r…xöÙ!Òwõ›e *¶¹ù¢èéúÏÿüO1s挨ŸÁ;`Äû#Zm²++X‘#Hñ‡Ÿ™¬V£F‹’¡Ý‡D†ª/›Fª 7¢›ÙàªU+ÕP"•y•$Lˆv?·o—–÷DÙ7£J'Nœõ³˜zÁ‘í¡© #~<`TœDLSˆ:Ž÷'n P•.Ø-[6#/²×ÿ(~ÿûßõ:ôYíÚYQQóê°å¿¡cFú1Þxc‹@È"$E‰pPŽü™søïÿ~‚q¢ãï*½T†è‡Ÿ2e EH´G§iøÞb;*æ÷â]±Õ€?€×72-”M*:x&"C|™"ëÜq;%ŠŸS5äÌ Çk¼/‹¼3Ó±}‘ bG ;"Ī2Aß2‰"LÐtŠF‰ÿ÷×bºE¨–Ÿzê)1þ<)³Bw±7kß~ýÕâÆê8v$ذaC-V ¢=`úôi¶n*]&ÐS„ꈰðI-[¶ôEˆEe…Œ‘žÞ^¬[÷wéÚ7+++jûÞ~ûíZÜÃóæÍ½hN`4±M—lüéO-Z¤„=üðÃÆQX s"½ÜÑ^;bµQ×¼ãŽ;L¯%Ë FV {Ûl‘k°víÚ„fŸ:tˆz-Lÿx≠)LÉØXv_û1b•¤utáµ×^•R€…Á÷²ŽgìIíØM›6Šƒïö0wïs± ÇßÿþNÔc̶‚·Ür‹S ¯IZx_hvŽ>}z‹Aƒï3ÌõC ÍÞ þêW¿²ü£E†ù´R‰ÂÁ_ “&=/åô J"4ƒkŠzÇŠËE… I ŒÖ>·ÝvkÔã0 ð2iEîSÙ笢›;Ú»U0eÊÓ˜Õ?ÚqØ`×ì8´!Ú’","ë’U†vÆ$b~QK„:dƒª±xñâ‹æêaë"³A«V­ŒÚ> 40½²–hÇ¢Û[•=L1x{_V©Rå¢: v˜¦í8솋‘1V¯^=ª—,YÂw„fïád•¡#GŽäN÷!æ³]:±Y¥I骂‰ôØ‹qƲcfŸÅüºh÷J¹råLŨ٢F¨â]êÑ£G”‹ÊŒ²×ªUËV÷$–ß‹E„Ѿ£õë'Û0q°Œ‘™ªÉ0"A?çr&ÿ¶aÂ;¼?¹Tˆ:eƒˆ¹q2uóæçç‰ÿh9‡Ðì&€l)Ú±Ø/’Ù4kÖLLœ8ѵ©^‚: .V™Yûöw™.îm5ž#Ò%‹gzÏž=Œ6ãô‰(âˆ&CþšŽV¯eÈ õr,ù…‡ „¨K6`¤ûWE¹÷èÑÝôYóÎ;ï˜TØçÏ÷‹èþ5‹ÕÂøCs)µ•V"Dwú¦U[½Å©Ð½¬E(—ßz봠ʃ°µÙ÷ôÕWÿÊû¶0¥Â*a±ÊðdßDÙ÷®Q3ª Áµkרšà‹ÑS!Q ì™g6ïLµ¬Ý{Øe#ÒM‡.=üŒwŒ­Zµsç¾Åv2HpÞ¼¹bذaÆ~šˆb†Ø!†ˆ%–¼S¹Ž¾‹[‰ ÏýÒ/YñâÅLËêØhïü<eµ"¼tééDhö>Äú.RÖcÝĬLfk+¢«Hæc­Ö 唢¾‹ÐlX2v-VíX?%èT„Vƒâx ã±®~‘bì6ÊÊÊ’úXN !!E—½– Eè7oηß~»X¶l©Ö"´“"|˜Š"”B‚¡w",<¯êöÛoÓZ„VY!bÁ‡)¡)‹ŽÅƒÁ 5ñU7™YëÕÚj‚±N",œb Ä¥"EH(BŠÐѱnƒyN…GúU„ˆ›s¾.³î"D}1PéÒcÝŽ3!!ExPEÒA!êŽxgÝEXÔ±^Å™íEˆm_¢-‘õ “´;ÖËÁVsÍ–'³Z·QÖcÑMçåàHœÍÊd¶&+«x¬×q&DkB!!!„BB!!!„BB!!!„BB!!!„BB!!!„BB!!!„BB!!!„BB!!!„BB!!!„BB!!!„BB!!!„"ƒ7oΣGýû÷£F4êÎ8ëg¿ˆ´oPêKˆ6"ÌÊÊ%J”¡P( îˆã¬GœýâÒöÕ½¾„h#œœœ@?œ ?´ ÆYí8ûņ ïÙ¾øoøj„H,Btáýá±`œÕ޳_Ü}÷ÝQë‹ßñ¡FEøôàÁÏ0Æ<þøãZ}Yß{ï]qÅWD­/~‡ÏðÁF»FÝeGê+B³lY!!Š –9’YaJJŠ«1¦õ¡U6Ȭ…¦O :ÔÖC¬jÕªbÈÁJ€²Ú©êîv|ÍDX¬X1ebj—J•*B„v²Af…„(4¡Þ® ½‡nu1¡n]…A©¯ÝlYáÅœ>}J,[¶T 6LtìØÑè©Q£Æ…?žJ•*eü\·n]ѺukÑ¥Kã³óæÍùùyDˆb‚Ø F­Zµ2b†Ø!†ˆ%~FlcÄŸEìÑ¡æ2”±¡~õu’ 2+<'V¬X.zöì!*W®s·zñâÅE³fÍŒEV®\¸¢Î¨ûu×]gÄ"Ö8V©REôîÝËhŠPCÊZvŠP¯ú:̓œ.Y²D¤¥¥¹ò¾999YdfÔrnjá¨#êêF Û´icd‰¡&2”¹Ì¡^õ% ZVˆ®;d€xîÅ ,dŠÏ??Qœ:uRùØ¡¨ êäEìðÚêðá|ŠPeÊ^VŠPŸúZeƒ™(ƒnܸAÔ¯Ÿì˨䤤$1bÄqìØQåâ†2£ìIIµ|‰Ú mG*(CÊHêS_;’³#K»BË—/ïû4Œê©§Ä¡C¥ʈ²âÝßq«P¡‚Xºt E¨’hTÉZ)B=êëDpAÌ 1ø¢bÅŠRÍ[ÅÈÉáÇK9ReBÙ̦ùÚP†4ÒíG(£pT꺥õ¨¯¹-+ÌÍÝ%jÖ¬éèa‹{!;;[¼ÿþqàÀ~ã<'Ož{öìëׯ3Þ“ 4H4jÔHT¯^=®‡{ƒ Äüùó¤‰Ê‚2ÅS'Lhذ¡xúéAbÒ¤ç˜!vˆ!®±oß^#¶S§N=ö˜£?RЖhSŠPbñ¨6˜‡"T¿¾±ˆ-(Yá™3§E‹©¶¾“˜ï–“³Éñ5Î;+V¯^eÜ?ñ¼LOO;vl÷-V¸6Êû{¼úbÀ€F,“XF¡¦¦Úk«–-o4Ú–"”P@*Žh¥Õ¯o,R JV8vìËïc¹r匇w¢®¹jÕJÑ·ïÃ1ɤL™2F—äÙ³g<‹®… í¸v,e~䑾 Ÿ qܸ±¡l"RuŽ#E¨v}ãšîYáÞ½{,¨Mš4ÇèÚTƒ‰'ŠzõêÅ4‡nçήÇ×À*9Nˇ:¹9%£T7nlùŽ]¬¡$BRy¢?E¨v}ã‘™îY!V:±šÎàÅÜ>táMŸ>Í®ÓÁ4³fÍt­\8·ÓÁ0¨ÃŒÓ=é–DÛXM×ðë;Rá क़T_ú"T·¾‰™®Ya^^žåT‰È ¯À{3tç]uÕUŽäÓ¹s§„N(ǹ:uº×QPf”=–wñ°ÿ>ËMhkŠÐGAé°þ)E¨n}!1]³Â¬¬,ÓïäK/½ä[ÙÐ;pན«]»¶X»vMÜׯ9p.'ï,±Œš[ÝÇv@[™•q„ ¡_¢ÒeG ŠPÍú&R`:f…f£ÝÞãÓ.[·~ îºëNGRš9sFÌ×ñeË–µ}=”mÛ¶­RĪyóæQˉ¶¦}–NÛBQ„jÖ7‘òÒ-+ܽ;×tÑÑ£GIUÞñãÇÛžçˆzedd8UŠÏ>ñD†íµUQ ò‘)FÕj´9E衸t’ E¨f}Ý—NY!&i›}7e\üïÂÚ¶mk;[k×®8rä°åyñ|ÖÉyQÙâƒ63+7Úœ"ôH†ºI"T³¾nHK§¬°k×®Qëqçí¤.;2±+¯¼ÒÖs«Ú|ðÁûQÏ…ßá3vÎ…kÊ–^Jzzû¨åïÖ­Eè… u” E¨^}Ý–.Y¡Ùü3,÷%{ù±ÂJ:ul=oªU«Vä ü7üÎÎ9®¹æ%öMļÅhu¸öÚ&¡Û2ÔU‚¡zõuSV:d…X,ºT©RQë€**ܧ'NÝ»w·½6ê¢E /‹Ÿ±Sƒc{ôèn\K…˜ ÃV´¹—‹—‡tx:›Î¤Õª¯¢R=+ܼ9ÇtP…j÷ë˜1£E‰%,Ÿ? :gΛvF†âœX~Nµx˜ øÙ²e3Eè– u– E¨V}½”êYáÛo/0ÝAÅ{vîÜ·DåÊ•ö¼Â¹dÚí f;} í)BŸd¨²)Buê률TÎ §MËŽZööíïRö¾Å–Eñn°5Î¥jÌæ]bé7ŠÐª.AŠPúz)'•³B³en»íV¥ï],V·nݘŸWÉÉɶ¦\È Ú0ZýÐö¡Ç2ÔA‚¡õõCLªf…Ï>;$j¹±¬ê÷/6¶u²MáUbdœ?é”~ýú™<“Ÿ¥½”¡.¤Õ¨¯RR5+4kß.]ºhqcç,Äm÷yuß}}ÝÄ6‘  £ÕmOR„¡†õõSH*f…A¸Ÿ!5'»G೺ˆmH²k”Ž€Õ×O©˜¡kÔÉ’i…WÔÁ±ì¥9X†"Tª¾2ˆHµ¬Ðl°ÌÍ7߬ô½‹}÷š6½6æçŽÍÏÏS:mÚ´á`NŸ ƒT_$¤ZV¨ëô Lçô óéÓ§O£9¡ž"Ô©¾2 H¥¬pÁ‚ù¦«©pBý/êçÍ›«d,Š/Î õ\b" J}e’JY¡Ùk€j÷+öN´»ÄÚo¼n€ |u]b ëªr‰5%Ï1ë«“xTÉ ­ÝÎÉÙ¤Ä}Š9vÝÆÛñ,º­Êü Þã¢Û~IPwR„òÕWF騔bK–áŠ'«­Zµªím˜Ö¬Y}Ù9V¯^eûÈ”U؆ mÇm˜|” Î2¤媯ÌÂQ%+4›tݤI©ïO§óš |ÁïtÚ˜·iӦܘ×o ê*CŠP®úÊ,U²Â©S§F-#²$»÷ïßçh~`Û¶mm­ŠÏ8=/Ê"cWq•*U¢–;;;›"ôZ\:É"”§¾*ˆF…¬p÷î\Ó}ëž{î9©îÉY³fŠš5kÚz¦ ^âìÙ3¶ÏÏⳘeA™dŠÑ¸qcMc²gÏnŠÐaé"CŠPžúª U²ÂÔÔÔ¨eÄ2”qÛ¶­ŽÐÆhÐxÞqΜ9ÃÖ¦½…êÞ¾}›±ªS§NÔr¢­½.OˆÔK†¡õUi0Š Â6[aÌž=Û·²?þ¡ÈÌhkšC„Úµk‹µk×Ä}mœçr"_”eö+^³g¿lZÆ &P„~ JuR„rÔW¥Ië*HË‘•/_Þô;yàÀ~OËtîÜY1eÊqõÕW;šÝ#°a¢Ês9Y´ Ì(;êàeÌÐFfåªT©’ÑÖ¡bRY†¡ÿõUqqkÄÝ¿Ëï¤g°ó–~kܸ±#ùà!ïæ»:t•âNÊ„:`)3/v³@ÛX•gÀ€¾Ü[!JP/R„þ×WÅíŽT÷Þ½{LW"‰ÈÆ­n?ìö€9±ì*Å¥wíÚézŒvîÜ!Z·ní¸|¨¦[¸µ£ÚÄjQ´Ý¾}{)BÙD¤¢ )Bë«ê¸ªÜl´aa°jI¢®¹jÕJÑ·ïÃ1­ŠÁ,Çw4*4^p­aÆ9zgY˜GékLàOTyÞ}w½­ë¢mýº¯B” ^2¤ý­¯ŠÙ JG^‹©¶¾“}úôŽéŽ÷fXìûÉ'Ÿõë×y1ì:ˆ;¶û+\;===æò£îˆbË»D¬Ó«WO[×jÙ²¥¯› ‡(A½dHúW_•³A•Dž›»Ëö<=€ð@Ÿ<ùE±qã‘—wÈ8ωÇ9ŠëׯS¦Lƒ 2Þ™U¯^=®Ý °½ä!K›¢,ñnù„˜`%ıBÌ;Äð—ÁL‡Œ,üÅ_0bmwŽcdž#ÎågŒB” ^2¤ý«¯ÊÙ j2_±b¹åûB¯Á;®#FxºX´]P&”Íé`·A®\¹Â÷ø„(A½ÊHúS_²AÕ„¾téÛ»2¸ – ËÌ̇”¾mQF”Õly3/%ˆ6”!.!JP¯²R„þÔW‡lPE©£«³~ýd_äIIµŒ0ÇŽUî{sôè£ì¨ƒ±ÃûÇM›6JÅ¢W™)Bïë«S6¨¢ØóóóDÏž=½—ЇæÍ›S TÙ÷ÏjJêÒ¬Y3Ob‡{m•È”¡Ê×e-;Eè}}uÊU–;ºÙÒÒÒ\y€'''K“aoAݾC°‡!ꈺºCÌ¥\¶l©”uQ$zÕ"ô¶¾:fƒª iz÷î×{0Œ4Eæ‡ÕldÌá5¨3êŽ ±ÆÛda ÚDæú†(½êBz[_³A]$‘’Ë—/3&—wìØQ¤¤¤Cõ##'K—.müŒ «±tíÚÕøì¼ys¥ëºóÄ1Al#Ī^½zFìÃȈYÄ1F¬ñYÈOÆ´RˆÐ®8ðWþ"Q»1y!C31Ubj³ºº-B+Qèo«÷=*‹ž_D8räH©æ°øbৃ„Û"4˃‚Ê]¿„x.B¼ˆ-Q¢DàˆbAª-B š°Êƒb óB&”Q£˜ F@,(BµEÈûÙ›û™ŠÆ™q¦ a×(»FgÆ9¨q&D»Á2YYY~x îˆãÌ83΄xú^¬=J 28P ûÈËAŒ3ã¬Sœ Äî„BEH!„P„„BEH!„P„„BEH!„P„„BEH!„P„„BEH!„P„„BEH!„P„„BEH!„P„„BEH!„P„„BEH!„P„„BEH!„P„„BEH!„ø-£Gˆþýû ÔÙë8oÛ¶5pqFùÅ&„H/¬¬q"  ÔÙk Ö®];pqF)CBˆô"lÔ¨QàШ3%HÆKNNNÔl¿ãCD¸hÑÂÀ> QwJ2Œ‡»ï¾;jñ;>ÔQ@„÷ÜsO`Ψ»Ûñ<ø™ÀK0Âã?®Õ—õ½÷ÞW\qEÔúâwø l„H,ÂÝ»sEÉ’%û`FÝŠ"Lt6ȬEDøæ›oþáŒP„a¢³Af…„(Ô5:tèP[±ªU«Š!C+Êj§N¨»Ÿ]£ÅŠS&¦v©T©R Dh'dVHˆB£FíÊÐ qèV3êÖU”úÚÍ™^ÌéӧIJeKŰaÃDÇŽEJJЍQ£Æ…?žJ•*eü\·n]ѺukÑ¥Kã³óæÍùùyDˆb‚Ø F­Zµ2b†Ø!†ˆ%~FlcÄŸEìÑ¡æ2”±¡~õu’ 2+<'V¬X.zöì!*W®s·zñâÅE³fÍŒi)+W®\ QgÔýºë®3bk«T©"z÷îe´ E¨¡ e-;E¨W}fƒAÎ —,Y"ÒÒÒ\yßœœœ,23j=WuCQW7bئM#K¤5‘¡Ìe¦õªo,Ù`вBtÝ!Ä;p/a!S|þù‰âÔ©“ÊÇu@]P'/b‡?ÐÐV‡çS„*ËPö²R„úÔ×*„èÌD„¬pãÆ ¢~ýd_F%'%%‰#FˆcÇŽ*7”eOJªåKìÐfh;ŠPAªPFŠPŸúÚ‘œYêÜZ¾|yß§é`ÔøSO=%:(}ÌPF”ïîüŽ[… ÄÒ¥K(B•D£JÖJêQ_'‚ bVˆÁ+V”jÞ*FN>\Ê‘’(Êf6ÝÈІ2 ¤‘n?B…£R×-E¨G}È-hYanî.Q³fMG[Ü ÙÙÙâý÷·ˆöç9yò„سg·X¿~ñžlРAÆâøÕ«WëáÞ A1þ0tΜ7 ìŒ Å9±üœjñ0ð³eËfŠÐ-ê,AŠP­úz!)ճ·ß^`º#‚Š÷ìܹo‰Ê•+'ìy…sÉ´Û…Ìvú@ÛS„>ÉPe R„êÔ×KA©œN›–µìíÛߥì}‹-‹âÝ `k$œKÕ8˜Í»ÄÒo¡2T]‚¡:õõRN*g…f+ÊÜvÛ­Jß»X­nݺ1?¯’““mM¹´a´ú¡í)Be¨ƒ)B5ê뇘TÍ Ÿ}vHÔrcXÕï_llëd5šÂ«ÄÈ8Ò)ýúõ3y&?Kz)C]$HªQ_?¤¤jVhÖ¾]ºtÑâÆÎXˆÛîóê¾û:ûº‰m"AF«'Úž"¤)B ëë§TÌ ƒp?CjNvÀgu!Ú"d×(«¯Ÿ2R1+ Bר“%Ó ¯¨ƒcÙ5Jr° E¨T}e‘jY¡Ù`™›o¾Yé{ûî5mzmÌÏ+›ŸŸ§t Ú´iÃÁ2œ>A©¾2HHµ¬P×é˜,ÎéæÓ'¦OŸFrB=E¨S}eJYá‚óMWSá„ú_&ÔÏ›7WÉX/^œê¹ÄE”úÊ$•²B³%Ö ÕîWìhw‰µ7ÞxÝøêºÄÖUåkK0žc(ÖW'ñ¨’Z-º“³I‰ûsþì.º¶ãYt[•ù…6¼ÇE·ý’ î2¤嫯ŒÒQ)+Ä–<2,ÃOV[µjUÛÛ0­Y³ú²s¬^½Êö9)«° ÚŽÛ0ù(AeHÊU_™…£JVh6éºI“&RߟN7æ5ø‚ßé´1oÓ¦M¹1¯ßÔU†¡\õ•Y6ªd…S§NZFdI2vîß¿ÏÑüÀ¶mÛÚZ7Ÿqz^”EÆ®â*UªD-wvv6E赸t’!E(O}U Yáîݹ¦ûÖ=÷ÜsRÝ“³fÍ5kÖ´õLA½222ÄÙ³glŸŸÅ1f1) Ê‚2É£qãÆšÆdϞݡÂÒE†¡<õUA2ªd…©©©Qˈd(ã¶m[- Ñ ñ¼ãœ9s†­M{ /Ô½}û6)bU§N¨åD[{]ž%¨— )B9ê«Ò`„m¶Â ˜={¶oe;~üC‘™9ÐÖ4‡µk×k×®‰ûÚ8ÎåD¾(+ÊìW¼fÏ~Ù´Œ&L ý”ê2¤娯J“ÖU6–#+_¾¼éwòÀýž–éܹ³bÊ”)âꫯv4»G`/ÂD•çr²h7@™QvÔÁ˘¡ÌÊU©R%£­)B Ĥ² )Bÿë«ââÖ*ˆ»ÿþ–ßI/Î`ç,ýÖ¸qcGòÁCÞÍwuè*Å5œ” uÀRf^ìf¶±*Ï€|¹·B” ^2¤ý¯¯ŠÛ© ï½{÷˜®D‘[Ý~ØísbÙU‹KïÚµÓõíܹC´nÝÚqùP'L·pkG ´‰Õ¢h»}ûöR„²‰HER„þÖWÕ pU¸ÙhÃÂ`Õ’D]sÕª•¢o߇cZƒY†îhTh¼àZÆ sôβ0<ÒטÀŸ¨ò¼ûîz[×EÛúu_…(A½dHú[_³A•$Ž.¼-Rm}'ûôéÓïͰØ÷“O>)êׯóbØ:t;vl÷-V¸vzzzÌåGÝÄ"–w‰X!§W¯ž¶®Õ²eK_7Q‚zÉ"ô¯¾*gƒ*‰<7w—íyz;à>yò‹bãÆ "/ïqž'Žsׯ_'¦L™, d¼3«^½z\»A`{%ÈC–6EYâÝò 1ÁJ0ˆb…˜!vˆá/ƒ™Yø‹/¾`ÄÚîÇÈH EèE‹ö¡º»ßmÛ¶:Ú±ZWÄÂÍXcYÆ cÔ]‡¹t„ø2j´Q£F{h Î^Å7è2ôB‚/^ìÙDn™@Qw>D E#YYã÷à@½ŒqPeè¥#tëÖ-pqFù%aœëÜáÝB@½Ž3„´8{-ApðàÀÅuæ”P„„BEH!„P„„BEH!„P„„BEH!„P„„BEH!„P„„BEH!„P„„BEH!„P„„BEH!„P„„BEH!„P„„BEH!„P„„¼÷Þ»Œ!!!äî»ï6`,¡ d6xÅW0+$„"$$Ù`(2`VHˆ„"ܱc»èß¿?qb–ˆØ¿ýöƳ€¿ýmŽÖÙ`D„Ì ‘4#:tè…/*1±JTÜ~†1-àñÇ×>dVHˆä]£”¡·¤õá¥Ù ³BBxGHz'AŠP• 2+$DÁ2”¡7¤õa´lY!!ŠŒ¥ Ý— E¨·ͲAf…„(2}‚2tW‚¡¾"´Ê™¢Ð}J,[¶T 6LtìØQ¤¤¤ˆ5jˆJ•*q*Uª”ñsݺuEëÖ­E—.]ŒÏΛ7WäççQ ˆ bƒájÄ ±C KüŒØ"ƈ5>‹Ø£ (BÍe(c(Býêë$dVxN¬X±\ôìÙCT®\9ænõâÅ‹‹fÍš 3¬\¹"p1DQ÷뮻ΈE¬q¬R¥ŠèÝ»—Ñ&¡†2”µì¡^õuš 9+\²d‰HKKså}srr²ÈÌ(rrr´ê†:¢®nİM›6F–Hj"C™ËLêUßX²Á e…èºCX¬X1Oa!S|þù‰âÔ©“ÊÇu@]P'/b‡?ÐÐV‡çS„*ËPö²R„úÔ×*ŒlÃä¬pãÆ ¢~ýd_F%'%%‰#FˆcÇŽ*7”eOJªåKìÐfh;ŠPAªPFŠPŸúÚ‘œYêÜZ¾|yß§é`ÔøSO=%:(}ÌPF”ïîüŽ[… ÄÒ¥K(B•D£JÖJêQ_'‚ bVˆÁ+V”jÞ*FN>\Ê‘’(Ê1+ hCÒH·¡ŒÂQ©ë–"Ô£¾Nä´¬07w—¨Y³¦£‡-î…ììlñþû[Äûóœ0tΜ7 ìŒ Å9±üœjñ0ð³eËfŠÐ-ê,AŠP­úz!)ճ·ß^`º#‚Š÷ìܹo‰Ê•+'ìy…sÉ´Û…Ìvú@ÛS„>ÉPe R„êÔ×KA©œN›–µìíÛߥì}‹-‹âÝ `k$œKÕ8˜Í»ÄÒo¡2T]‚¡:õõRN*g…f+ÊÜvÛ­Jß»X­nݺ1?¯’““mM¹´a´ú¡í)Be¨ƒ)B5ê뇘TÍ Ÿ}vHÔrcXÕï_llëd5šÂ«ÄÈ8Ò)ýúõ3y&?Kz)C]$HªQ_?¤¤jVhÖ¾]ºtÑâÆÎXˆÛîóê¾û:ûº‰m"AF«'Úž"¤)B ëë§TÌ ƒp?CjNvÀgu!Ú"d×(«¯Ÿ2R1+ Bר“%Ó ¯¨ƒcÙ5Jr° E¨T}e‘jY¡Ù`™›o¾Yé{ûî5mzmÌÏ+›ŸŸ§t Ú´iÃÁ2œ>A©¾2HHµ¬P×é˜,ÎéæÓ'¦OŸFrB=E¨S}eJYá‚óMWSá„ú_&ÔÏ›7WÉX/^œê¹ÄE”úÊ$•²B³%Ö ÕîWìhw‰µ7ÞxÝøêºÄÖUåkK0žc(ÖW'ñ¨’Z-º“³I‰ûsþì.º¶ãYt[•ù…6¼ÇE·ý’ î2¤嫯ŒÒQ)+Ä–<2,ÃOV[µjUÛÛ0­Y³ú²s¬^½Êö9)«° ÚŽÛ0ù(AeHÊU_™…£JVh6éºI“&RߟN7æ5ø‚ßé´1oÓ¦M¹1¯ßÔU†¡\õ•Y6ªd…S§NZFdI2vîß¿ÏÑüÀ¶mÛÚZ7Ÿqz^”EÆ®â*UªD-wvv6E赸t’!E(O}U Yáîݹ¦ûÖ=÷ÜsRÝ“³fÍ5kÖ´õLA½222ÄÙ³glŸŸÅ1f1) Ê‚2É£qãÆšÆdϞݡÂÒE†¡<õUA2ªd…©©©Qˈd(ã¶m[- Ñ ñ¼ãœ9s†­M{ /Ô½}û6)bU§N¨åD[{]ž%¨— )B9ê«Ò`„m¶Â ˜={¶oe;~üC‘™9ÐÖ4‡µk×k×®‰ûÚ8ÎåD¾(+ÊìW¼fÏ~Ù´Œ&L ý”ê2¤娯J“ÖU6–#+_¾¼éwòÀýž–éܹ³bÊ”)âꫯv4»G`/ÂD•çr²h7@™QvÔÁ˘¡ÌÊU©R%£­)B Ĥ² )Bÿë«ââÖ*ˆ»ÿþ–ßI/Î`ç,ýÖ¸qcGòÁCÞÍwuè*Å5œ” uÀRf^ìf¶±*Ï€|¹·B” ^2¤ý¯¯ŠÛ© ï½{÷˜®D‘[Ý~ØísbÙU‹KïÚµÓõíܹC´nÝÚqùP'L·pkG ´‰Õ¢h»}ûöR„²‰HER„þÖWÕ pU¸ÙhÃÂ`Õ’D]sÕª•¢o߇cZƒY†îhTh¼àZÆ sôβ0<ÒטÀŸ¨ò¼ûîz[×EÛúu_…(A½dHú[_³A•$Ž.¼-Rm}'ûôéÓïͰØ÷“O>)êׯóbØ:t;vl÷-V¸vzzzÌåGÝÄ"–w‰X!§W¯ž¶®Õ²eK_7Q‚zÉ"ô¯¾*gƒ*‰<7w—íyz;à>yò‹bãÆ "/ïqž'Žsׯ_'¦L™, d¼3«^½z\»A`{%ÈC–6EYâÝò 1ÁJ0ˆb…˜!vˆá/ƒ™Yø‹/¾`ÄÚîÇÈøàƒÒf9VÙó<à[ÜÐf¡Â2TI‚að²Á e…ÌáÇü0%K–}û>,òòò¤ʈ²¢Ì~Æ m¶~ý:ŠPEª&AŠ0˜Ù`P²Â£GˆzõêIsïÕ¨QC¼ðÂ$)GI¢L(Ê(K¼0mH*$C%H3 JVø‡?<"å=˜’’"V¯^%MœP”IÆXõë÷(E¨Š U• EÜlP÷¬CüK”(!í}xÅWˆûï¿_|øá1ßb„k£ (‹¬qBnÙ²™"”]†*K" n6¨{VØ­[7%îÇ_ÿú×bíÚ5žÇgÍšÕÆµUˆÑïÿ{ŠPfª.AŠ0ØÙ ®Y!–ùò{°‡ÓÁ4ƒ?#Ξ=ãzlp \Kµø:t"”Q†:H" v6¨kV˜•5NÉ{³eË–bûöm®ÅçÆ5TŒMVVE(› u‘ EÈlPǬ0--MÙû³R¥JbΜ7œçV5.hSŠP"ê$AŠÙ nYáñãŠR¥J)}/^ÜØ­!Q1Án8§Ê1A›¢m)B d¨›)Bfƒºe…óçÏÓæ^íܹ“8qâx̱À±8‡.ñðóþÔN„±ÊPG R„ÌuË ±=’N÷ëõ×_/rsw9ŽŽÁ±:ÅmKú(C]%H2Ô-+ìÞ½»v÷,öùs2Ÿ­U«–vq@ÛR„>ÉPg R„ÌuË ÝÜfÉOÊ—/oët ã³:ÆmKú CÝ%H2Ô-+Te’x,”.]Z¼öÚ«QëŽßá3ºÖ¿aÆ¡×2 ‚)Bfƒºe…UªTÑúþÅäòiÓ²/«wvv¶R“äc¡jÕª¡—2 Š)Bfƒºe…^m ë÷:¥ãÇ¿Pgü,óz¡‰Üð˜"ôH†A’ EÈlP·¬°X±b¸QO,•‚RgÈž"¤)ŠÐlPå¬"¤)BvR„š‰ÐlPå¬]£ì¥9X†"ÔH„~fƒªf…,ÃÁ2!§OP„‰ÐÏlPÕ¬Ó'8}‚"ä„zŠPÊ ª˜rB='ÔS„\b"ÔD„2dƒ*f…\bK¬Q„\t›"Ô@„2eƒªe…\t›‹nS„܆‰"Ô@„2eƒªe… Ìç6L܆‰"䯼¡Ê"”1T)+䯼znÌ‹A@ܘW ê(CŠÙ nYaZZš²÷g¥J•Äœ9o&<&8'έj\Ц¾>')A½eH2Ô-+Ìʧä½Ù²eK±}û6×â‚sã*Ʀð¡$ÔI†!³Aݲƒ(5¹eÅRigÏžq=6¸®¥R|ÐÕ}èÐAŠPF ê"CŠÙ ŽYa·nÝ”ˆ%X»vçñY³fµ2‹ø9mByz!AdH2Ô1+ܼ9G”(QBêõBï¿ÿ~ñá‡Ç|‹®2ȼN)ÚpË–Í¡ìT]†!³A]³ÂGýƒ”±KIIq4AÞmP”IÆXõë×OŽç$%¨· )Bfƒºf…GÉÉÉÒĬFâ…&‰sçÎJ+” eCe‰WýúÉFR„ IPUR„ÌuÎ ×­û»([¶¬ïƒaúö}XäååI/”eõ{0 Úlýúuò<')A½eH2Ô}^áܹoù"C\óÁ;vlW®§e~à|‹Û¼ysåzNR‚zË"d6„5H-Z(ªU«æÙ²bß¾½ÊO¯B àÙ†Çh#´•tÏIJPoR„̃²3²7·ijÖ¬™9r¤8|8_»5‰óó󌺡ŽnÅïÖ[o;wîó9I ê-CŠÙ`Ðv±ùåY¢I“& ©;ãà;ž““£ý&ÞPWÔ9Q‘ÐþóŸå~NR‚zË"d6´]ì#£$/^$úôé-êÖ­k»®W]u•¸óÎvÆ–@2 æðs0bÑ®];‘””d;ŽˆyŸ>}Œ6q­"TI‚²Ë"d6ĬðRöìÙmlá4yò‹bذabÈÁcÇŽ3gÎK—.ì¼ø¬@Œ+Ä ±‹Ä1ElqŸ ÖÊM3£õ–!EÈl0¨Y!!JŠPe Ê*CŠÙ ³BB¡”Q†!³Af…„( B$(› )BfƒÌ ‘\„:JP&R„Ì™"±u– ,2¤™ 2+$DRA‚2È"d6Ȭ ÷#$„B(BB!„"$„B(BB!„"$„B(BB!„"$„B(BB!„"$„B(BB!„"$„B(BB!„"$„B(BB!„"$„B(BB!!ƒ@!„"$„B(BB!„"$„B(BB!„"$„B(BB!„"$„B(BB!„"$„B(Âx9ôˆøºÿ@:{çO¶m \œQg~± !Ò‹ðˬqB„BuöZ‚?Ö®¸8£Î”!!DzþШQàШ3%HÆÝ¶99ѳáðïøP#D~¶ha`Ш;%HÆÃ·wßµÎøj„( Âoï¹'°gÔÝíø~5ø™ÀK0Â×?®Õ—õï½+ÄWD¯søwø l„H,Âw犟K– ìƒuG (BŠ0ÑÙ ³BBá?ß|#ðgÄ€"¤ž 2+$D®Ñ/‡µõû$ÌŸá»#GÃu÷³kôg…bj—D„v²Af…„¨4}¦ 3Ä$'S" Z‰pœñtÊ ˆÐv6ȬðbNŸŸ.[*¾6L|Û±£ø>%EüT£†ø¹R¥_þ0,UJüþùǺuÅw­[‹oºt1>ûÙ¼¹â|~ã™÷Žb‚Ø FßµjeÄ ±C X†FlcÄŸEìÑ¡æ2”M‚¡ž"t’ 2+<'>]±\|Ó³‡ø©r娻֋ß7kfLKùtåŠàÅ0\gÔýûë®3bkªRE|Ó»—Ñ&¡†2”Q‚¡~"tœ 8+ütÉñ]Zš;Óq’“Å×™µž«iÌQ ×uu#†ßµióK–Hê!CY%Hê'ÂX²Á e…èºC(Šód2Å/žŸ(Ο:©~ìÂu@]P'O±…ÿ@C[?œOª,C™%Hê%B«lð­‚œþcãñcýdmHJ_Ž!Î;ªžÃeFÙJªåOìÂm†¶£”¡ì¤õ¡Y6øS˜&üЬ]¡?—/ïû4ŸªV_=õ”øøÐAéc†2¢¬xwçû¼ê ħK—P„*ÉP R„úˆÐN6‰A³B ¾ø¹bE¹̨TI|9|¸œ#%ÃeBÙ"#f¥‰Y¸ eH#Ý~„2ÊP R„úˆÐN6‰AвÂsw‰ŸjÖ´ý°ý¼àÞï¦~˜êq+¦V˜¦a 38ÌÞ0çã]`¿AñÙüyÒÄ eA™â©ÓGaö…y&̃1«UCIJfAl{„_sÛu¸-Ѧ¡Ä2TI‚¡"t’ .+žrñA^˜âaºH×ÑèÒðƒþóY3]‹Îý“ÃÁ0¨Cׂ:¹7´ÍiIÊ)Ñâ¡ U– E¨¶ãÉuÏ ÏçåYN•¨îñ½‡÷f…9áôÝaçN PŽs}Ûé^Ge8QPöbǬ†Q¤hkŠÐGª.AŠPmÆ“ êž~‘•eúìéã=ˆ®Øa¾q2¡¼vmñéÚ5ñO# Ÿç²{]”q¸‹ÝÇvèiQÆ/&L ý’¡¤Õa"²A³ÂïS£Ý"ɽX/ÌÛÒ|>sFì]¡ác.[ÖöõP¶º’Äê³%ìÂmMú C]$Hª+ÂDdƒºf…ïÎ5]Gt€d÷䜳+Äp½¾ÎÈp6ª4üÙ¯ŸÈ°½¶ê¹‚A>2Åh ELÐæ¡‡2ÔI‚¡š"Ld6¨cVøùÔ©¦ßÍ’Þ—x¶ØAvø¯víÄù#‡­ß†?ƒÏÚ=²ÈŸRV‹ „Ûœ"ôH†ºI"TS„‰ÌuÌ ¿éÚ5j=J~"ûÚîŠ4‰O>x?úÔˆðïð;çúZÂ,ðR曽ËìÖ"ôB†:J"TO„ndƒºe…?4nµ*pb…•£v§XT«Vä ü7üÎÎ9Ž\Sö¸ÉPe R„êˆÐ‹lP‡¬ðóiÙQ˾@áû[íO€÷œKÕ8˜Í»ü|ÆtŠÐª.AŠPz‘ êš­(³Jñ{·b˜#qH0?LÅc°Êl…™pÛS„ËP R„jˆÐËlPõ¬ð«g‡D-÷x îßÒW£)¼JL) ê?Ál;­¡ÏR„^ÊP R„jˆÐËlPõ¬Ðì~~E“{;?¼æ@‚¯z´[„¼b&ÂpÛS„!E¨¡ýÈUÎ ƒp?Cj¯;áë‰pEÈ®Q>8‚'B?²A•³Â t.Š¡ktaÁ±ì¥9X†"TJ„~fƒªf…fƒeÖ*~ïV³3ŽÁ28¶’â1x‡ƒe8}‚" –ýÌUÍ u>ñïœ>a=}bú4Šê)BD(C6¨bVøÙ‚ù¦«©pBý/çú¢±ø‘ê¹ÄEÊ ª˜š-±ö©‚÷ë'K¬½ñº6ðÕu‰µÏ¹Äݦƒ!B™²Aå²B‹E·*rŸ–r²èv… q-º­ÊüÂÆ\t›Û0Q„Á¡LÙ ŠY!¶ä‰Vή Ü£¿Fvãd¦5«/߆iõ*ñSÕª¶»JU؆©+·aâÆ¼a0D(c6¨ZVøM—.QË™+ùýéxcÞ÷·Dï&ÿN§yw„¸1¯ïÔU†¡\"”1T-+ü|êÔèï‘””ð¾¬áp~à¿Ú¶ç¶Œ>ó¯vílŸwqAYdì*þ‡ÙˆÑìlŠÐ+ ê(CŠPÊœ ª”~¼;WˆbÅ¢–³¯d÷ä}aÎÙ•`¸^_gdˆÎž±“ðgqŒYL s® L2Åè1‹˜|¼g7Eè¥u“!E(eÎUË ¿OMZÆ#’Ü‹u. Ñ ñl5ôù̶6í-¼PwIbuÔ¤œhk¯ï¯%¨— )B9D¨B6¨RVh¶Â ¸×Çø• 3ïµHðÇڵŧk×Äœç²{Ýo ÊZÖÇxu²(ã&P„~IPR„rˆP…lP¥¬ð|^žø¹|yÓïduãV,L¯0ÇN€ÿö¾ÎâüáüÄÅ&|®o;Ýë¨ Ç Ê^Ìã˜U·Ê’+U2Úš"ôQ‚:È"ô_„*eƒ*e…_÷ïoùôbv~ø}˜ÝøSø!ÿù¬™î *š9ø†“2¡Ý<ÚÍ¢”Ñ®øro…(A½dHú/B•²A•²Â÷î?W¬hú}ü§‹Ý~¥ æÄ²«üwmÚˆOvít%ž;Äw­[;.ß‘‚é¥]ì>þÂF6øñ¾½¡,TY†¡¿"T1T)+ürÜX[ßÉÆ ŒKj˜b\ƒY¾>ÜÙ¨Ðx _ëËaÃl-ÍV“ÂÜÀø]k÷9n[¿î«%¨— )BE¨b6¨ÔÒ3§Å÷-Rm}'§Åø@Ç{³Û s(ŽÅ°¿íÐA|²c»ë´†¯ýmzzÌå?TƒÛb|—˜f†ÝŒ¹eK£m)B %¨¢ )BÿD¨r6¨Ô¼ÂÜ]â§š5íÐ,x ÷ óaªÔµL˜¤0MÃô3¸àÙù8wƒø¡Ac× ™vð@™â©Óù‚•`ĪiAìÊIJJA~A¬vòî4Ü–˜+êgŒB” ^2¤ý¡ÊÙ jó ?]±Üò}¡×à×—#FxºX´“ÅËQ¶Ÿ¦q=fá6ütå ßã¢õ’!EèuÈU[ƒôÓ¥KlïÊà&?U©"¾ÊÌ:(ýT4”eE™¥`¸ eˆKˆÔK†¡?"Ô!TqgŠlÜ ~¬Ÿì“jaÎ;ªÜzÍç1ÊŽ:ø»ê×ÿØ´Qšx„(A½dHz/B²Aw±?ŸŸ'¾éÙÃöÚ›ñò}óæâ‹‰ÅùS'•ßÔüüÉF]¾oÖÌ †ï´U"P^„*JPvR„Þ‹P§lPŬ°pWéwii®<ÀLN_gŸlÎQ^~QG™æäuD]݈!æR~ºl©”uQ‚zÉ"ôV„:fƒ*f…—¤ù¦w¯øÞƒ/nd~XÍF†ÁžÇ0\gÔ1@,bî>®ZU|Ó§·Ñ&2×7D ê%CŠÐ[ê˜ ªœ^:RòÓåËŒÉåßvì(¾OI1†êG–!û¹tiãgd@Xå›®]Ï~6o®t]w¾vŸ†c˜ 6ˆbõc½zFìÃÈòqˆ-bŒX㳆üdA+ƒíJs²áG‰dh&B¡PLí"|¡U6(4¯ÌY!!ÒŠðŸo¾!Õ?@ üap[„fÙ`P>+$D6bõ€ŸK– ìCuw{ŠÐb´ÝÏåÊ>ƈbÁ‡)¡ü}Ï=Áýë9\w¿»F)ÂÆzÈàÀÇ1àƒ”P„N×½[´0° ÔÝõ!ÐÛ¶:Ú±ZWÄÂÕxŸ:)~hØ0°1FÝ?Ò`.!¾Œý¡Q£à=4Âuöl>PÀeè‰#ÃÌ/öl"·T„댺ó!J(ÂXGŽf ܃uötrl@eè¥#|Ó­[àâŒ:óJ(Â8׹û… :{¾RDXA‹³×4<¸8£Î|€ŠB¡ !„ŠB¡ !„ŠB¡ !„uøÿ#p8±?E?~IEND®B`‚././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/guide/imports.rst0000664000000000000000000000212615074674453016623 0ustar00rootrootImports ======= The toplevel ``gi`` package allows you to import the different libraries namespaces and ensure specific versions of them. The next code line will import the ``GTK`` and ``GLib`` libraries from the ``gi.repository`` module. ``gi.repository`` holds the libraries bindings. .. code:: python from gi.repository import Gtk, GLib If you want to ensure a specific version of a library you can use :func:`gi.require_version`. .. code:: python import gi gi.require_version('Gtk', '4.0') gi.require_version('GLib', '2.0') from gi.repository import Gtk, GLib To avoid `PEP8/E402 `_ you can use a try block. .. code:: python import sys import gi try: gi.require_version('Gtk', '4.0') gi.require_version('Adw', '1') from gi.repository import Adw, Gtk except ImportError or ValueError as exc: print('Error: Dependencies not met.', exc) sys.exit(1) .. seealso:: For more detailed information of the methods provided by the ``gi`` module checkout :ref:`guide-api`. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/guide/index.rst0000664000000000000000000000037215074674453016236 0ustar00rootroot========== User Guide ========== .. toctree:: :titlesonly: :maxdepth: 1 imports api/index cairo_integration gtk_template threading debug_profile deploy testing porting sysdeps flatpaking faq ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/guide/porting.rst0000664000000000000000000000740115074674453016611 0ustar00rootroot============================ Porting from Static Bindings ============================ Before PyGObject 3, bindings where not generated automatically through gobject introspection and where provided as separate Python libraries like pygobject, pygtk, pygst etc. We call them static bindings. If your code contains imports like ``import gtk``, ``import gst``, ``import glib`` or ``import gobject`` you are using the old bindings and you should upgrade. Note that using old and new bindings in the same process is not supported, you have to switch everything at once. Static Bindings Library Differences ----------------------------------- **pygtk** supported GTK 2.0 and Python 2 only. PyGObject supports GTK >=3.0 and Python 2/3. If you port away from pygtk you also have to move to GTK 3.0 at the same time. **pygtkcompat** described below can help you with that transition. **pygst** supports GStreamer 0.10 and Python 2 only. Like with GTK you have to move to PyGObject and GStreamer 1.0 at the same time. **pygobject 2** supports glib 2.0 and Python 2. The new bindings also support glib 2.0 and Python 2/3. .. note:: Python 2 is no longer supported since PyGObject 3.38.0. General Porting Tips -------------------- PyGObject contains a shell script which can help you with the many naming differences between static and dynamic bindings: https://gitlab.gnome.org/GNOME/pygobject/raw/master/tools/pygi-convert.sh :: ./pygi-convert.sh mymodule.py It just does basic text replacement. It reduces the amount of naming changes you have to make in the beginning, but nothing more. 1) Run on a Python module 2) Check/Verify the changes made (e.g. using ``git diff``) 3) Finish porting the module by hand 4) Continue to the next module... Porting Tips for GTK -------------------- PyGObject does not support GTK 2.0. In order to use PyGObject, you'll need to port your code to GTK 3.0 right away. For some general advice regarding the migration from GTK 2.0 to 3.0 see the `offical migration guide `__. If you need to know how a C symbol is exposed in Python have a look at the `symbol mapping listing `__. Using the pygtkcompat Compatibility Layer ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ .. note The pygtkcompat module is deprecated. If your code is dependent on pygtkcompat, you have two options: 1. Update your code to use the GTK interface directly 2. Copy the bits you need into your own application PyGObject ships a compatibility layer for pygtk which partially emulates the old interfaces: :: from gi import pygtkcompat pygtkcompat.enable() pygtkcompat.enable_gtk(version='3.0') import gtk ``enable()`` has to be called once before the first ``gtk`` import. Note that pygtkcompat is just for helping you through the transition by allowing you to port one module at a time. Only a limited subset of the interfaces are emulated correctly and you should try to get rid of it in the end. Default Encoding Changes ^^^^^^^^^^^^^^^^^^^^^^^^ Importing ``gtk`` had the side effect of changing the default Python encoding from ASCII to UTF-8 (check ``sys.getdefaultencoding()``) and that no longer happens with PyGObject. Since text with pygtk is returned as utf-8 encoded str, your code is likely depending auto-decoding in many places and you can change it manually by doing: :: # Python 2 only import sys reload(sys) sys.setdefaultencoding("utf-8") # see if auto decoding works: assert '\xc3\xb6' + u'' == u'\xf6' While this is not officially supported by Python I don't know of any downsides. Once you are sure that you explicitly decode in all places or you move to Python 3 where things are unicode by default you can remove this again. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/guide/sysdeps.rst0000664000000000000000000000130715074674453016620 0ustar00rootrootSystem Dependencies =================== PyGObject not only depends on packages available from PyPI, but also requires certain system dependencies to be installed. Because their version isn't taken into account by pip's dependency resolver, you may need to restrict the version of PyGObject itself for the installation to succeed. This lists the minimum version of the system dependencies over time. 3.46.0+: * glib: >= 2.64.0 * gobject-introspection: >= 1.64.0 * libffi: >= 3.0 Example distributions: Ubuntu 20.04, Debian Bullseye, or newer 3.40.0 - 3.44.x: * glib: >= 2.56.0 * gobject-introspection: >= 1.56.0 * libffi: >= 3.0 Example distributions: Ubuntu 18.04, or newer ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/guide/testing.rst0000664000000000000000000000067515074674453016612 0ustar00rootroot.. include:: ../icons.rst ================================== Testing and Continuous Integration ================================== To get automated tests of GTK code running on a headless server use Mutter. It allows running your app on Wayland display server without real display hardware. :: export XDG_RUNTIME_DIR=/tmp eval $(dbus-launch --auto-syntax) mutter --wayland --no-x11 --sm-disable --headless -- python my_script.py ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/guide/threading.rst0000664000000000000000000002507615074674453017104 0ustar00rootroot===================== Threads & Concurrency ===================== Operations which could potentially block should not be executed in the main loop. The main loop is in charge of input processing and drawing and blocking it results in the user interface freezing. For the user this means not getting any feedback and not being able to pause or abort the operation which causes the problem. Such an operation might be: * Loading external resources like an image file on the web * Searching the local file system * Writing, reading and copying files * Calculations where the runtime depends on some external factor The following examples show * how Python threads, running in parallel to GTK, can interact with the UI * how to use and control asynchronous I/O operations in glib Threads ------- The first example uses a Python thread to execute code in the background while still showing feedback on the progress in a window. .. code:: python import threading import time import gi gi.require_version('Gtk', '4.0') from gi.repository import GLib, Gtk, GObject class Application(Gtk.Application): def do_activate(self): window = Gtk.ApplicationWindow(application=self) self.progress = Gtk.ProgressBar(show_text=True) window.set_child(self.progress) window.present() thread = threading.Thread(target=self.example_target) thread.daemon = True thread.start() def update_progress(self, i): self.progress.pulse() self.progress.set_text(str(i)) return False def example_target(self): for i in range(50): GLib.idle_add(self.update_progress, i) time.sleep(0.2) app = Application() app.run() The example shows a simple window containing a progress bar. After everything is set up it constructs a Python thread, passes it a function to execute, starts the thread and the GTK main loop. After the main loop is started it is possible to see the window and interact with it. In the background ``example_target()`` gets executed and calls :func:`GLib.idle_add` and :func:`time.sleep` in a loop. In this example :func:`time.sleep` represents the blocking operation. :func:`GLib.idle_add` takes the ``update_progress()`` function and arguments that will get passed to the function and asks the main loop to schedule its execution in the main thread. This is needed because GTK isn't thread safe; only one thread, the main thread, is allowed to call GTK code at all times. Threads: FAQ ------------ * I'm porting code from pygtk (GTK 2) to PyGObject (GTK 3). Has anything changed regarding threads? Short answer: No. Long answer: ``gtk.gdk.threads_init()``, ``gtk.gdk.threads_enter()`` and ``gtk.gdk.threads_leave()`` are now :func:`Gdk.threads_init`, :func:`Gdk.threads_enter` and :func:`Gdk.threads_leave`. ``gobject.threads_init()`` can be removed. * I'm using :func:`Gdk.threads_init` and want to get rid of it. What do I need to do? * Remove any :func:`Gdk.threads_init()`, :func:`Gdk.threads_enter` and :func:`Gdk.threads_leave` calls. In case they get executed in a thread, move the GTK code into its own function and schedule it using :func:`GLib.idle_add`. Be aware that the newly created function will be executed some time later, so other stuff can happen in between. * Replace any call to ``Gdk.threads_add_*()`` with their GLib counterpart. For example :func:`GLib.idle_add` instead of :func:`Gdk.threads_add_idle`. * What about signals and threads? Signals get executed in the context they are emitted from. In which context the object is created or where ``connect()`` is called from doesn't matter. In GStreamer, for example, some signals can be called from a different thread, see the respective signal documentation for when this is the case. In case you connect to such a signal you have to make sure to not call any GTK code or use :func:`GLib.idle_add` accordingly. * What if I need to call GTK code in signal handlers emitted from a thread? In case you have a signal that is emitted from another thread and you need to call GTK code during and not after signal handling, you can push the operation with an :class:`threading.Event` object to the main loop and wait in the signal handler until the operation gets scheduled and the result is available. Be aware that if the signal is emitted from the main loop this will deadlock. See the following example .. code:: python # [...] toggle_button = Gtk.ToggleButton() def signal_handler_in_thread(): def function_calling_gtk(event, result): result.append(toggle_button.get_active()) event.set() event = threading.Event() result = [] GLib.idle_add(function_calling_gtk, event, result) event.wait() toggle_button_is_active = result[0] print(toggle_button_is_active) # [...] * What about the Python `GIL `__ ? Similar to I/O operations in Python, all PyGObject calls release the GIL during their execution and other Python threads can be executed during that time. Asynchronous Operations ----------------------- In addition to functions for blocking I/O glib also provides corresponding asynchronous versions, usually with the same name plus a ``_async`` suffix. These functions do the same operation as the synchronous ones but don't block during their execution. Instead of blocking they execute the operation in the background and call a callback once the operation is finished or got canceled. The following example shows how to download a web page and display the source in a text field. In addition it's possible to abort the running operation. .. code:: python import time import gi gi.require_version('Gtk', '4.0') from gi.repository import Gio, GLib, Gtk class DownloadWindow(Gtk.ApplicationWindow): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs, default_width=500, default_height=400, title="Async I/O Example") self.cancellable = Gio.Cancellable() self.cancel_button = Gtk.Button(label="Cancel") self.cancel_button.connect("clicked", self.on_cancel_clicked) self.cancel_button.set_sensitive(False) self.start_button = Gtk.Button(label="Load") self.start_button.connect("clicked", self.on_start_clicked) textview = Gtk.TextView(vexpand=True) self.textbuffer = textview.get_buffer() scrolled = Gtk.ScrolledWindow() scrolled.set_child(textview) box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6, margin_start=12, margin_end=12, margin_top=12, margin_bottom=12) box.append(self.start_button) box.append(self.cancel_button) box.append(scrolled) self.set_child(box) def append_text(self, text): iter_ = self.textbuffer.get_end_iter() self.textbuffer.insert(iter_, f"[{time.time()}] {text}\n") def on_start_clicked(self, button): button.set_sensitive(False) self.cancel_button.set_sensitive(True) self.append_text("Start clicked...") file_ = Gio.File.new_for_uri( "http://python-gtk-3-tutorial.readthedocs.org/") file_.load_contents_async( self.cancellable, self.on_ready_callback, None) def on_cancel_clicked(self, button): self.append_text("Cancel clicked...") self.cancellable.cancel() def on_ready_callback(self, source_object, result, user_data): try: succes, content, etag = source_object.load_contents_finish(result) except GLib.GError as e: self.append_text(f"Error: {e.message}") else: content_text = content[:100].decode("utf-8") self.append_text(f"Got content: {content_text}...") finally: self.cancellable.reset() self.cancel_button.set_sensitive(False) self.start_button.set_sensitive(True) class Application(Gtk.Application): def do_activate(self): window = DownloadWindow(application=self) window.present() app = Application() app.run() The example uses the asynchronous version of :meth:`Gio.File.load_contents` to load the content of an URI pointing to a web page, but first we look at the simpler blocking alternative: We create a :class:`Gio.File` instance for our URI and call :meth:`Gio.File.load_contents`, which, if it doesn't raise an error, returns the content of the web page we wanted. .. code:: python file = Gio.File.new_for_uri("https://developer.gnome.org/documentation/tutorials/beginners.html") try: status, contents, etag_out = file.load_contents(None) except GLib.GError: print("Error!") else: print(contents) In the asynchronous variant we need two more things: * A :class:`Gio.Cancellable`, which we can use during the operation to abort or cancel it. * And a :func:`Gio.AsyncReadyCallback` callback function, which gets called once the operation is finished and we can collect the result. The window contains two buttons for which we register ``clicked`` signal handlers: * The ``on_start_clicked()`` signal handler calls :meth:`Gio.File.load_contents_async` with a :class:`Gio.Cancellable` and ``on_ready_callback()`` as :func:`Gio.AsyncReadyCallback`. * The ``on_cancel_clicked()`` signal handler calls :meth:`Gio.Cancellable.cancel` to cancel the running operation. Once the operation is finished, either because the result is available, an error occurred or the operation was canceled, ``on_ready_callback()`` will be called with the :class:`Gio.File` instance and a :class:`Gio.AsyncResult` instance which holds the result. To get the result we now have to call :meth:`Gio.File.load_contents_finish` which returns the same things as :meth:`Gio.File.load_contents` except in this case the result is already there and it will return immediately without blocking. After all this is done we call :meth:`Gio.Cancellable.reset` so the :class:`Gio.Cancellable` can be re-used for new operations and we can click the "Load" button again. This works since we made sure that only one operation can be active at any time by deactivating the "Load" button using :meth:`Gtk.Widget.set_sensitive`. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/icons.rst0000664000000000000000000000144615074674453015150 0ustar00rootroot.. |python-logo| raw:: html .. |ubuntu-logo| raw:: html .. |debian-logo| raw:: html .. |fedora-logo| raw:: html .. |opensuse-logo| raw:: html .. |windows-logo| raw:: html .. |source-logo| raw:: html .. |arch-logo| raw:: html .. |macosx-logo| raw:: html .. |github-logo| raw:: html .. |git-logo| raw:: html .. |bug-logo| raw:: html .. |linux-logo| raw:: html ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/images/LICENSE0000664000000000000000000000030415074674453015545 0ustar00rootrootpygobject.svg and pygobject-small.svg are based on the GTK logo, created by Andreas Nilsson, licensed under CC BY-SA 3.0. For more info see https://commons.wikimedia.org/wiki/File:GTK%2B_logo.svg ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/images/favicon.ico0000664000000000000000000010327615074674453016675 0ustar00rootroot hV ˆ ¾  ¨F00 ¨%î@@ (B–D(  ¤¤‹ÞîîîîîîîîÞ‰‹ÿÿ***ÿdddÿhhhÿ222ÿÿÿÿÿÿÿŠÞÿÿ¹¹¹ÿÁÁÁÿ···ÿúúúÿ€€€ÿÿÿÿÿÿÝîÿÿÿÿÿjjjÿüüüÿÿÿÿÿÿîîÿÿÿWWWÿ€€€ÿ|||ÿÿÿÿÿ888ÿÿfffÿÿÿîîÿÿ   ÿïïïÿžžžÿÍÍÍÿÿÿÿÿ<<<ÿOOOÿÿÿÿÿÿÿîîÿÿþþþÿVVVÿÿ...ÿÿÿÿÿ<<<ÿOOOÿÿÿÿÿÿÿîîÿ222ÿÿÿÿÿ666ÿÿ...ÿÿÿÿÿ<<<ÿOOOÿÿÿÿÿÿÿîîÿÿùùùÿ‹‹‹ÿÿ===ÿÿÿÿÿ<<<ÿOOOÿÿÿÿÿÿÿîîÿÿtttÿýýýÿ÷÷÷ÿëëëÿòòòÿ<<<ÿOOOÿÿÿÿÿÿÿîîÿÿÿÿ---ÿ ÿÿÿÿ111ÿÿÿîÞÿÿÿÿÿÿÿÿ[[[ÿÿÿÿÿÿÿÝŒÿÿÿÿÿÿÿÿÿXXXÿÿÿ‹ŒÞîîîîîîîîÞ‹ÿÿ€€€€€€€€€€€€€€ÿÿ(0 vv3_ffffffffffff_2ºÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¸»ÿÿÿÿÿÿ+++ÿÿÿÿÿÿÿÿÿÿÿÿ¸4ÿÿÿÿ–––ÿòòòÿÿÿÿÿÿÿÿÿýýýÿÁÁÁÿ///ÿÿÿÿÿÿÿÿÿÿ2`ÿÿÿÿŠŠŠÿ¾¾¾ÿ‡‡‡ÿ‡‡‡ÿÈÈÈÿÿÿÿÿïïïÿ ÿÿÿÿÿÿÿÿÿ_fÿÿÿÿÿÿÿÿÿ¹¹¹ÿÿÿÿÿ‘‘‘ÿÿÿÿÿÿÿÿÿffÿÿÿÿÿÿÿÿÿ```ÿÿÿÿÿÉÉÉÿÿÿÿÿÿÿÿÿffÿÿÿÿÿ;;;ÿ¥¥¥ÿÉÉÉÿ¯¯¯ÿ™™™ÿÿÿÿÿØØØÿÿÿ£££ÿªªªÿÿÿÿÿffÿÿÿÿVVVÿüüüÿÿÿÿÿïïïÿðððÿÿÿÿÿÿÿÿÿØØØÿÿÿõõõÿÿÿÿÿÿÿÿÿffÿÿÿÿêêêÿÿÿÿÿvvvÿÿÿsssÿÿÿÿÿØØØÿÿÿõõõÿÿÿÿÿÿÿÿÿffÿÿÿ111ÿÿÿÿÿæææÿÿÿÿEEEÿÿÿÿÿØØØÿÿÿõõõÿÿÿÿÿÿÿÿÿffÿÿÿPPPÿÿÿÿÿËËËÿÿÿÿEEEÿÿÿÿÿØØØÿÿÿõõõÿÿÿÿÿÿÿÿÿffÿÿÿ:::ÿÿÿÿÿèèèÿÿÿÿEEEÿÿÿÿÿØØØÿÿÿõõõÿÿÿÿÿÿÿÿÿffÿÿÿÿøøøÿÿÿÿÿ}}}ÿÿÿhhhÿÿÿÿÿØØØÿÿÿõõõÿÿÿÿÿÿÿÿÿffÿÿÿÿ€€€ÿÿÿÿÿÿÿÿÿùùùÿóóóÿÿÿÿÿÿÿÿÿØØØÿÿÿõõõÿÿÿÿÿÿÿÿÿffÿÿÿÿÿ[[[ÿ´´´ÿÌÌÌÿ±±±ÿUUUÿ~~~ÿÿÿÿ£££ÿªªªÿÿÿÿÿffÿÿÿÿÿÿÿÿÿÿÿÿÿÿ+++ÿ777ÿÿÿÿÿf`ÿÿÿÿÿÿÿÿÿÿÿÿÿÿøøøÿþþþÿ666ÿÿÿÿ_4ÿÿÿÿÿÿÿÿÿÿÿÿÿÿéééÿöööÿ'''ÿÿÿÿ2½ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿº½ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ»5`ffffffffffff`4ÿÿÿðÀÀ€€€€€€€€€€€€€€€€ÀÀðÿÿÿ( @ HHm»ÙÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝØºl#ØÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÖ! ×ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÖmÿÿÿÿÿ...ÿ{{{ÿ¼¼¼ÿÖÖÖÿåååÿÔÔÔÿ¢¢¢ÿFFFÿÿÿÿÿÿÿÿÿÿÿÿÿÿk¼ÿÿÿÿÿ···ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¨¨¨ÿÿÿÿÿÿÿÿÿÿÿÿÿºÙÿÿÿÿÿXXXÿÍÍÍÿ………ÿ[[[ÿPPPÿxxxÿâââÿÿÿÿÿÿÿÿÿŠŠŠÿÿÿÿÿÿÿÿÿÿÿÿØÝÿÿÿÿÿÿÿÿÿÿÿÿëëëÿÿÿÿÿ÷÷÷ÿÿÿÿÿÿÿÿÿÿÿÿÝÝÿÿÿÿÿÿÿÿÿÿÿÿ”””ÿÿÿÿÿÿÿÿÿQQQÿÿÿÿÿÿÿÿÿÿÿÝÝÿÿÿÿÿÿÿÿÿ ÿÿÿqqqÿÿÿÿÿÿÿÿÿnnnÿÿÿÿÿÿÿÿÿÿÿÝÝÿÿÿÿÿÿÿ“““ÿëëëÿÿÿÿÿûûûÿÌÌÌÿ²²²ÿÿÿÿÿÿÿÿÿwwwÿÿÿˆˆˆÿÝÝÝÿÝÝÝÿÿÿÿÿÿÝÝÿÿÿÿÿÿÝÝÝÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿwwwÿÿÿœœœÿÿÿÿÿÿÿÿÿ$$$ÿÿÿÿÿÝÝÿÿÿÿÿ°°°ÿÿÿÿÿÿÿÿÿ¼¼¼ÿHHHÿ000ÿ___ÿ×××ÿÿÿÿÿÿÿÿÿwwwÿÿÿœœœÿÿÿÿÿÿÿÿÿ$$$ÿÿÿÿÿÝÝÿÿÿÿÿþþþÿÿÿÿÿØØØÿÿÿÿÿ\\\ÿÿÿÿÿÿÿÿÿwwwÿÿÿœœœÿÿÿÿÿÿÿÿÿ$$$ÿÿÿÿÿÝÝÿÿÿÿ[[[ÿÿÿÿÿÿÿÿÿÿÿÿÿÿ\\\ÿÿÿÿÿÿÿÿÿwwwÿÿÿœœœÿÿÿÿÿÿÿÿÿ$$$ÿÿÿÿÿÝÝÿÿÿÿqqqÿÿÿÿÿÿÿÿÿcccÿÿÿÿÿ\\\ÿÿÿÿÿÿÿÿÿwwwÿÿÿœœœÿÿÿÿÿÿÿÿÿ$$$ÿÿÿÿÿÝÝÿÿÿÿlllÿÿÿÿÿÿÿÿÿtttÿÿÿÿÿ\\\ÿÿÿÿÿÿÿÿÿwwwÿÿÿœœœÿÿÿÿÿÿÿÿÿ$$$ÿÿÿÿÿÝÝÿÿÿÿIIIÿÿÿÿÿÿÿÿÿ¹¹¹ÿÿÿÿÿ\\\ÿÿÿÿÿÿÿÿÿwwwÿÿÿœœœÿÿÿÿÿÿÿÿÿ$$$ÿÿÿÿÿÝÝÿÿÿÿ ÿóóóÿÿÿÿÿþþþÿlllÿÿÿ ÿ’’’ÿÿÿÿÿÿÿÿÿwwwÿÿÿœœœÿÿÿÿÿÿÿÿÿ$$$ÿÿÿÿÿÝÝÿÿÿÿÿyyyÿÿÿÿÿÿÿÿÿÿÿÿÿüüüÿäääÿüüüÿÿÿÿÿÿÿÿÿÿÿÿÿwwwÿÿÿœœœÿÿÿÿÿÿÿÿÿ$$$ÿÿÿÿÿÝÝÿÿÿÿÿÿ€€€ÿøøøÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¿¿¿ÿÍÍÍÿÿÿÿÿwwwÿÿÿœœœÿÿÿÿÿÿÿÿÿ$$$ÿÿÿÿÿÝÝÿÿÿÿÿÿÿÿQQQÿjjjÿbbbÿ...ÿÿÿ333ÿÿÿÿÿ333ÿ333ÿÿÿÿÿÿÝÝÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿhhhÿ<<<ÿÿÿÿÿÿÝÙÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ²²²ÿÿÿÿÿþþþÿ;;;ÿÿÿÿÿÙ¼ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÛÛÛÿÿÿÿÿÿÿÿÿcccÿÿÿÿÿºoÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿJJJÿØØØÿ¬¬¬ÿ ÿÿÿÿÿm ÚÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿØ$ÚÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿØ# o½ÙÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÝÙ¼n ÿÿÿÿÿÿÿÿðàÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀÀàðÿÿÿÿÿÿÿÿ(0` $ìì?Ž´ËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌË´>0ÇÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÅ/NõÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿôM1õÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿô/Åÿÿÿÿÿÿÿÿÿÿÿ222ÿIIIÿYYYÿNNNÿ999ÿ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÈ@ÿÿÿÿÿÿÿÿ///ÿŽŽŽÿÜÜÜÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùùùÿ»»»ÿJJJÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ>ÿÿÿÿÿÿÿÿ¬¬¬ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ²²²ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¶ÿÿÿÿÿÿÿÿLLLÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüüüÿóóóÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÀÀÀÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ´ÊÿÿÿÿÿÿÿÿÿÖÖÖÿ£££ÿYYYÿÿÿÿ ÿEEEÿ»»»ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ|||ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÊÌÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ©©©ÿÿÿÿÿÿÿÿÿÿÿÿÿîîîÿ ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÌÌÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿÿÿÿÿÿÿÿÿÿÿÿÿMMMÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÌÌÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿËËËÿÿÿÿÿÿÿÿÿÿÿÿÿ‰‰‰ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÌÌÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¢¢¢ÿÿÿÿÿÿÿÿÿÿÿÿÿ¡¡¡ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÌÌÿÿÿÿÿÿÿÿÿÿÿÿ+++ÿqqqÿÿ”””ÿwwwÿJJJÿÿ‘‘‘ÿÿÿÿÿÿÿÿÿÿÿÿÿ±±±ÿÿÿÿÿ???ÿDDDÿDDDÿDDDÿÿÿÿÿÿÿÿÿÌÌÿÿÿÿÿÿÿÿÿÿ...ÿÂÂÂÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿëëëÿÙÙÙÿÿÿÿÿÿÿÿÿÿÿÿÿ²²²ÿÿÿÿÿëëëÿÿÿÿÿÿÿÿÿÿÿÿÿ666ÿÿÿÿÿÿÿÿÌÌÿÿÿÿÿÿÿÿÿGGGÿôôôÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ²²²ÿÿÿÿÿëëëÿÿÿÿÿÿÿÿÿÿÿÿÿ666ÿÿÿÿÿÿÿÿÌÌÿÿÿÿÿÿÿÿ!!!ÿñññÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿèèèÿÀÀÀÿÂÂÂÿíííÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ²²²ÿÿÿÿÿëëëÿÿÿÿÿÿÿÿÿÿÿÿÿ666ÿÿÿÿÿÿÿÿÌÌÿÿÿÿÿÿÿÿ¬¬¬ÿÿÿÿÿÿÿÿÿÿÿÿÿöööÿ]]]ÿÿÿÿÿQQQÿàààÿÿÿÿÿÿÿÿÿÿÿÿÿ²²²ÿÿÿÿÿëëëÿÿÿÿÿÿÿÿÿÿÿÿÿ666ÿÿÿÿÿÿÿÿÌÌÿÿÿÿÿÿÿÿüüüÿÿÿÿÿÿÿÿÿÿÿÿÿ___ÿÿÿÿÿÿÿ‰‰‰ÿÿÿÿÿÿÿÿÿÿÿÿÿ²²²ÿÿÿÿÿëëëÿÿÿÿÿÿÿÿÿÿÿÿÿ666ÿÿÿÿÿÿÿÿÌÌÿÿÿÿÿÿÿ```ÿÿÿÿÿÿÿÿÿÿÿÿÿãããÿÿÿÿÿÿÿÿ‰‰‰ÿÿÿÿÿÿÿÿÿÿÿÿÿ²²²ÿÿÿÿÿëëëÿÿÿÿÿÿÿÿÿÿÿÿÿ666ÿÿÿÿÿÿÿÿÌÌÿÿÿÿÿÿÿ’’’ÿÿÿÿÿÿÿÿÿÿÿÿÿ¨¨¨ÿÿÿÿÿÿÿÿ‰‰‰ÿÿÿÿÿÿÿÿÿÿÿÿÿ²²²ÿÿÿÿÿëëëÿÿÿÿÿÿÿÿÿÿÿÿÿ666ÿÿÿÿÿÿÿÿÌÌÿÿÿÿÿÿÿ¦¦¦ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ‰‰‰ÿÿÿÿÿÿÿÿÿÿÿÿÿ²²²ÿÿÿÿÿëëëÿÿÿÿÿÿÿÿÿÿÿÿÿ666ÿÿÿÿÿÿÿÿÌÌÿÿÿÿÿÿÿ«««ÿÿÿÿÿÿÿÿÿÿÿÿÿœœœÿÿÿÿÿÿÿÿ‰‰‰ÿÿÿÿÿÿÿÿÿÿÿÿÿ²²²ÿÿÿÿÿëëëÿÿÿÿÿÿÿÿÿÿÿÿÿ666ÿÿÿÿÿÿÿÿÌÌÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ···ÿÿÿÿÿÿÿÿ‰‰‰ÿÿÿÿÿÿÿÿÿÿÿÿÿ²²²ÿÿÿÿÿëëëÿÿÿÿÿÿÿÿÿÿÿÿÿ666ÿÿÿÿÿÿÿÿÌÌÿÿÿÿÿÿÿyyyÿÿÿÿÿÿÿÿÿÿÿÿÿèèèÿÿÿÿÿÿÿÿ‰‰‰ÿÿÿÿÿÿÿÿÿÿÿÿÿ²²²ÿÿÿÿÿëëëÿÿÿÿÿÿÿÿÿÿÿÿÿ666ÿÿÿÿÿÿÿÿÌÌÿÿÿÿÿÿÿAAAÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿhhhÿÿÿÿÿÿÿ‰‰‰ÿÿÿÿÿÿÿÿÿÿÿÿÿ²²²ÿÿÿÿÿëëëÿÿÿÿÿÿÿÿÿÿÿÿÿ666ÿÿÿÿÿÿÿÿÌÌÿÿÿÿÿÿÿÿâââÿÿÿÿÿÿÿÿÿÿÿÿÿùùùÿpppÿ ÿÿÿÿFFFÿÑÑÑÿÿÿÿÿÿÿÿÿÿÿÿÿ²²²ÿÿÿÿÿëëëÿÿÿÿÿÿÿÿÿÿÿÿÿ666ÿÿÿÿÿÿÿÿÌÌÿÿÿÿÿÿÿÿaaaÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ÷÷÷ÿÕÕÕÿÕÕÕÿøøøÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ²²²ÿÿÿÿÿëëëÿÿÿÿÿÿÿÿÿÿÿÿÿ666ÿÿÿÿÿÿÿÿÌÌÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ²²²ÿÿÿÿÿëëëÿÿÿÿÿÿÿÿÿÿÿÿÿ666ÿÿÿÿÿÿÿÿÌÌÿÿÿÿÿÿÿÿÿÿqqqÿîîîÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿóóóÿ|||ÿÿÿÿÿÿÿÿÿÿ²²²ÿÿÿÿÿëëëÿÿÿÿÿÿÿÿÿÿÿÿÿ666ÿÿÿÿÿÿÿÿÌÌÿÿÿÿÿÿÿÿÿÿÿ ÿNNNÿ………ÿœœœÿ¢¢¢ÿŽŽŽÿZZZÿÿÿÿUUUÿUUUÿ;;;ÿÿÿÿÿ???ÿDDDÿDDDÿDDDÿÿÿÿÿÿÿÿÿÌÌÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÌÌÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ’’’ÿ£££ÿ>>>ÿÿÿÿÿÿÿÿÿÌÊÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿáááÿÿÿÿÿÿÿÿÿüüüÿ<<<ÿÿÿÿÿÿÿÿÊ·ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿSSSÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿµÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ@@@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ‰‰‰ÿÿÿÿÿÿÿÿAÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¥¥¥ÿÿÿÿÿÿÿÿÿÙÙÙÿÿÿÿÿÿÿÿÿ?Çÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ;;;ÿJJJÿ ÿÿÿÿÿÿÿÿÉ2öÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿõ0NöÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿõM3ÉÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÈ1AµËÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌÌ˵@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿþÿü?øððàààààààààààààààààààààààààààààààààðøü?þÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ(@€ @]ª»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ª]!¤ûÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿû£føÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ÷d‰ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ‡aÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿf"ùÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ÷ ¦ÿÿÿÿÿÿÿÿÿÿÿÿÿ000ÿlllÿ•••ÿ´´´ÿÉÉÉÿÎÎÎÿÇÇÇÿ´´´ÿžžžÿeeeÿ%%%ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ£ûÿÿÿÿÿÿÿÿÿÿ...ÿ‘‘‘ÿæææÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÇÇÇÿNNNÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿû_ÿÿÿÿÿÿÿÿÿÿÿŸŸŸÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ´´´ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ\‘ÿÿÿÿÿÿÿÿÿÿÿ@@@ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÛÛÛÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿªÿÿÿÿÿÿÿÿÿÿÿÿßßßÿÿÿÿÿÿÿÿÿÿÿÿÿçççÿÃÃÃÿ¦¦¦ÿ™™™ÿªªªÿÏÏÏÿüüüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¿¿¿ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¨»ÿÿÿÿÿÿÿÿÿÿÿÿÿÃÃÃÿwwwÿ///ÿÿÿÿÿÿÿÿŠŠŠÿüüüÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿhhhÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ»»ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿZZZÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿáááÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ»»ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ®®®ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿEEEÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ»»ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿIIIÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ‡‡‡ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ»»ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿûûûÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ½½½ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ»»ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÝÝÝÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÒÒÒÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ»»ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ$$$ÿÿÿÿÿÿÅÅÅÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿçççÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ»»ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ ÿfffÿ···ÿöööÿÿÿÿÿÿÿÿÿÿÿÿÿùùùÿÉÉÉÿ~~~ÿ!!!ÿ»»»ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿíííÿÿÿÿÿÿ***ÿ»»»ÿ»»»ÿ»»»ÿ»»»ÿ»»»ÿ555ÿÿÿÿÿÿÿÿÿÿÿ»»ÿÿÿÿÿÿÿÿÿÿÿÿÿÿSSSÿáááÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿýýýÿôôôÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿíííÿÿÿÿÿÿ:::ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿHHHÿÿÿÿÿÿÿÿÿÿÿ»»ÿÿÿÿÿÿÿÿÿÿÿÿÿwwwÿþþþÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿíííÿÿÿÿÿÿ:::ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿHHHÿÿÿÿÿÿÿÿÿÿÿ»»ÿÿÿÿÿÿÿÿÿÿÿÿiiiÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿíííÿÿÿÿÿÿ:::ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿHHHÿÿÿÿÿÿÿÿÿÿÿ»»ÿÿÿÿÿÿÿÿÿÿÿ'''ÿõõõÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿñññÿ™™™ÿ```ÿMMMÿ[[[ÿ‰‰‰ÿØØØÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿíííÿÿÿÿÿÿ:::ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿHHHÿÿÿÿÿÿÿÿÿÿÿ»»ÿÿÿÿÿÿÿÿÿÿÿ¥¥¥ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÂÂÂÿÿÿÿÿÿÿÿXXXÿíííÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿíííÿÿÿÿÿÿ:::ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿHHHÿÿÿÿÿÿÿÿÿÿÿ»»ÿÿÿÿÿÿÿÿÿÿÿúúúÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿßßßÿ ÿÿÿÿÿÿÿÿÿ¶¶¶ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿíííÿÿÿÿÿÿ:::ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿHHHÿÿÿÿÿÿÿÿÿÿÿ»»ÿÿÿÿÿÿÿÿÿÿbbbÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿaaaÿÿÿÿÿÿÿÿÿÿ¶¶¶ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿíííÿÿÿÿÿÿ:::ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿHHHÿÿÿÿÿÿÿÿÿÿÿ»»ÿÿÿÿÿÿÿÿÿÿŸŸŸÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüüüÿÿÿÿÿÿÿÿÿÿÿ¶¶¶ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿíííÿÿÿÿÿÿ:::ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿHHHÿÿÿÿÿÿÿÿÿÿÿ»»ÿÿÿÿÿÿÿÿÿÿÈÈÈÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ×××ÿÿÿÿÿÿÿÿÿÿÿ¶¶¶ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿíííÿÿÿÿÿÿ:::ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿHHHÿÿÿÿÿÿÿÿÿÿÿ»»ÿÿÿÿÿÿÿÿÿÿÛÛÛÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÂÂÂÿÿÿÿÿÿÿÿÿÿÿ¶¶¶ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿíííÿÿÿÿÿÿ:::ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿHHHÿÿÿÿÿÿÿÿÿÿÿ»»ÿÿÿÿÿÿÿÿÿÿèèèÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ½½½ÿÿÿÿÿÿÿÿÿÿÿ¶¶¶ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿíííÿÿÿÿÿÿ:::ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿHHHÿÿÿÿÿÿÿÿÿÿÿ»»ÿÿÿÿÿÿÿÿÿÿÝÝÝÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÊÊÊÿÿÿÿÿÿÿÿÿÿÿ¶¶¶ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿíííÿÿÿÿÿÿ:::ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿHHHÿÿÿÿÿÿÿÿÿÿÿ»»ÿÿÿÿÿÿÿÿÿÿÎÎÎÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿíííÿÿÿÿÿÿÿÿÿÿÿ¶¶¶ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿíííÿÿÿÿÿÿ:::ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿHHHÿÿÿÿÿÿÿÿÿÿÿ»»ÿÿÿÿÿÿÿÿÿÿ©©©ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ,,,ÿÿÿÿÿÿÿÿÿÿ¶¶¶ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿíííÿÿÿÿÿÿ:::ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿHHHÿÿÿÿÿÿÿÿÿÿÿ»»ÿÿÿÿÿÿÿÿÿÿvvvÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ’’’ÿÿÿÿÿÿÿÿÿÿ¶¶¶ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿíííÿÿÿÿÿÿ:::ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿHHHÿÿÿÿÿÿÿÿÿÿÿ»»ÿÿÿÿÿÿÿÿÿÿ...ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿûûûÿCCCÿÿÿÿÿÿÿÿÿ¶¶¶ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿíííÿÿÿÿÿÿ:::ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿHHHÿÿÿÿÿÿÿÿÿÿÿ»»ÿÿÿÿÿÿÿÿÿÿÿËËËÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿöööÿzzzÿÿÿÿÿÿ"""ÿ„„„ÿöööÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿíííÿÿÿÿÿÿ:::ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿHHHÿÿÿÿÿÿÿÿÿÿÿ»»ÿÿÿÿÿÿÿÿÿÿÿGGGÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿüüüÿÒÒÒÿ¾¾¾ÿÂÂÂÿâââÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿíííÿÿÿÿÿÿ:::ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿHHHÿÿÿÿÿÿÿÿÿÿÿ»»ÿÿÿÿÿÿÿÿÿÿÿÿšššÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿíííÿÿÿÿÿÿ:::ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿHHHÿÿÿÿÿÿÿÿÿÿÿ»»ÿÿÿÿÿÿÿÿÿÿÿÿÿ   ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿûûûÿâââÿÿÿÿÿÿÿÿÿÿÿÿÿíííÿÿÿÿÿÿ:::ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿHHHÿÿÿÿÿÿÿÿÿÿÿ»»ÿÿÿÿÿÿÿÿÿÿÿÿÿÿZZZÿáááÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÉÉÉÿ777ÿSSSÿÿÿÿÿÿÿÿÿÿÿÿÿíííÿÿÿÿÿÿ:::ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿHHHÿÿÿÿÿÿÿÿÿÿÿ»»ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿCCCÿŒŒŒÿ¶¶¶ÿËËËÿÝÝÝÿÏÏÏÿ¸¸¸ÿÿ777ÿÿÿÿfffÿfffÿfffÿ___ÿÿÿÿÿÿÿfffÿfffÿfffÿfffÿfffÿÿÿÿÿÿÿÿÿÿÿÿ»»ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ»»ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ»»ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ111ÿ¸¸¸ÿæææÿ¼¼¼ÿ777ÿÿÿÿÿÿÿÿÿÿÿÿ»»ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ+++ÿ÷÷÷ÿÿÿÿÿÿÿÿÿÿÿÿÿúúúÿ555ÿÿÿÿÿÿÿÿÿÿÿ»«ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ©©©ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¶¶¶ÿÿÿÿÿÿÿÿÿÿÿ©“ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÐÐÐÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÞÞÞÿÿÿÿÿÿÿÿÿÿÿ`ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿŸŸŸÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ¬¬¬ÿÿÿÿÿÿÿÿÿÿÿ]ûÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿìììÿÿÿÿÿÿÿÿÿÿÿÿÿñññÿ&&&ÿÿÿÿÿÿÿÿÿÿü§ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿšššÿÆÆÆÿžžžÿ!!!ÿÿÿÿÿÿÿÿÿÿÿ¥#ùÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿø!cÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿh‹ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ‰iùÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿùg#§üÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿü¥"_‘ª»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»»ª‘^ÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿàÿÿ€ÿÿÿþü?øøððððððððððððððððððððððððððððððððððððððððððøøü?þÿÿÿ€ÿÿàÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿÿ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/images/logo.svg0000664000000000000000000002064115074674453016227 0ustar00rootroot image/svg+xml gi ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/images/overview-dark.svg0000664000000000000000000002046315074674453020056 0ustar00rootroot Python PyGObject GIRepository GLib GObject libffi Gtk-4.0.typelib libgtk-4.so ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/images/overview.dia0000664000000000000000000000353515074674453017076 0ustar00rootroot‹í\ËnÛ8Ýç+ w›Ð"EQdݤ@˜n2è3]´EÛjeÉè$îb¾}(J®mYòCÔAé")¤\ÝCR¼ç¾üáãË"è=‰8ñ£ð¾Õï‰py~8»ïý÷Ï;ÚÿøpóÁóù{õ3‹ù¢§ž“ôê¾?—rù~0x~~Á:á2ŠAà¯@"ÿñ àe4è?Üôz»<.yz/¿Ë¥ŒýñJŠ^Èâ¾?æ“ï³8Z…^?³Êí&QŽ'Ü÷ßMóO;ìy:â}Égb þ½Ú¹¥>ŒÕs¾qÑñb%¾2‘ëåI…Ÿô÷ŽMn•(£pöðîQH)âwY±ò›[e…­’ ÏüðKµP5ŽÍÒÔ±-äÚ›v¹nüºpÁëÂů ç'£e˘ûòrEàa†*㕨“Lx ºØ±jÁúÞ§¾”щòOyœSìöψ»4zg±ïÞ=‹ /ÞZýïO:}%Ͼ'磗Ž^Iæ}Ý‘÷'?ñÇ(+½ÊÖܯÛq_ì:OloØã2o•‰È£ÂND4[ùžHNtæ}› OóÜlpªÝ‹v ›Æó“eÀ×Ç«P4ªðÅCé+ã‰ðºeÊ/ïdtW ‰&”v)“Žé=ŸS£P&Qªê(%z·ŒT´&í@žÛ³[‘ªQUq^ÒO[yÚËÉ&/I//?ß¹ÅUuž6W;Ý={qy7þGòÐã±×»ë}Š^ú[9®Ä¸ïÝ÷¿XûaPl<åLIƒPÖm˜ë($ä–jcÊŠQzØdU0ãq%NkÎñÉ%É¥ iˆ Ñ[¨nÔƒXŒ&Qêæ¶k¨¡tú;¬å&õ©z` %Ø¢Ôq`Í…?›Ëj0¦*¥ ¬Íáz`ã(öD<ÚÏ7%‡àôß6ã\†’ñ¨døv:v/AQbTŒ¾E{B[Špµ8Hð—xÎ:Ù(æž¿Jª_аµÿA'ð²›YÌW‘À׿Uü+*¢„`S€jhï`çZªÿºn‡ "Ya®;„€úZ ~X]ä…¼B›y¾J…RL+MxÅàZÓ{(ãõˆëô\t¿™™(“¸Ä‹ºF/¾ìCŠyª³lªU—aÏ®PØ¿×r…“AGTXÕp< e\z¿7UÛ`}ßäjÈÞKä:Õ9˜öógÿˆV±/â]Evyúo)Óãf ûÔYûvû*~è.ß×+¦á3Sq(5ì™… QþRKæqí^&¥k¤ïhXxÁ°VH[uuTö8œM½Ú²gêÁ Å9ëδj¬`i–£ˆÂ.…‚ÒêY6u)"•]íT$·.êUˆ„Æmw–Bm#>Œdø-%Ãç/šMŒjèZ5PÀpª±ˆÑ F3\­f°Ï0Ú€8ľuMvºœaTHV†ÒQàÚêšk#_ƒth¥ ÏQ°Ûý˜ £ÎU?žù±Ð¾£xm4DÇ]hßR€fŽQFE\­ŠÀUºäV/v*"­‚´†@饒꘠·¬!Zh@³DaCÛŠAý¥ð J!}½>i„‚ ×+œ6„ƒ®ž[ë^)à ‰n¤‚¾¶ûæ¥Bã&4ZÁh…¶µBd'^K.°ŒÈ,#Œ\ø¥rag ô£ªa‰d w58?·ðŽw@*$ËÖH"{˜î °Ò™ÖvhÝÍ©a8¡w°3þìz–nV Ô#×Ü4­Bn²,–§ì¬M­nÞáveÕ˜#ÇÑsõFb„º"œ'»šøëAž¤¢šˆÛãÉÁ;Ùü¥7WqœæP¶2Ò—{Û¿îiÁêgaþ,Ú–.*¨¦qN,ÀhTn·¨RIJYK—¨¡ RC7ÝCU?¿œM3•¬>™‘šâº É’©&Ô€d¬ýgí¶Iæ“ø¡FTCS^À Í‚ë<²QHéA.\¥†¶Ò2d˜Õ>–$~ŒNMUMm ¸¾ÌÔR£ÂŽšnªZ4­q¶(íÉ*8(Géß Éý†$gÕ 9{£Âà¯d9ööX.)ZÓ4‰£g{]Ûy»4g«zA÷ÍåUÝ754ghîÐê‚æNœÌµZXËB·Pýb]¯c9&Û3‹œôL>Äo{«YÙÕ+³zÕòêÕtꛕ«îW®TÜ;#׬[™u«ëÝæmÇfî©LMºüÞžÈÒ@#lh»Y§sŒÕ¾ÐFžw¦Yqn0ºáLÝðY~¿³R¯f§l÷ÂÆÀql˜²r6ÂhˆëÕ¨ ¡'ö µ'öΔdHîÐvÓ×`Ý·­"7¡™m0ª¡í½²Z8$‘Q ]+{»„±ùþ/£^K1d×úˆnö¾¢øáæF·¾c././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/images/overview.svg0000664000000000000000000002004015074674453017126 0ustar00rootroot Python PyGObject GIRepository GLib GObject libffi Gtk-4.0.typelib libgtk-4.so ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/images/pygobject-small.svg0000664000000000000000000002111115074674453020354 0ustar00rootroot image/svg+xml ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/images/pygobject.svg0000664000000000000000000003460315074674453017260 0ustar00rootroot image/svg+xml ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/images/start_linux.png0000664000000000000000000002324515074674453017633 0ustar00rootroot‰PNG  IHDR@“ÀØ­* pHYs  šœtIMEà 9)¿üÎäbKGDÿÿÿ ½§“&2IDATxÚíÝ œå7ðÿ ÷}ˆˆ*xFDEuÕhðŠG²¹³Ùd}“ÝMLÌÍfº9ÞMÞ$cŒÇz‹ÆDÄ/0àŠ(*÷} Ã9ýöSÚcÏ034§s|¿|Šê®ª®®zjªêWO=Ý]VUU¹\.Ö­[ .Ì­^½:6lØ›7oŽÚÒtAYYÙVÃZ·níÚµ‹®]»FŸ>}Ê:vìXcº²€R IÝk¯½–›2eJtïÞ=†šõ[µj¥d€&eË–-±råʘ>}zÖ?úè£càÀe)e]š …Ÿ_|1 ?^xaþE›cÓ¦MQД¤“*qÚ´i“õo¹åÖ>|x~øáeÕhΜ9¹I“&åÃÏQQQ!ôÍ* uêÔ)n¾ù–øÀ>ƒ *+O'ÕüœsÎ9±víZáhVR¶IçÜsÏ©S§f•=å©ÁsûöícóæMJh¶RÖI £-Z”+O ƒöÛo€š YKYgÀ€±bÅŠ(OuïÙ³§Rš½½öê™}ÍOyú´W‡”Ðì¥Ì“²Oyá;€š»Bî)W@KS®öhI² hqH1Åu7Ü”uMe¾@ÓÕZ °­pðÑK/VH@³‘²OkÅœBz/B .Šj/GïÞ½â¤| Ú·k— Û°qc<òè¤X´xñN-‡lÓ+³_™/¿’ý–N§ŽãÐCκ†–éÀT{xëÖ­¢Kç.±qÓ¦¨¬¬Ì¾ãØcFD¿¾ûÖ¾j¿¾¼¼<ºwë#{÷êU=ü¥™³âÙ©Ó²üèaÑ;Xþ<áþX±re>œûôî÷Þ7!žÉÏ«ß9g7¸ é½Ó|çÍ_“žx2ž|jrœsö™Õã×oØgqztëÖ5^{}n<ùôä,,1Ü„P»†eO·¥sÊÉ1a⃑~¶+… €Ò1¤s§N1fôI;5o ÍœõrÖrä‘Y°9ü°Ck /6lè­ÂOrP>õìÙãÝ tà ìëè“5k×ns† mÛ¶ý÷=_½fÍVï›æßªU«,„%oÍ›gãA×±C‡8íÔS¢K—.YJá'ÕB§Ú ‚v†  Akß (wÞ}OákÖl\êûY^е«õ|›ÁŽoÏ7Õê$ÅÞXºlY<÷×éY•øÆ«Ç­[WiãA3P^V–]Ü´jÝ*,hµÓó€€uȇµk+âü[D“Ç&=k+*bôI'Fß}ûDUUUÜxó­~âšÔVðþŠU«VW·ùY½zu6ì´1£wê·L  Aï;ôÐxfÊÔ˜2mZÖ¦&]y-^²$fΚcFŸüž/_Õ;A§m›6±eKUVMUcûJŠ÷úû³|äÑêð“O2ᇲôàÃÄYs†ì‡zH´oß.^œ9+îÿöm°Þ{÷Š÷vX£X¾÷?*Ц䊪õffùòѳG÷8å䓪k{RJá'ÝöÞe&LÈ 2X)-Âôé3| hy @€ @€ @€ €Ó:ý7sæ‹JhYè°ÃW@‹0}ú ·À€–G @€ª]wÃMzeûòa[5Õò±½€¦¦õÎà>zéÅÙðÔo,ÜR—¥x¹wå:¼<{v,\¸8N|ÿñuŽtÒã±oŸ>ñÔägÞ“r«Oåúõ1uÚs±`ÁÂØ¸qcìÕk¯8â}ï‹þýú¶¨ð°;·É{µ¯ìèr5Ö娣¨¾“Ã{y€Ü™÷Þ]Ë}àÀ1}Æ ±¶¢":wêTc\¶xÉÒ8aÔqqðA6ª?„ÇŸx*zôègŸyF´iÛ6–.]/¼8³Y âm¿'OòÂ@ @Ûsõ˜Ëåâù^ŒÙ¯Î‰›6Å€þýbäˆáѺuë=²bUUUñì”iñúܹQV^‡¿ï°:—»PPèïìIªU«VqH>ÜÌœõrŒ8zXq/Íœ‡|P6Mq¹5TVwÞ}OœrÒIѵk—X·®2n»ó®¸`ܹѡC‡Xµzu<ôÈcñ¡žµÓåµ$xN>ñýÕÛgŸÞ½³®Ôí¹zÍš˜öÜôX´hQTå§Ý·Ï>qÜÈc¢]»vÕå›ÊãÅ|¬[·.[÷4Ïé3žW_{-6mÚƒ8¼Ævzù•Ùñü‹/Åúõë³p6jäÈèÞ½Ûnû›ÙÖ:ÖµiØQCgÃZåÿÎÒ:¯\µ*^|iföºŽ•/ǽ·ÚWÒãcQïúm«<÷´íÙŸÓº}ÔЬLrùýð€öÏÊ­¼\“C ñØmG¤—ò`áâÅ1vÌ)1óÂ\üuúŒ=¶b3òëÕkVÇÙgþMœuÆi1þü¯ÊSW]¡zÈÁñÚësó'õMÕÃÒã×羇æÐö”U¿}ûæÇ-Ê¿5o^žÞš÷öº,Z´8úõÝw—,ó^={d'Ü5kÖîÐö|ô±Ç³õ>?ÎÎÿÐ9Y@›šŸ_±EùןyúØêrN'ÿEK–TÏs]eeéç/X§zJ\tþ¸üzö§Ÿyf·þÍ”ò7[{’ÊÊõqÞ¹Œ£†‰Çžx2[qùçCS¦N«÷ýZ¿RÊsOÚÞýyÁÂ…ùýîôlÿ[ê)<4Ù”®ìŠ»†Ìžýj;bDtîÜ)Ú¶mÃ>*æ¾ùÖ.]øÚËS¼L¯½öz3|xtìØ!ßuÌï)é*}¿ýãå|×fì?`@Wð •Uß|ÀY´hIu:ìÐC²~²p ßBTåªbÂÄM·Ü“ò'òÊ¢@²­í™nõÙ§wÐÚ´iÃòa`þ‚5Þã˜áGg'ò‚Wç̉‘ùíÒ¥sçlžµkÌŽ9"»˜j?ì°X¶|ÅnÝn¥üÍÖ^‡dèÐÁÙ:x@lÞ¼9†y÷ùÊ•+ë}¿†Ö¯”òÜSûÒŽìÏïî{bD¾Ìæä÷G€Æd§ÛÕ'µwÿ§{«Ÿ§*ô²²²]ºð -Oº Oë‚.]:ïÑ‚=ü°CãþŠ÷åK2ë•Wbì)§lwY¥“àäg§d'Ö%K—ÅûwŽ¿'ÿ|K,[¶,Nuì.YÞöíÛg·dR—nɼðâKñØãOf5¥lÏeË—ÇÔiå+Vd¨“ÚÛ»S­6Qé–^CÛ¥C~™ªÿP[·Š-[¶ìÖmVÊßlíuÈo>$­Þ¹ÅSü|KUÕ­_)å¹»÷¥â´½ûs}/pk×î4©´=:uêcFŸ¼UCà=¥cþ*=´»uíš=_³ví}ÿ.]ºDÏ=cîoF.ÿo¯ž=ë=Ù7TV© k~^³^~%zíÕ3»ú׬—_Žnݺfãwµ†† ·ÞqgÉÛó±IOd·|NìwB´mÓ&»å÷¿·ÞÞð6êØ1»å¶;Ûõ4¥¿Ù-ÏÆT6ÅûÞÚµÙþИì¶6@‡|p<õô䬡njœn<öø{lŰ<;ejV˺ô¸Þ~»vÙrîjG~XÖö¥—fmÕ{{Ê*ÝæJmšÒÇ瓾ûöÉž÷ÝE·¿’~4kß’j!6lØÏ¿ðBÖ.¨ÔeL5TmÚ´ÎnçTäO~O>½íö: “§LÉŸ ×fµÏ6Ð^fOx¯ÿf‹íHy6¦²©±ïMší-¢(5àŒ²ˆG”àºä¯‡ ¼Kߣ¾ï&JŽ<òˆì |÷½Î>}rD>€,X¸¨î rÄáñ— ³“ð®ü¨òÞ½zU×ФÇ;ZV)=“_—}÷};¥ 4eÚsYé]·½Šç¦ÏˆeK—emNz÷î'ŒUò2Ž:nd`ôDtèÐ> |o¼ùfƒï™¦I'úû&>˜õ‡ä·Ù{z’ß³¥Ú‘òlLeÓgŸ}âO¹/ Kì¿_¶?4&e&LÈ yò@óã Ænzþ‚ßs-Ž@;Ãí/@€ €=.û ô‹Ó-* 2TIMÒo¼¾]Ó/Z´Ø-0 åÙ*¥_x.t¿øÅ/JšÉ­·ÞZãu¥Ú‘×”2ÏÝ­Ô÷(eº=±¼ï…Æ´^;º, ý}]€¦äÜß´k^¨ —ËÅ?üÃ?ÔyÀ¯}Ð¿à‚ ²é·WzÍŽ¼®9ië¿§BÀøñãã„NÈ~­¾_¿~ñÙÏ~6–/_¾[·M}ÛÇß.ÐØ=¿àÑøÆ=§U‡•Ô]rmïøÖŸNéónñ!©ä[`-á€ÿÄOÄÈ‘#£S§Nqúé§ïÖ“+Ûïç?ÿy|ã߈¥K—ÆŒ3¢K—.ñ±}LÁÔáÆ)ßK†³úù]ŸÙ¿½äåøà‘—ÇÏùtZ²FÛhöìÙqæ™gFÇŽã”SN‰×_½FCC5Rÿþïÿ#FŒˆ5kÖlsžo¾ùfœwÞyñ­o}+.\}ûöo~óí?œÅ‹ǘ1c¢sçÎñõ¯½Æ{TTTÄG>ò‘èÑ£Gœx≱`Á‚ãÿõ_ÿ5{]z¿4ŸºÖa{×ý׿þuôêÕ+ú÷ï÷Ýw_õ¸Þ®½öÚX¿~ýv•ušgZ¯´œi=—,YR=nàÀ1sæÌìq*—ô¾›6mª±µÔ·œéS‡§vZtíÚ5ë ±¡õ»ÿþû³rIËÙ³gÏøÞ÷¾'N,ië›ç¶¶ßŽhhývÇv¨«ö'T‰#÷=±ÆðNm»ÇÈýÏŽOúIÜþ×gÃÖo®ˆ«úx\zí>qåÝcbź…ÕÓϘÿHüÓÇÅ…×tÏÜxp<ðòµu¾ß­Ïý0?ݨ¨Ü´¦FSíÇÉÊÊÅñ{ÏŒ‹ß+ë§çÅ5F×=ó­øð5=³šªUë—´¼töÙgÇ¿øÅìjÿƒü`|îsŸÛª6*u¿úÕ¯âŸøÄV¯¿æškâøCüùÏÎj ¶5Ï«¯¾:{ž†§éSºçž{²qW^ye 2$Þzë­X»vm÷ùÎw¾:tˆ¹sçf'»¯~õ«5Æ/[¶,{ÝСCk„§†jÔZÎdÖ¬Y1gΜøîw¿W\qEe¹ãŽ;â€Ȇ¿öÚk%—÷ºuë²åLëY~ÉèÑ£ãÈßvÛmÙò´iÓf«u¨k}ê[ί}íkqøá‡Ço¼‡vXV¾¥¼®¶Ç{, TÒú5Tf m¿±­õÛÕÛ`[µ?µÑçýñò’gß™ö_¢mëñÛK^‰aýOk'¿{®ºúáççóí¸ñc‹ãûgOȫǶšW E½òÇøÎߌmºT×6¥®öãä“¿z¼/þçÒÙÑ¿û¡ùç5—sÃæuñ»ËæÄ=ÇõÏ|w÷Ò„ rÅÒ¹ìíóYÝ¿­×64φTVVæ:vì¸ÕðI“&åòWí¹õë××˜×øñãsùËŸÔJžçG‘{á…rùДëÙ³gîâ‹/εjÕ*ׯ_¿Ü›o¾™=ΟÔj,ozŸyóæeW®\™Ûwß}k,Káu©Ÿæ³³ëž¦_¼xqõ¸öíÛoõšùóçç~ðƒä:è ÜYgURù/gÿþý«Ç]wÝu¹qãÆeO:é¤Ü½÷Þ[Ò:4´œ}ûö­QžÅåRÊú%/¾øbnŸ}öÉånIëWß<Ú~¥l£ºÆ5´~»s;ÍߟùNî²kûäþñöcsO¿~w®rãšÜu“¿UcšóÉ}ýî±5†óë¶5žo©Úœ÷Û·Ï-Ÿ¾ñàܲŠùÙ㊠+sûã~ÕÓ}òúA¹[§ý0÷ú²¹M[6l5Ïɯߓ½~ñš7ê\ÞÚï›|üûç–®}+{¼d훹O\@é ãRÿ×,©\æÎ}m»º”}m PºÚMµ&íڵˮÐÓ•q±t•|ùå—ÇM7Ý”MS,µ ¹ð c¿ýö+yžéXšþË_þrVkô¥/})¶lÙ’K·"ò'Ûìq¡_n™¤×åÃRv¥öíŽÂô½{÷Îjtvźï½÷ÞY?5®ïvWávTUUUIïY¼œÅ·^Ò-¸‡~8ò¡*ò1N=õÔ’·a}˙ʡ¸<‹ß¯”õ›A¦O#­\¹2{m µ×£ðºÔ/œ„·¥¡ålȽ÷ÞãÆ‹aÆe ¸S[—4¬Å˙ڗ¤¶Pi¹Sããún»¤²ÚžòiþÅåYj¹dU©wÝ•Ý"üíoŸüä'wúoo[Û¯¾¿Ï†ÆíÌúíÌvš¿ó/Ùm¦Ô¶çgOˆëÿva\6âÝÛDõµý©íù“â½Gd÷êØ7»Åuç§+ãÎϬÏúö_=õÆøÝ¥sâkcoÎÚç»zÜÓÙm±™‹žªûb<ÿ/5Ï]Ûï•Yo_॰խC¯ã ãVåûiÚf€R;ŽI“&ÕVYY™ðS0ùþ÷¿_cÜßýÝßŧ>õ©8öØcëœ_jsã7Æ¾ð…¢¡y¦Z€ÔøøÇ?þqö °Ÿþô§ÕãÒ󫮺*V­Z?ùÉOj¼.}@j7²bÅŠ¬ÍÇÇ?þñãÓôéu©QjÀ[І–³!©=˹瞛5šþÑ~Trû˜ÚËY»V%Õ>¤ÆÕ)\ÕW»òì³Ï–ü^cÇŽ­~¿TÞéy)~ö³ŸÅßÿýßg¡î¬³ÎÚ%{ÛÚ~õý}64®”õ«¯áþÎl€mÕþ¤šŸgÞ¸7þç©/ÇyC¿œ ;~ÐyqíäoÄÚ +bÉÚ7ã§|ºzúÿœxIÌ]þ|l®Ú•›VGÇwÚøôî²|yÌuñÿÿb~Þ[_°w͇›ÙK¦ÔvTÿSãÎWgËrÇô«â¨~5k´ ãîšñÓ8ºÿ黯°JmT^»Ûm€n»í¶¬ÝMñkS›‡Þ½{çzôè‘ËŸøjŒkh9Šßyç¹~ô£%ÍóòË/Ï}þóŸ¯sù.\˜=zt®S§N¹+¯¼²Æë***rŸýìgsù«õÜ€r×\sMeÉŸ\³×åO^ÕíP¶µÛZ÷íiCTjÛ“+®¸"[δž‹-ª1þæ›oÎuèÐ!·nݺ:_Ÿ‡¹nݺ•¼œ ,È3&×¹s笟ž—òºúþóáe»Ú˜•ºýúûlh\Cë·­vS;³€–­®¶?ÅmkRwñï{å¾yÏi¹çÞz°zÜúM¹ÿûèçsùC߬ÍÏÄY×V{ìÕ[rŸ¿ypî‚ÿéšûÇÛ˽°à±:Û÷<õúøÜÕ}b«÷½kúOóï¹wi—W,Ì}ëO§ç.º¦gÖOÏ‹çùû§¯Ì]ô»¹oÜ36·rÝâÝÖ¨,ýW|…Z|eš¾w¥øË듾 :µ¹y÷eÓû¾ yóæÅÑGßþö·³Z€ô]@-Ŷna]ýõ‘?ùf·Ÿ°€Æ)â’áßÚæí¯Æ,} ¾øc¥ÚÞß›5ë•· µØŽ„—ý&èÆ$µISãç¯|å+Ù­ôe{©=PS°»Ê?݆ûÍo~SçW °çØÀ¶üàìûÂv(/\yn«k Ž<òÈì‹õÒ§®žþùê+ò¦Ðí.éSS©R£sÞ;¶À®Õº”?øØ¼5´íýÞ•í°§ìÈí¯U®¸€–F @€ @€ @Ø1Õ¿ï߀€r¹œ’Z ·À@€ @€ @€ @€ h­€Ý)—Ë)Zœ²²2… -=ðA´´ðSûo^ €€z ÏëëCs >õõ‹ÿö…!hfá'=.;UUU5ž B4÷àSü¸¼¼¼:ü+6oÞ¼U‚æ€ ¦uëÖѾ}ûèÞ½{ôéÓ':uꔡԇ%!Hšxø)šBøÙ²eKÌ™3'žþù6lX ><;)8ØÓRö‹öçÎ'NŒ#Ž8" ­Zµª®*tB4ƒƒ~ ?›6mŠ^x!V­ZçŸ~†ÒðT-E :ûï¿||ðÁ¬64¡6mÚT‡ ÁvRÀŽžâà“ºtÕ›j~Ò-¯“O>96lØ Kã %)ì7nŒÑ£GÇŠ+²}£°?Ôn‡4Á ”ºTÓ³fÍšì¶W ?éÀö\uJûFÚGÒ¾¢œ4ƒðSh÷3oÞ¼:thv xWÚ'óçϯ¾-, @@ >…~!ü¤ªýTÍß¿u0`@,_¾<ÛWŠCPñ>…4T|û+ÔSCÏôI`ké“i) â}hb!¨¸tjô Ô¯øƒÅ5@@@ ?µo¾è¨[a?ÑHšQJP¿Â~"ü@@ =u…J @µC0$M0 B/<„†ï+B4ÑðS‚ A¨±:þäS²®¾çME)ËÝT×­¥ Ú5>B4ÁT~võ¼¾yc9ÁûðÅÙrÌ~õÕìùºuë⤱§Å‰§žk+*²a/¿òJ6MšŠ÷5@ï=?† ì’ ÔÒ5dHÜwÿĘ2í¹8èÀcò³ÏƦMoîéÉÏĘÑ'ÇÔçþZ=-¥…Þ†<ñðƒ{l9† >2þãûÿÝ»wφ­Z½:¾þíïÄ´ü6Ý™å|  ™„Ÿºïée¸ûO÷Æ-·ß‘ýÔ@ïÞ½ã‚qŠó>tnÉ¿º]•ŸÇíwÞ•u -Œ}zïç{NœÞ¸(¯gCÎÐÔiÓâÜ?ñTìµ×^ٸǟ|2 @Óž{®zÚíy¯º‚@]'Ýô‘êŸÿ÷/㾉cõê5þ w‘Óg<—ÿÓ?ÇϯúIöwôþù+ñÊìÙ±ÿ~û5éý…w¹ìÒ ´§Ý1þîøÿ$>èÀ¸ë¶[bôI'ÆO~ú³¸ëî{JžÇ­·ÝWå_3ò˜1þÖ[bäˆáqõÏ·åCU}†¾S«3í¯Ó³†­O>ýtܱY÷äSOgáä¹é3jL»½ïuÖgÄ„?Ý]oî¿! ~gœvZL¸g|\˜QÍAZßânO»úGÿýûõWç¼–… Ô¥ð³oŸ>qÕÿ£Éî+@@ ?…6?õµý¹õàðÉýmtîÔ).ýðEÙó[n¿}»BT’^Û¹sç¸ôâgÏo¿k|µûG÷nÝbíÚµq×=Šå+VĨcF—Ý.¹3ÀÒ¯wëÚ5Ø¿z¯Ï}æSÙ:ÕçÏ÷M¨s^ìœÞ{ï¿ø¯««CÐìWçDŸ}ö‰Ÿ]õã,5å ÞåÐèkj¢bóæÏÏú]öÑÃß|k^Éï±pÑ¢¬ß³Gwú=³þ¢Å‹|ÝÁƒãÑI“âw¿¿6û­§T›“n—´iÓ&~wíª§)¾·=ïU¸¥VŸ%K—Ö9/v^›Öm¢]»vï>ÏoÓvmÛ)˜fD ФíÝ«WÖ¿ëÖ›kÜ6ytâ„íºâOR-ÎÛýåY?µÏiÈÐ!ƒ«_—wìØ1:tèÃŽ+W®ÌÆ5dð.y¯†Ö½ö¼Ø9Ë–//|é³ÚŸÔæ'uo¾õVv+,CxÏ]tþyYÿçÿý«X¹jUöqô'Ÿž_úÊ%ÏãÌ3NÏú7üïÍÙGØo¸é³çãÎù`ƒ¯6ôݶ=Ç{lõãŽ;®($ Ù%ïU—3N[ç¼¶× £Ç4ØíiÛºí¹»ýóW¯Œ×çÎÍ‚Ï/þ몬Kç¾ñFüÓ_³Ó5nM;]p~ôèÑ#nºå–¸ðÒ˲aCŽ<2.½è¢’çñ‘K.ÎÚe¤65©ñô>½{ÇÿùÂçã‚wÂU}9øà¬Æ§²²2FW€FÊ6·oß.=äà]ò^uùÛË.ËB_š×Í·Þ¶Ãe¨MJMéû›>è ¬Áó^=ß¾­˜BP ?©14ÍCÙ„ rcÇŽU@I'ÊÔ¥O=mÚ´)Ö¯_YcßÇ<.½ôR…õ¸á†â„Nˆ.]ºD§Nò¹}Ö¶¨U«VY;±R¿¶­½ñÆëÛ5ý¬Y¯¸´< @€ @@³çËôÀ>"@‡ßv™ôТ¤€€eÍšU €€–åÞ{ïVPöí»(hŽ>üáËÔã®»Æ+„FħÀ@€ @€ @€ @€@€ @€ @€ @€@€ @€ @€ @€@€ @€ @€ @€@€ @€ @€ @€@€ @€ @€ @€ @€ @€ @€ @€ @€ @€ @€ @€ @€ @€ @€ @€€Ý¥¬¬L!€}F€ @€ @€ @€ @€ @€ @€ @€ @€ @€ @€ @€ @€€–¥¬¬L!€}D€ @€ @€H€Ð0?òöhqóÔw`‡mï/Åû Д"ååÙÁ<õûŠ´ˆ«ÙÔµjÕÊAJ@i_)Þwxï´VÀކŸÂ=u­[·ŽñãïŽÊÊÊX¿~}lܸ16mÚ[¶l‰ªªªìu¹\NáѬ÷‹â Ó¦M›hÛ¶m´oß>:tèu…ý¥P$ @@<ØèGŽë֭˺‚6lØ Í›7gHø¡%íé‚ ííڵ˂OÇŽ³. +@@@:À×®Jût¥[:ix:Ч𣈖´o$µ÷‹‚R-Pzœ†Õ®„   à !¦v Pax!ün¥.~hI…[]…Û`… T_ $Mè _€ à Uÿ…šŸB­DKÛ7Š÷Â~Q; >ЄPaXzœn{¥ƒ|qøI ZʾQ臠­/ w¿t¬YµjuT¬«ÌžwêÔ1ºuí²UY @ÀNè ë->ЫùÁþQ³&¨v'üì>«V¯‰ÕkÖV?_žtïÖUvîÀžBMñÁ»ø Þ ¡GøÁ¾R¶Í®øb‚]£¢b]à `—† â†ÑÅ¡Gøº.FãçÝ+µ?,e˜ìTª}| þ ´­aì9°KêµÃPZBØö¿^@€ @€ @€ @€@€ @€ @€ @€43­Zµ*i˜4:u,iXkE4ݺvÉúëªÃOa˜4Keeeѽ[׬kHyš %…$hq¨uúïþû着ªê.—Ëe@S;YOyyu—>VVQQ‘…ž-[¶¤þ©©Ë‡ŸA©+¼¸ø1@#=sЧ.|&¦.…Ÿ‚Ê*++·ªýI!HðšCJÁ§v-Ðÿ>™×€IEND®B`‚././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/images/start_macos.png0000664000000000000000000003317515074674453017601 0ustar00rootroot‰PNG  IHDRð*ek•ø pHYsÄÄ•+tIMEá 4Ï U5bKGDÿÿÿ ½§“6 IDATxÚí \×ïÞ’Â0Æ€]Lmˆ_¯c;~äÝ6ù´MÒM“m¼ÛÚm¶›4Ý»×M6IÛ$MÚ¤ÛÆÙÞ6nwoÒÖI·MÛOÒÛÆIc›ÄŽk(~pÚØlƒ ô–î‘„ÍŒF/ÄïûqÈÌèŒæ¡3ßùÏΜ‘LLLx<§Ói³Ùìv;p»Ýt !Äëõ²þr°†ƒá› ‰Dvz`˜5üW*•Êd2…B¡R©Ôj5 S$ãããÔã“““´Pff¦V«…ˆ %N 4"§§ÆÎÈÈ f—ÓœNR*•¹¹¹t*Åž€”€Ææfxx˜jœFèR›ÍFMŸ““È´H ¨´©º©À©Æ©Ì¥v»]§ÓAåºZ§§2—:&oRúçÄ)€… Õ8•¹kn¹Òü7OÙº}D…#šk.™éësËY¹‹suⵌ Y\D:³‰*;7K-¼÷<æáÁ 6ߨgftÛÆz¯ L8Ý*}^Q¡Q%Å•ÂN— ´P¤12µ*ÈÈÈ„~J?ÌGùùù|ñò|Í»p g8Û¤¥ÿ\ã¨éª2ï#tÊ@ÏùÉÑÁ¬ÒõN§+Užº-WêF붯Òù<â¥×b/0â#t¯ÇåôD\8¢¹æ ó•³ýº‚’ÇÕ¶3]C+6Ô”èF/·t Í*¦«ØPWšÅ¿‘ö+Ç:zi¹[ýBw[úêÚ1––)/v4_¼R¶¹®L5¦ìõºÐ- µµª×O`z9O}JƒeZ '''©æ] ?Ý?æ‘/w49Ý’Üò:>Ó·ß²r†»šíçNd¬ôxò˜=–äÛâ_Aû¬*(‘ù·‘ÄiÝ%Ê“Â?¹cä¯ý•Vûd×yèô¹.KqMqÍÎâ@‘Ñ®£';Ë ø/,¼ÖÎÃÇ»ˆ¡À`ê'R îºÐF ×®-UKHyaþé÷Ït®0ª!Çôº\.gÊ]ºtéСCtxçÎË–-£‡ýHXÊyY‹Hè¼ zJë?ßñ¬T·¸péJ©„t^¸H¼¤´tIaeÝ`wûx÷© ™=«`9ëv·uðÜñÇú-«²•ÄcüËñ–’çèø³cÉÆùþ’nóÙúÆ“4èûà‚«t‘ãÌÙ.:j,«®*Ë—Mô9Ñ»vóÚ•_á#]ÇN;>ö±Œ¿ü¥ƒŽ69TPY»ªÐ_Ý6rålù~ßœ¥µUåz…¯¼uäJÛé“ïë +ÖT•äjˆÇÒþ—˹åú‹Íq¬¨YY¢‘±\.'®ñžö†s½¾+ׯ*ÎVùãÔ± M]þض¤jÃòÂ,>Ùs,wvŽˆ®Cþʼ+M;/3”nX]®w„néÆí+´1¤2¬#RTCmN/ª%Òœò­u‹ªY+íè;ÙIJÖä©§ò(vQ)™Ýá´;d*¥”x]NCIÝš²þæþž©¹,CÄX™§ö•DmXl$m}#åÆBÜ~IQ¡K„n·Û©=™Ôæ~­ûNr9s»2ì¼,5'tÞ…i™»Ú{¾USPU´¼F§ÓËe²¾AS߉ÐQ:‘~D XǯÒÂÁójò—–éúO¶÷{ˆ£ëx‹¥¨¦@›aÈÕõ´ 9ül#ö“‚ìŒgièÜ™.²~㦠5C[NuŽHµÙ¥Ätyh‚ÑÍðejŸ\½.meáªõµþ3 ]pϹ¡¼õukkІºÿ6äñe®?Ý¡ª¨ÞxíÆš Õ¹3Ç/ŽÐ àuXz[šGËk7Ö­¯RôŸkë5³WD*³tµMè×lÚT[Uâì8ÙavûÕóÇšºdt!tõzÚšþÚoå>3q/wÖD×áLÓÚÚMukJœ]MGÏÛ38¶4#¶Ä´Ûå :…©§ýБ#G:ÔÒíUk’àþJ'!5Ks˜i¶¡ ÇŽÖ÷[èÖ:ûξwìtŸÛ·7ô+×­ÐI‰Û¨Rzµz¼Ai'ZÃÐ^*M#t¾y°ãæz>“©õòü•ÅËä …L*#jõªå%^_C µL.WK%ô£n§GªÒ3:A¨ÊÖ¬œN'- f^ÒïLâæ]dggçä)U*‰DJ÷B©*YV´‹äôgÊÎɣŸvnîªÊ‚†Žþ’5¥Úé íJ¡e~‘«ÍDVUe…Ú“¦ðkdذm]ÖŒ3¨6 ÙMv.!“î’¬übÒqfÔ¾,küC )3ê¦råþš8}ýAÏXÓsÔz±P¹8Ç-†Â¬iËH³ŒFKÛ¸³Ô@ KÉÔT™\C¬.ÖíT¯‡è Ú©Ú#W‚>j>^´ú.7ÇFñ,·,[Áº øO¡1Ò`ÙåÖqmi,»Ôë[Aã†UÌùJµ¼jUÏñ³f[…Fã[¶}øòEBÖ,É Î6e•uôöZHiM‰^Á_—J×®W^è8{ºË—1ªZUAÎö{âvW$•Ðu:Ýøø8+Õè²eËvïÞ°*sퟙ™)f^V<¡ó.¨¯õz½¯g5ÿ?Óñ“黈†M_¦½’©\Wïc]¾uÏ™ž%;*ü!žÂ¸¼¤ãÌàÜNCÞ\MÐ\2ýº;£XAB†ìžR¥ÿ›l㣄è}ád†UFry`Èfê5VmTÍÎvrÊ'SYºsCfO ÓÌÎk"E…ò\!\ìᜤ[¿µnJÌ^Ûë»kc¹\"ÔR—cˆjÑøòoiT»Té»2ÆÞŒ©M³]>ÓEJ׿-Æë4Ÿ¯±×XQ³ÈÕÜü>©ÙXaä|xÐ;1j’d-­ÛYÁŒö7·‘œ9Ô˜–9t*VzÍîp8¨I}úðà øI’Ëid›wà»7F$æëìôß”ýð<^àî;ÛÔo¨Ú¶cS é:~a˜ùíU†Âr±¹­·¤z‘">+hjüÛ‹Íníïhëו1·Ý¤9K+LçZÎ –äi§OÒÔ–¦±ñ SAuf1µ]ìµ;ìcý—Îö“²Åœ·1Eå~eƒ‘XNv^™p¸Ö‘³‡Ô_4E²\g_{é‹ÃÌÂè™ ³©mÈlsØÌ]çNR”«Spni,¨rŠJˆ©é]g§Ã6v©í,!¥ÙþÛ¬¶¡ž.¢[[2«€sÒ4b\±¹¦ÔXPqíš²±«<»Fb¿zºéÄ{}f»×ãîj9;DªŠr$PcZFèLŒÃÃÓ““r?¾ºât2ÏûЃÏ×¼ ç—›=J&œŠ©Ü…ßéœ?«mèBÛaíæÅ2zɵ¡²§éLÅô‚\ª+®0ôwÊåÆå‰-Ñ•¬P 7¼ïkÁ¢+ª\³,g:e»¨„tö,Éžþ¥9FÒqòĕРu%2úKK%Aq¶ŽÑYy]5ih9ÙåŸVºªv™¯™Ž}va9Q°#Kn1Éô«6Öœ=Ñ|¢—Y½›Êr‚ Kf4ʵ\b³YLº©NIݾ6²æÆ÷ýck6­`R<¡[ÍòÍëÇN2ëLWzíµeþ¦…¶¾æCÅúœÙKQf•ÔÕLŸ–rËÖå²/*ˆbj¿å”o®ržik<Öæ­X³©P‹tK kAÒØØ¸zõjBxô? éïïÏÊžÊ ÿ±QëÛECªìM_f&Žš DŸóJó{Êš+±GgnKOýYéöºb‰ÇíñJd² AÛ‡ŽÉ_¿¥, Ïy½_^É—iŠÏUŽÛí•Hea¿N`¹ó©#‹6n/ÖJÜnT&“ÄeKy×Ämw¸%R‰B¡ˆoíq;éÎ r¥÷CS™ÖÖÖðé2*Ð?Q,`¾æM{4MKóÓaìÆžéx¶gzbee¥ØƒÙß ÝBHõµ¹ñÑ„×E,Rº*¤³:°ôµ7´õ]ÅÚèÇÜŽR‘]#,×ëqúnêø¶5¸£…X·”wMd*UBÂg©ŒþV8ªÒICCCuu5vĽLsL˜Ìv¥6K§ŽÓ1íqXD­V²,蜷}v–2}Â@Íê©Õ¬€9·¤---r´+_è§t¥6'7®ý'K•®GÇÚ¬Ütë§YªæÚÔtÜR Á™p+©$tìH|)—£GbG@J£×ë}B¿ñƱ/ˆñj;aÞIíN’¹øÃþPTT´lÙ2©TÊ´äžœœ¤ÃJ¥R¥R1o‰Édn·{bbâÒ¥K¸) ì¼p¸$?¨Õj…Â×(–Š›ÓÜl6S§«¦¡ŸR¿S¡3½Ò¢Û€ã ¤I°¡è€ðµeÞÿùÏžy[Ç¥ÓÐàýÀ23ÍíÇ?hn=ÝjrE½ÜÈf·™Í&“9†’®îŽnWb÷dŒ;$ÆïtuŸ>Fi<}Áf"à8,`o€”¨KA*Žx g5[¼óÎ;ýªi«^W}Öµ©DÏnk½W"ÑdfæädJ¶?ÙÊouWß‘™’·?Ù1«¤éWßþÕ`<÷§íÈ Oþþ‚9š-JÄ^"®æ?øÆ–-uëþh3°½y?òA¢I¿ 6åa.n½õÖo¼qÇŽ7ÜpÃM7ÝtË-·° p=X¤Pl#Û²£îwÏ?»VÔì¹»íly¸þñ{^:ÍWÎ:ÜŸñÄ+í½#ã½ »ßxü®é’}/×Hò÷Ø[$‘<ôjG¼vèÙïSDµE‰ØKêO>¶ÿOí/ÎNqN„Çã|˜¥bð£ÏËo4Ç?z`YœËå}°(“Ô?¶ëv?ä{Žõ1×ô¶·žd¦HhŒÜ:݃4Uêö©©ÛsÁ˜}ÿ¿ÝëŸxï[ø#Huáö›6/5èõÆÕŸùnu˘“¯ ~õÝû»»²Ð /¬ýʾm-G:|Kruì­ÛuCþÝO4´7ÜXÎÿÖ [Ç#Û·ß{¯ýkjòmQß‘gkî}yj;̧÷Hn«Ïen}µF¢y½»nÙ^#Ùór«ÀÍlûíÏN]4øtû#ˆØvžï4uüž™D×óXßÌK¬“¯Q ȱJ±íâq¨§xU¡„®ö›o¾ù§?ýéðáÃï¼óÎÛo¿}ðàAv„Î7çøê¬Þñ£ûÎo¹ùGÌA^tÝýãV¯×z°êñê~ã—ù7u»jvÑÍìüÞG‚âÍóËv[#¯í>pó«m‚é„îý<ôн5ëö¶¼vG•ˆtHdzÖïþÇMþ4œ~e9HFþŠÊÚ›j ùg›l«¯ïõoÑáÏ5×ÝõßtÆÂ [sì:è? u¿½ÿ'd{m¡\¿òSïw>AÈ?øé›ï|çÓ+y·Ètìæº]7îtZ_Y´wåý¿qM-è†lqÛÎõ×­¼mõaßþlÙ;¹¥è…¡™ˆž3ÌŸ=ʽJ1í”8,c?ž!8¯Š‘ÐuË-·\ýõÛ·oß¹sç 7ÜpóÍ7‹H¹P›ò¿wmWýÆÛî'-¯Ÿó‰S©¼üÜýŸÝ~ûg_l ¤w˜ §3o#Ïï}ôÙ—sѹdu¡zzöêGïݬ–¶Þõ0©o§s·¾¼G2›ý§ý6–gnØù‰m·ýS5!§Ïõ†Ûœ¾gkWØýÚ÷>¹Ô?ïê}G_:X·åÁç¿”#¹ýåÆn9}«ôEßmùôHý¯ÚèÂõµßz˜|"üù?ùêáÏøú—«õúüüj¢ÊÎWë ½œo‹Ì—δ‡ïÙ^.W?õЋäÀñÞ™Í*)´JßIÞzáÑÛo¿ýÙ_Ó½üʬ(›³OÌ ‰|«ÓI#•Çr "U½0îQÏ;/‚@;ôj-ó‰bªCgÛ…—Kë~ðJÃï¯Ê¿ôÛûßøs±¯¿ïõñuÇŽ·žy»nå»_iß7Ó w.3»ÚX@êÇiœ¸òÓOõÞðàhrôþÿÖnß¾–lßxøRþŽßÿ›·Ò/[wÇùq’QZY®Ÿ™£ûÙšÒ½u¯ïÿL`âÒÍ÷½î½mÿžŸ.¿K½£îÁuÖ×W«ù³Ö!S6îy”¾ðÖ'n~œìîÜ2àÓmS³K³·È?¦ *5érq—¸…ò4:~â¥_|5ÃFä/üB®Ú~Ò2F§êYßÁž²Jr¾ýÁI6•'¨0AÓÆ€sNÓ$1x^‘MC_s{Ê%´Ùbp9Oz·å'o´n¾ouû»¯²­LOœç ¹õºÚrƒ«ïׯ ¹×Ny¾u°tóM«7ïÔýõùÛ®Œíçú6º ¹ÞX¨IŸ µ6]μ¦ºHã|ïÿ=O¶½4•³17ïZYWOªÆ›kõSËy¶¶boî¾®ï}œ˜L&¹Æ WÓ‰¯þ®ûúO”Û3ÔÙZ•ðŽ˜Ù¢Æƒ„Ü´Âÿµò¥7¾rÏ7ïxã¶[Êgö„¢°šü¨¾m÷êuróþ;Ž-Ò¬ äæ?¶~å¾Õš?ÿþGdÛCErÿ›ŠCJŠÄÿ4Þ¾ù­ó_Ú³Öè² µ4TÕV2ß /­­&uït|åÎR\=uÖbMä^%ÎýÙIg•Çhpœ’“HÊúÃΑ©ã¥õŸýìgô«BŸ ›CWУûÀ®jºÕŸky­ý«FêŽêOwÛ3Et’¢è ¾šLÝ€t{¬"Ó—AQÜö“ÝGï©áŠõùU;|j˺ÒLºFš¢;žß}ø¥ÏN‰J‘QäŸ3°¦æ¶C{[©°4S“™““sÛÏ|©¹ÆÜôB~féƒÏ?¸®îà+§~*ž“™-ê}£óËÓÉýõ»¦ zàSÁ/áSoýÊKäÁ:Dñ™æÛ"yáMí¯=¼«:G"ÑìØ[}ôÀ=ꈶç;»ŽîûÒº|ßÕä¯û¿§gnëk~øâîÏ­ÌQh>ÛhæžÈ»J!û3Â’J –°Èâ¯ÁÑ %mRá‘þv"KFT ¢«0N§3ðX?¥‡ÕjµÙlv»Ýá‡yU§äÝwßݺu+ñ·f'³›@šM&¢¤‘ýSÌfj{ýluÙlf«•UP<.›ÍE×O¯×GûÛ™^Øó‹¿ßÿ€Q ˆíôvÍß³¾^å4A´¢§_ؾîÈ?X_¿OM¢[{³ÙJü× ñÃe3™F­–'j•¶Cæ10{ˆ&"Ö†ÓÓ#B9—p‘ [,XÅuÎuþüù™Î¹B[³ë ì»bœÚU«õêè~9Õ–Z‹=äkn]£wš«'oL8‰Z´E¶Ö=šêŸòRËêè×^oˆ»ùäjƒ!–*b•¶CæÅæÂ1T‚¾$y„…UÃ&^f“®.¬b—ËÕÙÙ922BãqøÒ©-©Ä cs¦ë.*tZÀ÷Íõõõ×]w]ºÿ¾¶î 9åKgŸŽÌÝ9E…õ«ð)°Cbn¤Ó#r7,Ÿ®Ñº@I¾"i™ììl¦e çìÚh6›}ï ýŠÿüÏÿ ø/ÿò/©ü›ª—–/ ™¨_Z®_¨•<ÙwHÔÎé õ;\ŸäÖøQXs ´cá‹Íù¢r1ÑzØP=š tΩ,}s*€¤²¹È‰šN›:Ãij.ùäÎij­Ï±ÓÑH¥#3jkÇÅì{Ä °ÇCÃs΀="×'Èé:H+›‡7bö¨ò°ÏEäqa‰s ZØÚqt:„RÀæQ¨<¢Qñ¢‡ÖÓCåLÎf-¡rg™=¬è£Õãåt¤žÍ…§ð¹;t R•£#äÌ¢ˆÙùbî[ ‡Û€€ÇÅd`êt¤¶ÍùT¬oÏ4|Z«øH •'‰ÖÖdM V9ýè>…3~æÓtB¡ƒTµyØHœâv»].—ÝÓé h= §ãA¤T7;_Sna›T®P(˜îSär9Ó%Kå"#÷„:B)osÀÜápLLLÐ#P¯×³ú¥ "hp`³ÙÌf³V«U*•Tñ,• x|Μ¡ƒ°¹˜4 k€þ¥!9µ¹Z­¦‡=™NްÛAtW4  A: h¥¢£ÔéBuá2qwºU$¹è#ºÉ°9 Ïív;=ü˜ìUc¤‰†LÊ…©ZL¡óù=ìhì+‰$WxÅ=OÎÓ£N£ÑX­Vìm/襽æcþR¡3Fæ4¸˜TŒ€Ó£s=„RÞæœNgèô×  ¾ÐXV-ZÁX6›~éôø·€µyà/ó*¤ eê‡$ Þ¦3äâßxY¹dÃo]$ßv+<Ö>éÐ!ïÕ÷‰Åÿ‚o]•$ïZq§TþÕ}ýöþ÷Fßmm8gý]¡ùH]vÝÖìë T¨É­T—N0SB%>_N—}þóŸ_¶lYð¤Z.ð+‚y?ÜÿdMdln±X¸_!ÈÐÖA¼šÓp"×ëÊÎÍÎÊÒé'ÌòÖVëÅ.Iž‘ó„Viìé…}†‰?äi­†<}v¶&S:,;a7uz5…µ—ÏZZ÷÷íÓuج·«™ ƒöªl´iòT×XçbeA¾r‘à®p^ø É¢ÎÍšyw¬§§¥éŠ]•Ÿ•Á9ËXOÓ½_ø?›nÝ’ázôïwéên,Î Ó=²Ç5~êý“^âL•<0êÊ42 õ¸&μßäœ&°ôLå¬&FæÞ“÷üÓ·|r«N.MÅ:ét:µZ-Ónгí#« »ðç(ÃÄÄ„F£è>7½h ÉÃsa¿‡æÁxxp÷x~û»Åý½º‚ER–Heô £t"ýÈW€×Äré§‹íúüERM‘Èè?:@GéDú-À7oŸµïçþü¬æ¢!‘F«“Iäô £t"ýˆðáúÓSÏu Zf6Ämû[ß}¹¡[`Çä/é¤ÿ³M7ÆZ†Ãòʾï¿ÛÑÏŒŽvŸyfß÷_=ÔÎŒÚF»¿½ïû½c6(¦–Ξê[ “Ýéö¤&œ/´ã /D qy>BIgù(,|q:’††Ü®‹Š¬,Zøç Љô#_*†éСÏŠÌ,âñÏâñÿó xéDú‘/ÃÃ{£ï~ k×ÑåÒòn/qÿ?ß÷Љô#Z@xÍUYrOÑ,Q•roü*sv®É>ÞtžI+tµž¦[7[üy†‘î6¯÷£eÚ辜IVȤþ$ƒ7µ_Il(ÇšC`ÎÂóxÙœ/Tç\ÉÉ2h`ÎH|¦ ‰—~4|òïÇoåžwø¸V§›±93;½þ•úœ®Õꆇ{‹ï᜷q¬Q­elîõÌ,VBÿ“IÔÚÆÑÆ;Œw ì@æ|´+$²™Ë‘ɯÿìù_¡Ó‹×}ú±ïÈÑÈ8Md7õü÷÷¿Yßá{ÝøÖO?øwþ]†48¶“Wí¼î¿¾{bü‹[ôÄÚøÆ :ËdwC¿ù³e™Šs'g¯¹Õ —ºÝ'^õù_¾MgÐWnûæ×v•4c=MOÿ×ÉÚró/ÿÐtÿÓ/®UÍ,trøÂ÷¿þXó¨S‘]ó…;?BÏM©û¢m¾ÚÈžsfÒÃ&ÖIT5Bè Œ»Í…Bž‹¤%‹§có )û/‘jÔ´ï¼–6i^î”ÿe¼¾©˜¥jéoã›÷œõo‹óý…™¹üR—H™¯RjTç>ü›ðEºR/èÑ»œnÛËdKw÷$³Í§þç™ünø_¿õì²LÛ‹=öà¿Û_|îžP›»Ãÿñůµ—lyúwIÇÎ?ñç;LŽ}_Úlô¼e×x½¿í795Šþ·Mޝ?÷?ýÛ×ÛºG–V©ÿrèÃëöVQ9ô-®çþGŸ^µHö?Ï}ãk_¼üüËßÒyÝÚ¨?ñÔ3ßÍ+Ð{‡ zvÏÞ %[¾ýØî¡–Çžù)!%©+ôàZ¬ï¸8:H“ðòæÅKHð¼é¯Dæñ¤djçdä=žþ ‡+Gì ]íÍ‹ß:Õ®%^|óM:B>²é–¾oþ¹³ö£ÏÇ 2ån«sÒã)ÌÕN­­\•7½Yf…ÖÿíþÕ ÜEœµÐì¢ ç˜À”äT.­ Ø9^OBè IEuŽEL„î^³zòàANç+‘L%^#eɤe½y ï¼Ùuãíz­Ö—F§BöJ¦LˆT21a¡øæ]¯[ß>ùk ]®Ìw*,–ŽÒ¿¶É Z@8B§0‘Ÿê¤J½/Q.Q(õ^ï½ÿþÂ'®YÌ8Çnw+TróÕ–?.»×kuOï»ÙĹ¯*ê>Ñöè¾6BîúúQÖÒ•K¼?}ìÉ+?µW/‘¸J£×;0<á]’éÛ'NÛ€×ëò‰Ãä |ßBÇ?ìJËzÔ˜xV.`î²b¢uá¨\8µ"¾Ù¢sýúÁ%Kcc‰èDßGë×óÍë0\7ä]í£úöKÜÿÏos:‘~D ðÍ»IwíjÇ ].#qñÿó}H?¢¢kHG¤úmÌyùÉ}g{†&-¦7üõ»ï~êªÝh<@“WZìéÿÖó¿îè9ûÜ#ûs6~<_-e}afA¹?è.ÿH‘žþOªÎÛrMØrÍ’ Å=ûÁ¥¾±‘¾7~üD¿§¸þÕ=Lvç±ï?+—ŽùÊÕ qKiH¬Jå…ßüá“Oÿó£_ùÂoi¹¥×ÞýÌ—wÊCö¹4#gÓõÑ%[r”RÿGÊk®¿ág§þ\±8kzqß™ O<ñ¯_a÷Ä { 3ä£t ³¤³#tßÒåŠâ§þãÑÿÚ“þ…æßù÷7üú—™v‹i¡žþ¹Äô ûRÉ‘#G¶mÛ¿€9Ë• ]dšEŒÊívûàà B!ô4£äê°¼©IþÁYi×%Ÿ”K—¹®YåÚ°Á›—~«ìýŠ‘zùX£t²Ã7oF¥+«Ö™³ˆx|Ð9ø¾ùØ©‰Söó¾ä†jù:íºkõ›©ÍcßÛn§Óå!*UøÇ8}oü R•Bãâ<ôC¡w±ïq:ÝD*WÈ$)]¥é®ËÏÏW©T’³†YDÄ¥ÌðÀÀ@vvv𓢬À!c6››››!t0BÂæ|ç Ì¡:­ Ž8>¡ó9ÏæÂN§u8"¡#åæ!<Âþ¬<ƒ°Íƒsèø À|¥\HÈ»F#zuߢÊCè ¹’-¡A:áJ³Ž+ØÌ%¬f‹œN®ºœ]¥ó5U }Ï‘x§Cè IO|wAÃz<`s8$®¢2,lÉÐw\„ÚOŠ‚tÎÆ„Fë*'<­™îînìgw ˜j&•Jò-ZV9,)Ÿ„á Ïù’-œ%C©«CWþ þ\ºÔ%ðô?çƒûD0Ÿ.ðœQDr‡ÐAr)^8o.БiЈ¹Ò†Ö1ÎØ\8ñBâýÚh$W¾…ð÷)H ƒü°¨˜*¬u›ÇžuÐÁ\§VÊ ¼mN8J~s¡‡¦_„M-¾_ÎÆŽœ‹€ÐA Ä鲿ëjB‰«·. ×íÅæ:Hóu]cx¡ƒ9‹Ð9¯)Å(›³/ưõB)©{1wA9csäÐAâ®cLËÅà¶+¬˜/H'qm΀îsÁ¼eW¦Ç×aŸûû ±Gèœýè†ö"'\‡#=4¡ƒ”É·ˆ·§Cè`nR.¡ CÖÛ-X±9ßý̸d]¡ƒ ä#êGûÌ™Ðùjf\Bo‘ BI§r¾v,¡W©x°$ƒÐƒãñÐA9o“†vÇ—d:"t‡ _„NøýO݃äGøEt„«ï *G t0oa8ážHÀï$’§F±ÃÁÜDèQßñ €ÐÁüÔþHÏ÷ bÂs̗мéãÓQG:HŠ˜3cNx:\~/Ý\ØTÚ°7ç‰`§¡|=ÄXi!t0ÿé¾PEàÝFœ·I¡ƒyŒÐC?"ü=ÍEz,@è YLËe&ŸÍ9åÎyDP¡sÆìÕ5¡Ç„æÚæ‘ÎË—=N “x·ð 4=öF¨§ÇñÐÁÜÙ\LÅȨð)>4n"Þ‰ Šð·¬®´‘†â+$Ýi€/Ã(|s 9t0/)—°MܯÔ9„ÒÁþ `s07A:çÕa ¡ƒÔ³3_½ÓTQ nÂs¡ ÂÏŽŠ? tì!¶ÈËOá7`4 ÃÞ‰D„ïÆ‹|y‹ÈƒB©äw¾ö^bfá  °{AB#ô(*'lú‚‹@:ÇéÇ€˜–‹$ÚéÂ]éFÄ›Cè 5\Ñ(‰S.1U4Ò†+qoÖ¡ƒ¹Žbb?r„À#\m{¤ƒ9Ï Ï“É56ö#Bà t,‘xt¢ç{¬6sP{…m›ûCB©݇}ënC!D^8†}tܯ\!t&á<ç@Ü»! Ò³ÉìßÑÐÁ\Yd#¬rá—ðÂé`.#tÎè[Øï$ÂF‹¬Ì:HvÝÑÁà`¾jo|ûØB„ÒÜéâçESt07çÌõÍ}å‡ÐAÊDâaû óÚ‘ÖɈ2-/‰é}õÊÙ1)á¹5 ÀÜx\LŒ¢¶#B "´4r µQ|$ŽV.`¡ØYdñ‡T’¤ÇR™£¨Æ:Hù™$µ4Š‹@ëá‹¡• HhŒ.£’è: ¡ƒÔ“µðAƒ9®À"ƒ‰9>„RÃ鑺;ÌKÕMD}†ÐÁ²? P9!t’‡Mì]^0—˜s#BévÁì`ÁÖ@,ÜC€4«Z:Hù⨷:H·c f ¼îAè Ý®mavÌOhå„Ð M€ÐAÚ†ê,´ ¡¤IÕ…Ð M€Ð¢Ò¤rBè µh NBèéV !t€ƒ €4©r:À•/iR» tH t€Ð@è t:@è t: t:„B„B¡„B¡€ÐB¡€Ð@è t€Ð@è t:@è t: tì€Ð@è t:@è t: t:„B„B¡„B¡€ÐB¡€Ð@è t€Ð@è t:@è t: t:„B„B¡„B¡€Ð@è¡€Ð@è t€Ð@è t:@è t:„:@B‘c@J`µZ»»»ÇÆÆ$IvvöÒ¥KÕj5„)Æäää_ÿúW—ËE‡©ÐM&“Ùl®ªªÊÈÈ”AÊR€žžÆæè(<B€`ll,ìDRÇv"„i„:„B„B $~°À‚ª]:H·# ;,Ø*¡T¤I%„Ю|H“: ¡D¤Iå„Ð M€Ð¢Ò¤êBè‡iR!tH tnq š¾€9«œÑÕOx îAè Ýsx ÞBèGiUµ tžGl` „ÐAêH‡ <’ÇìsŸ[‡ÐA:<ð8@å„ÐA \ºF1;üæ«ê&¢>Cè ­lÎwä°¦3£°9˜ã Zcq},Bé)}4K ­“œÁD¢p,,•Câ`ké¼kBIjêÐ2âh$OÀueŽ¢Cè %ÑÀ0´]Âóèr2ˆÐAº*ÂU?¸ß0læ2ÂY'£¨í:Há«Ô°W¦a#qx̯Ù#Ü£8(„„ޤ„ë# —(R)âhÕ T³¸WàX¾5¤däöê•Ëd2ìXhÕâK¹$´’‡?Óà·ó®lá‹ÐÐËØÀñ#ðl¡ …ÍfÞñ…V*Zµ˜ ð?ÁJ¦ Tì莤Ãù@ÀïÁ£ôxS©TýýØu ¾ÐJE«V ë§ «Ö/ÞæaÛž‹Q9üß]¤Ö£H¼ð…á ]Bs,a{ˆhK)%%%f³Ùår¦Èår:10ê{µB¡°Ùljµ5Äýð ›4ç Ò‰ˆ7 ‡3œᲞ£ÍѾeÞý.2µÓEj=¢ð\ä[¤edd|ô£íéé£S²³³©Í5 SÆétR™ËU*ÕÕ«W‹‹‹QE@Ææâ_÷Ãw„sö¡HøŸï“l‰®ù9ü÷=¢ä[¤‰—¸¼ØH8uiœN^YY¼ J5>>Ne.§±ùää$U~p.€ù2;gN_A¸š6†¾èY¸Ÿ–ØÃs‚¡ó'wñOF¤‹ ØÅßåL¹Ä¥ŸE&CeîK¹¸Ýî:)//¹0÷9ßíPήùæ ]«UKåL£FÎ÷Wð…ç$†:DǨ<¬ÊI¸²L¦›ŽãÂOq®¤ðé„çØ|»Ý><(û¿“Ÿ•U-[eÎÒÖºQûSû s˜½´ÅR¾^¼mIë¶–âå–Ò¶ÙKÝ÷™]äC_L-lêŒSÝí]¥m«f­(m_üÒÂÒö¸ñ@™m]’_Þ^7jj¿içpë=Óä?¼"–º_ÅsXÖVül¼63„̯·Þó¨g_J~©¹ýîiþ9˜÷Ÿ³´Í1fkùºùÕ;‡0¾˜Z´nk$oHíÚº³Mÿýÿþ»´]]Š©¸ñ@Ù­Sž“FóEý•ëFíOí7íT¤íýªíó‹oi0¿8Ž“s›wa|1µ¼­'’EjµéoüÍwºuØoI«µmgñ|*õW}öýÇýÓrÚ¸sLwÈÔõ†?È¿þzVì\êÔ‹yÓ¦d!“ä¿D!³©Î9¨m ÌÛ¢¨±;::,A!ç¼-n,;d\s0·-XSø ºk:‹¶uJƒújÞvÇÔ'\ûsRÛÕí k;­ûªÇسX— ãzçÆS+Ú·G*Å“R- ëK×{Ͳ÷¼©Ö…ë}Ûüc6ÊÝWÞ!†ºÜð”\`EÕ9ríÌí±s`¨»­2ïš/îQT$´µµÅ²b*f,oj¿Î9¨må€ –fqc­õÌÁŽ©…M[¥Á´Ð£°­Ó ¥'}óº~ǽOúÆð²c*îwä‹©•z#© j[ÒêZmr®N©¿î zÛû/ýâÆe*(š7ïˆ}áW°nݺXê~qc©ý©ýÄ9,jî2m“Eë¶Ébëk—eqswêú÷=¸}ñºÂXêëb5Þºâ¸Åñ¼sã‹©UwDRAÔ·c_àûM©σ¶ïëÝ[~ÿ©˜ñ@Ùí÷Î(†Ì¶Hj¥%É9S…™è±ÔþÔ~â–¬ïöè*ê–Ŧ»îûƒk_wš×—lW×Ûc4wŒÛí›C_L­Þ´3R?›/n|P¦^Ì[¶ì2_Ü{êFíOíw ÎaiKÃvÏõ‚e¾íÛË÷m-\_f].~µÓSÚf?Î;‡0¾˜jܼ+Rc*n|P¦ß÷‚´nÝ#ËÛzëFíOíw Îa™  ÖÞ¢íæõ¶í²ÜÞÞÖ[Úæ¾ßö€ÇºÙcxçÆSk:vGêoLÅÊîöŠ,XÑ.»ûêFíOí—9¸çÆSk;ö€bÑÚm2õÑW¬’zQûSûeî9„ñÅTÓ–½HÈS{/¦Öuî@B¥˜Ò4-2¦2™ À ô׿þU¶lÙ"]]]²sçNÙ½{·Ëž={J_öîÝ+ûöí“íÛ·GÆ”ê(b SÄ1@LSÄ ¦ˆ)@LEÅT__Ÿ8pÀúJL¤ˆ)K*¤FŽé *b "¦ìúÄ'>!'œp‚œþù® "¦BbÊ©Ã?\Î<óL™8q¢Lš4In»í¶RPS!1¥‚iüøñrýõ×Ë´iÓäÅ_”×^{Mòù¼¼úê«ÖíÄ@ÌÊTV¦xkbª kÊ;h5þÁå=ôˆ¹äãÇÓ3yÉg´Òuͺž“¬u]+Þ÷)ߦ;ÆÒ\׳’ó6ë +'€˜1å g¤¨8Êy&oG“îxŒ½ddú7fš˜Ê8ö4f¢˜ÊYáSÝ )=qLéVPÅÈÑã„­©@ÒKcÚ+OziŒŒg%*h»?´ ¦ýÊ”æ‰lÈêSÆq»½]wÜßÈôoÌ41¥9®Wxˆ±NºµÊ£Yq£¥ˆ)û±…Ûì˜*„Nت‘Nºu¸Î°V¬ŒÀÃa!tˆbj æË£Ä»Â£;¶iŽó” ÏW=`u)í˜öxù€Õ® s¦²Õˆ)ç!»´1U^A Ž)õXg­Pöe=à<ª°CyéB*kþŒóù"ÇÏ8gðSµ‹)=âÜ(ó •u#b•G–\ÌyN•ŒYiLi!+` c*8’’ÆTù/íÜ' »o/Çš}[á¯ûŒ˜ÒBÇàÉÀÀ<=rò¸÷ò Õ¬|ÄùLiǬ$¦ÂÞ!ÛŸ˜Š{kçc½‡ßüoP!÷_úSðÛÍ…ÐÄÔàyk½²¿–«û˜€˜P1¥œ^ˆªö˜€˜âãdÄ=z4€”;ì01bÿ†Sõ‰©lN—\¶Þ? Mô¼qö ®ˆ:õÔSå7Þ°þáà?þã¿äÿöñóo 1U«˜RA“—¼Í¨çÉÍÄR“'O–ÎÎNyèå•*´zÏ_äÙ¦M1U›˜Êæ 1rYV¦€H­H©zøåUúiî®rØ9çóo 1U›˜ÊëZʘ*F–Ã^ÑҵŸÿAqdÞß^ñÊ:£S@Ī”:´÷ð+«TÉ‹=û9‡Š˜ªÅa>@*nŒ”1å8$hRáñšž]+GSé²[…Çéö{NizÊýÃ+¦Ô?¼º@•<×sÀ:)cˆ©šœ€®"H­©C~éÏ‚¬p¸°pØP…’®ë¥Ëö×|Þó†”ÄSùË_ä÷¯5¨’gºö[Ï-þ!¦jSfäX«IaŸSÖŠ“ &]+ŒW<¼§Ù‡‰) UL©ÿ¦½¾@•<¹˜"¦ªSYÉf+©°Ãu*  1ŒâgÐ…*-ã9ôgŸ¯EL‘1õØkTÉ£[‰)bª+Söá=›®%?Ý0‚W>äW &ÇÛ-Ê>¤˜ce ˆ‰©Çg5¨’;SÄTóñ–À€‹©'ß\×/“ŸÉ÷{ $3õ¹ùrÕ-Ë?ÕëFíOíw Íá‰gÞ’ ¾r¶œö±O×ÚŸÚoÜïèÞV¦ˆ©óq2Ä0ÐcêW“ 9ê„3ä³cþMN<+'w³ ž»üº)òƼ•²±{_ݨý©ý¤9|çˆdÖ#¿—ýKëFíOí—˜"¦øl>¾˜úÃ[Í©L>WÆœu‘>j¼|âäŸÈ¿œ”“cÎ}FFžqŒ›ðsë%í˜HfÂÏî°âbÞš®ºQûSûHsP+E}«KϳÖÚŸÚoÜïèîÍÄ1U‡˜*½µÁX}*Ï…ÿi0|cʘ³>‘G_^.§}ï2ùÜIçɱçþQ>ô‘OÉgN»EŽÿ™cåØñÉ/|Y>öù±òÕë:ä³ß—QÏ’¯\$_þY“|òKäÈSNŽëQ95óE¹ÀHº=ì>Iîïv–‘Sõ˜}êçšÿÀ=šxÌø¹§Ÿg˜‹K!³­nÔþÔ~ÓÎá¶)OÊ~xE,u¿´sPQ³gÉ|Ùö‡Üž**^ð—7¸ö¥®Gm³Õ¤ö§ö÷;úíbŠ˜ªqL©• ò_åÚ˜rϾ1õÇ·Ûÿ£Ëdñ׿&#G&Ÿ9é"ùèá_—Çœ'ÿó“#¾}§d¿{¯|äSŸ‘#îù‚œ~Õ#Æš&§eŽ— ŸNº=ì>IîïqÇ̼¦•¯?}ƒaþ,ޏjviÛ䫎w]O&j.Ì3ÄÅÿq—´›a‘o쪵?µß´sP‘rðàÁXê~iç ¢f÷¹ÒùØéœV°ÅqÙ¦Ævþ§®ÿîú‰Û·¨1<·Æ/Ž«ö§ö÷;º±˜"¦jSÞ• ÿçï¹¹Yï-åk„¡¹\áãf¬Ïü3ß:!ïúL¿˜¹÷U£ôñ5î·apÍU- ‘˜š>·=‘sÆ_,›¾õMÙ6öÛrþ§?+Ÿ=êërÔ¸ûå˜ýQþéè¯Êˆ±Ÿ”QóFÉIÍ'ÉØ+'DŒ5MN7ãbÂ3I·‡Ý'Éý=ž¹QŽ8úF™Z¼>õ'ÇËé?1·=­xŸ92áè”cÆÎ½‚y†¸ä瓬°˜cF½´uõYûM;‡417–ÚŸs*jvΟ-Ý%›.zh’ãráë×^oÿÁ”]W÷ë(>ÖþZ0©t]íOí7îw4±˜"¦jSþó“<Ÿ¿ç|÷rÇgñe<× ñT|÷ó¼ç#fŠïkUÞãÓãΕ*½1¨çÔ}o4öaËÀàŒ©gçµ'rîø‹díé§ÊaúÜqtVž?ñ9ò³ÇÈÇOþŒ|òŸ”“[O–ùaÝ0ZÎùÙO"Æ*ÆÅô˜íÓo´V ó=O&úîuÿŒœ~Wо‹±4ÝyYãß¾5faß§;¾8·ð¹qõ!ßoz…é3£»nì˜rΡÍZ™êŽäŒ© Ã{î•©è±¼s°cjã·ËÆûo·¾nz ðÕyy“yÛýÿy­µ÷ßßGmW·—s¿{œŽq옊ûý¼µ˜"¦jS*|¼ï3å9ÌçŒßÊO9ŠÜ'°îïÞæ~“PÿçÍÅý†ŸÞÐrZñãlø C%¦žŸ¿1‘ ~t©4™15ó¤å˜?{ÄùÞÉ#嘙ÇÈGNýˆŒ¸p„|ú7Ÿ–Q FÉÕ¿1ÖãòÍÐy/M·ïc_6M:ÏŒ’·=Û½—3òÍIÅûO¿ÉŒÇã~9ξŸù˜£o’û¬mÅûšûÉŒ{Ü5Ïà1 ·æ=—û®>Þñ}õÏ¥ÿy·,\Û)Í\éç¿~ ÑùJê~qc©ý©ý¦ƒ¿§§Ç¢.'½-ÉTÔ¬äyý´£ùÍÙg¹öiïWmO:†ÚŸÚoÜïèêbŠ˜ªULÙD\§˜Š<*p.žwO÷ÆRin¬JaèÅÔŒw7%réùWX1µì_“³Fü£¼þå“åÛ'e号ޓ¿ÿØßËßý¯¿“/­ü’ŒœvœÜýäëcÂãâg#¶?{“|Þ;g3rÜõÞÿÇò+Çx¿RÑtwÀþïþqa,û«¹í¾Ÿ/ŸÿéÜÒWë~‘cz¿Ï\T¤Å~¿é© XÔÔ)üײHÞs‚ÂþS÷‹KíOí×7‡?/‹¤Æîèè°…œó¶¸±5muÍÁŽ©7Ï%³ÆŽ’7Ç–¿Œ6om]þí÷ƹö礶«Û­ûª±Š¬Ç-l³Ù1÷;ºr=1ELÕ$¦ ŸŸ§Å½1§3¦bó…ÇTñãkBÏg ›‹3à‚ƒÌZ2CŠU) µ˜z±as"Wüøriþæi2÷+cäü9LŒÓäô/A¾øÖå£ßú¨õÄQòá#>,Ù[Ž“Gÿ¼8b¬'äŒÌ(¹ä¹ˆíÏÝl…Ì ‘¾ÿ ßÍÈ÷ì_ÝwäÍrÃÏF•oWÛ¾{³\2Ò1¯È1½ßƒg.æøÄ~¿é]víݲxÝVyô•‘T$´µµÅR÷‹KíOí×;‡iæmQÒÌ!n¬Å붹栢¦eÚTÉÿà«!¾b}½uü|óº®î>VÚŸÚoìïh1ELÕ"¦BW‚"b*öôð˜ò€žw¢ œ‹ó|­ Òƒ"1õ§…‰\?ñv¹oÌWdûYgÊŒO°bê´oŒ”c_9Ö:Ä7¦{Œœ²ñ9ú²Ñòäk+"ÆzÒŠ‹KgDmW—3òùkÞ‰¹ûþgL.ÞoÆ-f/7îÿ¹t¤ú8çPx|Æõ˜¨1½ßCø\¼f”g_•»üº{dyÛv1æ4GR°nݺXê~qc©ý©ý¤9¨¨iê!™áX™wáY–ùÆZ×¼sP×oÿñyÛç;ǘP¤¶ÇRûSûûMXKLSU©ˆ• ºëß\Ü'¶C'¦f.êLìº[¦Jî¤/Ë.mlaeêÌãä„¥'ÈèE£å˜—Ž•“¯ú¦<0ãí˜qž’o™qqÙ 1Û_¸EŽtÎù{Oyîuÿ ñËR3òyȱíæïÙûpÜ7tLï÷à¹>åüÒ¼¼æ–ï7½+®›,«7í’ïnŒtÃ%:gJÝ/n,µ?µß45›žBýû¹¦9œëØv®Ü9a‚k_꺺-xû¹ž1LW–ÇWûSûûOLSÕŽ©ôã•ÎÅ:l˜ÏóV²1õ_K¶¦rßôÙrÁ×ÏMß>C¾6öXÓ5Æ †‘òs¿/3æ·§ÉýŸ_L‘¦-{ëºOµ?µß45/?/˯½¬Æ./]VûSû›ë×ì#¦ˆ)>›n1õç¥ÛR›¹x‹ÜzÍrÄñŸ’/|g”üû¯ôŠÆA:ÿ6qª4oë“×VöÔÚŸÚï@šƒŠšîÙ¯Èê›*«oú©4š_o*\.¹ùêÂíÖ}®6ïc_¿ºà&Çõ›Êœã8/«ý©ýÆý޾ßHLSÄ0ìbêåeÛ*ö¿*OÍZÙ¯1Ü5¿ù½ÌYÜ,ë»ö×ÚŸÚï@šÃw:IÞzä÷²cÁÛu£ö§ö÷;·š˜"¦ˆ)`ØÅÔ+Ë»0H<5«ÑŒŠGäÊ_Þ[7jj¿i¿üùÎ'X+Eõ¢ö§ö÷;»Šs¦ˆ)b v1õÚŠnUò­•¬LSÄ0ìbêõ•=ªäôÄ1ELÃ.¦ÞXµ@•œJLSÄ0¼DÅTww€aÏ›¯-çõ˜"¦bŠ˜ˆ)Sˆ)€˜1€˜ˆ)Sˆ)€˜1ELÄbŠ˜"¦S1b 1S ¦ÉšòZpy=b.ùøñôL^ò­t]³®ç$k]׊·;éæ}ʷ鎱4×õ¬ä<Õ­m†É;5Vκœ5o/?Æ}_-p ¦xÁˆ)bjðÆTÖ,*¤Œ:Ä”wÿÙâ¾+ˆ9Ý ÃHêºS¶œã>Îr†—3¦ìÒ÷ÏZ÷Ó<V_óÍ­VöøYó±YOXi<‘ˆ)^0bŠ˜1å g¤¨8Êy&oG“îxŒ½ddú7fš˜Ê8ö4f¢˜ÊYáSÝ )=qLéVPÅÈÑã„­©@ÒKcÚ+OziŒŒg%*h»?´@L ¦ˆ©C¿2¥yb'²ú”qÜno×÷72ý3MLiŽëb,„“n­òhVÜh)bÊ~lá6;¦ ¡¶jd‡“n®3¬+#ðð`XHb1€˜"¦Âa¾\1J¼+<ºc›æ8OÉð|ÕV—ÒŽi—Xí :g*[˜r²KSå¤à˜RuÆQ!Ü e_ÖΣ ;”—.¤²æÏ8Ÿ/rüŒsO@b ¦@LÕ.¦ôˆs£ Ï*TÖñ8-àÄï´c¦=Ìç 0½Ò˜rRKSö!;#â0_yüœu(1gÝ®3†Lî'ë8$™ðû32åsºôrX9ž€Ä@L˜ªþa>#b•G–\ÌyN•ŒYiLi!+` c*8’’ÆTù/íÜ' »o/Çš}[á¯ûŒ˜ÒBÇàÉCLS1…yz&ääqï äA«Yùˆó™ÒŽYIL…½5B¶?1÷ÖÎÇz¿ùß¡Bî¿ô ¦à·?š ' SÄ@LSƒç­ôÊþZ®îcÄbŠ˜P1¥œ^ˆªö˜1€˜"¦ø8Ä@LaÇT6§K.ñ9Lšèù¼ä‹Œ'GÄ@LaØÆ”;ŒòFº“›5˜ˆ)€˜Â0Ž©lΰb(ÝÊ1S1bªSy]«jLYc:V»t_:@LĆìa¾¬ä =F•bJ6 {goicj–ùàELñ1ôÜ!¦ˆ©šž€®¢¨’“ɃV¦ì±ÔŠ¿p€˜ˆ) “˜ÒEËæÄH¹ªuΔ}¸sª€~ÄÔêí>Ä ¦ž;Ä1Uƒ˜ÊJ6[å˜ÊfÝ ¨é¬PÄ@Laè®L•ÉUx²¸?¦T9Çäü)€˜ˆ) —Ã|ürb ¦@Lñq2ÀPŠ©7Í/b ˆ© ç1ELSÀ°Œ©^b HSîç1ELÕ ¦Ô{BUòþRQŸÍÇçöÄ0bª—˜"¦rL%{k>j¨BL5öúS@‚˜ xîSÄ1 ØzË|p"¦€d1å}î¼ELS5)­üvîø±?j&üÍSÇ”zß©ÔoÅàŸga.…ùîÃȹßï "1õ1Sh1•/‡‡:å·HpÇP!\¼ñ“*¦¬÷ r¬„y¯Ç£eÏÓù8ߪyöoµ ¦b ÄTe‡ù\aâ>‘<ì„òT1å[1 ´Ð•©¬ûqöØ®ýðŽëb15Û|ð"¦€ø˜ zîSÄÔ!‰©¸Ð9”1Uz\iÞ¬JaÆÔš^b HSÏbŠ˜ªsL?j&æÜ£ªæ³?ŠÆ·²ä ;ëp¤;š¬}™!Ūˆ)Ä15`bÊwzóÅ€S†K'®'>ÿ \15Ç|ð"¦€ø˜ zîSÄÔ0~ôø·pàm0tcj‡1$‰)ÿs‡˜"¦ˆ©lpDåóyÞ C6¦òkwXæ8S@|LÙÏ›¼1ELñÙ|À0Ž)'b HSybŠ˜"¦bêmóÀ‹˜âc*è¹CLSÄ0cªi‡1$ˆ©€ç1ELSÀ0©¹ÄSsž;Ä1ELÃ0¦æS1b @å1õκ>ÄSAÏbŠ˜"¦bŠ˜ˆ)SÒÄÔ<óÀ‹˜âc*è¹CLSÄ0cªy§1$ˆ©€ç1ELSÀ0Œ©ùæ €1ÄÇTÐs‡˜"¦ˆ)`ÆÔ»ëwúS@|L=wˆ)bŠ˜†eLíò!¦€$1åîSÄ1 ØZ`¾xS@|L=wˆ)bŠ˜†aL5´ìò!¦€ø˜ zîSÄÔÀŠ©¬)ï Õø—÷Ð#æ’OÏä%ŸÑJ×5ëzN²Öu­x»“nÞ§|›îKs]ÏJÎóXÝÚf˜¼óPcå¬ËYóöòcÜ÷ÕçbŠL€˜"¦oLe=Á¢BʨCLy÷Ÿ-˜ÓÍ`1\¤®Û1eË9îã gx9cÊ)Íqÿ¬u?Í`åñ5ßÜ aeŸ5›õ„•ÆiÅÔÂÖÝ>ÄSAÏbŠ˜ª~LyCÄ)*ŽržÉÛѤ;c¯™þ™&¦2Ž}™(¦rVøG·BJOSºTF1r4Ç8a+G*ôÒ˜öÊ“^#ãY‰ Úî- ‡˜Zd¾xS@|L=wˆ©¡SK–,‘3fÈÃ?ìóÈ#”¾:=÷Üs²|ùò*¯LižØÉ†¬>e·ÛÛuÇýLÿÆLSšãz…‡ á¤[«<š7ZŠ˜²[¸ÍŽ©Bè„­Ùá¤[‡ë kÅÊ<<RA‡1ôcjqÛnb ˆ© ç15´bJ…Tgg§¼÷Þ{%°¨ÕªÞÞf4õJOÏvÙ¶­K6mÚ,+W®–^x¡‡ùrÅ(ñ®ðèŽmšã<%ÃóUX]J;¦=^>`µ+蜩l5bÊyÈ.mL•W‚cJ=ÖG…p+”}Y8*ìP^ºÊš?ã|¾Èñ3Î<[L-ißíCLñ1ôÜ!¦†VL=øàƒ®ˆÚ·¯OöìÝ+»wï‘-[¶šñÔ!í6IKK»¬Z½FæÍoÆÆµòÀï¨aLéçFžU¨¬ãqZÀ‰ßiÇL{˜Ï`z¥1å<¤–>¦ìCvFÄa¾òø9ëPbκ]+f ;™Ü;NÖqH2á÷gdÊçtéå°2r<_Líñ!¦€$1åîSC/¦ì•¨¾>3¤öì•]»vËŽ;¥½}“¬_ß&MëÖ›Õ$ -•¹sßµV¦ªSÎs–‚Vyô€`ÉÅœçTɘ•Æ”²–0¦‚#)iL•ÿÒÎ}ºûör¬Ù·þºÏ‰)-t ž<Ã1¦–nØãCLñ1ôÜ!¦†fLíß¿_öîÝW ©žž^YßÒ&k×6˪UkdÙ²UÒаDÞ~{¾¬X±ªÊ1¥…œ‹¤…üå\ÐjV>â|¦´cVSaoíOLŽ5‚ó±ÞÃoþ·F(„û/ý‚‚)øí‚æÂ èÃ)¦–™/^ÄSAÏbŠ˜ª~L%¡Wö×ru¢1µ|ãb ˆ© ç1ELÕ7¦ô€“À«QÕâ1µbã^b ˆ© ç1ELš•)‡4¦VnÚëCLñ1ôÜ!¦ˆ©šÆT6§K.{(0šèyãÏ¡¿sQËK¾ÈÈeÞS1…ASîù¼Që“›ÃB¥61¥éŽï-Ÿôsíú?µß°`Šº ðÆÔªÍ{}ˆ) >¦‚ž;Ä1U“˜Êæ ë…½~+SõŒ©¬ùÃȺÃJ׈) ª˜Zm¾xS@|L=wˆ)bªf1¥#]LcCˉa¯úX‘’•œ šn­xå\«DÞÕ"ÿ˜®qÔŽÇéZø\ÂBÅú^­¼ÅYø>ó®ï½Ÿ1úýUÿ÷ÀÛ* ®˜jìØçCLñ1ôÜ!¦ˆ©æ³ÃÀHSŽC‚Yõb^|¼uÙóî݆s쨕)ǘV\ÇqŽï»ñ¸€ñ“GJø˜î*üü¼ã¦Š©Èï¯V¿ –˜Zc¾xS@|L=wˆ)bª¦' Ûç%;üä "÷Jˆ+Tˆ¸VnæsÆ€oEÅ0«(¤âÆôœc²–*¦"¿¿Zý0hbjË>b HSÏbŠ˜ªqL™±"É_ÄK/þ¥q‚VCêSIÃ$]LÅw(c*Ùïƒ%¦ÖšÏW/b ˆ)ûùÒÔÙWºLLS5ˆ©¬d³•Æ”ãEÛ: æ~±¶‚Á0VC*ˆ©ØÃ|á1UÙÉÞñcÆ{TÕÃ|Ùâ9Q?ËJ,1¥^¼ˆ) >¦‚ž;Ä1U“•)ÍsRxšŸ #âqçý¿]AÌ SÜ èIÉ¥9=fµ«j‡ùâN@Œ©Ê1µ®³¯`k_é21ÄÇTé¹ã@LSµ?ÌWÅ7µäÏÿÆ›‹ò{1µµÏ‡˜ÄTÀs‡˜"¦ÐÇÉ„¿ˆ—VøüCSü†NL5›/^ÄSAÏbŠ˜â³ù€aSë·õYšˆ) >¦œÏû21ELU=¦ÔÊ¿` ÇÔ~b HSþç1EL±2 ØjéÚ/-Û܈) >¦¬ç‹çùCLS¬LÃ5¦<ˆ) ALÄSAÏbŠ˜be †1µ e—Kƒ‰˜âc*è¹CLSÄ0 cj–ù¢0kµ1ÄÇTÐs‡˜"¦ˆ)€˜"¦b Äb ¦@L ¦b Äb ¦@LS1€˜"¦ˆ)Ä@L˜@LĈ)Ä@L˜"¦b ¦ˆ)bŠ˜ˆ)b ¦@L ¦b Äb ¦@LS1S ¦ˆ)€˜"¦bŠ˜"¦S1b 1S ¦S1bŠ˜ˆ)Ä1EL ¦b Äb ¦@L ¦b Ä1S1ELSÄ@LS1b 1S ¦S1bŠ˜ˆ)€˜1ELÄbŠ˜"¦S1b 1S ¦S1bŠ˜ˆ)€˜"¦ˆ)b 1S ¦S1b 1S ¦ˆ)€˜ˆ)bŠ˜"¦bŠ˜ˆ)Sˆ)€˜1€˜ˆ)Sˆ)€˜1ELÄbŠ˜"¦S1b 1S81µÿK__ŸV]]=ÒÙ¹M:::eãÆill"¦bŠ˜ˆ)„ÅÔ{ïýE¾|Ê)ré%—È/®¿¾dê”)ò§—^’ÖÖ Ä@LS1…¨˜ºâòËåÉ'ž™3g–Ìž=[/^LLÄ1Sà0b ¦Àa>Ä@LÃ|Ä@LÄ8ÌGLÄbŠ˜â0b ¦P•˜úͯm…Óœ9sJdÕªUÄ@LS1ó ¦b |œ b ¦@LS1S ¦ˆ)€˜@LSÄb ¦@L ¦b Äb ¦@LS1€˜"¦ˆ)Ä@L˜@LĈ)Ä@L˜"¦b ¦ˆ)bŠ˜ˆ)b ¦@L ¦b Äb ¦@Lñ‹ˆ)€˜1ELÄbŠ˜"¦S1b 1S ¦S1bŠ˜ˆ)€˜"¦ˆ)b ¦ˆ)€˜1€˜ˆ)Sˆ)€˜1ELÄ@Lño 1ELÄ1SÄ1€˜ˆ)Sˆ)€˜1€˜ˆ)SÄ@L ¦ˆ)b 1S ¦S1b 1S ¦ˆ)€˜ˆ)bŠ˜"¦bŠ˜ˆ)Sˆ)€˜1€˜ˆ)SÄ@LĈ)b ¦SÄ1€˜ˆ)Sˆ)€˜1€˜ˆ)SÄ@L ¦ˆ)b 1S ¦S1b 1S ¦ˆ)€˜ˆ)bŠ˜"¦bŠ˜ˆ)Sˆ)€˜1€˜ˆ)Sü"b ¦@LS1€˜"¦ˆ)Ä@L˜@LĈ)Ä@L˜"¦b ¦ˆ)bŠ˜ˆ)b ¦@Lè_L©ÕqäŠNþm!¦ˆ)€˜@L˜@LĈ)Ä@L˜@LĈ)b ¦SÄ1ÀCýàºø·…˜"¦1ELSÄ1ELbŠ˜ ¦ˆ)€ÁS}}}²gÏ^+¤¶oï•îîY·®E›ÌxZ-K–,—w,’9ùwˆ)gL©U);¤zz¶KWWlÝÚe†ÔZ+œ–,]. ‹åy döœ¹Ä€SÓ§O—ÎÎNÙ»woñßéíÝa­Nµ·o––6YßÒ*ÍÍ륩©YÖ¬i’E‹–ÈÓO?MLbª¡¡Á *µÒ”” ©7ß|“˜ÄÔ–-[¤««KvîÜ)»wïvÙ³gOé«“ZÅÚ·o1ˆ)b €˜ ¦ˆ)b SÄ1Pï˜R‘¤>^&ŒúØb $¦T0wÜqò¹Ï}Îrä‘Gʘ1cäŠ+®I“&Y·S1+SãÇ— &Èĉ­w<Ïçó¬L$9gʪk¯½Vž}öYYºti)¤8g ÀSÝÝݲk×.×Iæ*œT@͘1ÃRÄ€'¦z{{­)INû÷ï—÷Þ{ÏúêÜ®BJÅ1ˆ)3¦Ôª”II¨"¦1UŒ)uè.,šœñäELbÊŒ©°`R‡÷ì¯Aˆ)@L™1Kqˆ)@L™1¥¢¨RýŽ)SÄ1@LSÄ@µb é”b •ùÿwß{s¥6IEND®B`‚././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/index.rst0000664000000000000000000001272315074674453015144 0ustar00rootroot.. include:: icons.rst .. title:: Overview .. toctree:: :hidden: :titlesonly: :maxdepth: 1 getting_started tutorials/index changelog bugs_repo guide/index devguide/index packagingguide maintguide further contact .. image:: images/pygobject.svg :align: center :width: 400px :height: 98px | .. include:: ../README.rst :start-after: | :end-before: ---- If you want to write a Python application for `GNOME `__ or a Python GUI application using GTK, then PyGObject is the way to go. To get started, check out the "`GNOME Developer Documentation `__". For more information on specific libraries, check out the `GNOME Python API documentation `__. .. code:: python import sys import gi gi.require_version("Gtk", "4.0") from gi.repository import GLib, Gtk class MyApplication(Gtk.Application): def __init__(self): super().__init__(application_id="com.example.MyGtkApplication") GLib.set_application_name("My Gtk Application") def do_activate(self): window = Gtk.ApplicationWindow(application=self, title="Hello World") window.present() app = MyApplication() exit_status = app.run(sys.argv) sys.exit(exit_status) How does it work? ----------------- .. figure:: images/overview.svg :width: 600px :height: 222px :align: center :class: only-light .. figure:: images/overview-dark.svg :width: 600px :height: 222px :align: center :class: only-dark PyGObject uses `GLib `__, `GObject `__, `GIRepository `__, `libffi `__ and other libraries to access the C library (libgtk-4.so) in combination with the additional metadata from the accompanying typelib file (Gtk-4.0.typelib) and dynamically provides a Python interface based on that information. Who Is Using PyGObject? ----------------------- * `Anaconda `__ - an installation program used by Fedora, RHEL and others * `Apostrophe `__ - a Markdown editor * `Blanket `__ - listen to different sounds * `BleachBit `__ - delete unnecessary files from the system * `Bottles `__ - run Windows software on Linux * `Cambalache `__ - a user interface maker for GTK * `D-Feet `__ - an easy to use D-Bus debugger * `Deluge `__ - a BitTorrent client * `Dialect `__ - a translation app * `Drawing `__ - a drawing application * `Feeds `__ - an RSS/Atom feed reader * `Gajim `__ - a fully-featured XMPP client * `Gameeky `__ - a learning tool for making games and learning experiences * `Gaphor `__ - a simple modeling tool * `Getting Things GNOME! `__ - a personal task organizer * `Girens `__ - a Plex client for playing movies, TV shows and music from your Plex library * `GNOME Music `__ - a music player for GNOME * `GNOME Tweaks `__ - a tool to customize advanced GNOME options * `Gramps `__ - a genealogy program * `Komikku `__ - a manga reader * `Lollypop `__ - a modern music player * `Lutris `__ - a video game manager * `Meld `__ - a visual diff and merge tool * `Metadata Cleaner `__ - an application to view and clean metadata in files * `MyPaint `__ - a nimble, distraction-free, and easy tool for digital painters * `Nicotine+ `__ - a graphical client for the Soulseek peer-to-peer network * `Orca `__ - a flexible and extensible screen reader * `Paperwork `__ - a personal document manager * `Pithos `__ - a Pandora Radio client * `Pitivi `__ - a free and open source video editor * `Plots `__ - a graph plotting app * `Quod Libet `__ - a music library manager / player * `Secrets `__ - a password manager * `Setzer `__ - a LaTeX editor * `Terminator `__ - The Robot Future of Terminals * `Wike `__ - a Wikipedia reader The following applications or libraries use PyGObject for optional features, such as plugins or as optional backends: * `beets `__ - a music library manager and MusicBrainz tagger * `gedit `_- a GNOME text editor * `matplotlib `__ - a python 2D plotting library * `Totem `__ - a video player for GNOME ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/maintguide.rst0000664000000000000000000000221715074674453016160 0ustar00rootroot================ Maintainer Guide ================ Making a Release ---------------- #. Make sure the `meson.build` file contains the right version number #. Update the NEWS file #. Build new version using ``python3 -m build --sdist`` #. Commit NEWS as ``"release 3.X.Y"`` and push #. Tag with: ``git tag -s 3.X.Y -m "release 3.X.Y"`` #. Push tag with: ``git push origin 3.X.Y`` #. In case of a stable release, upload to PyPI: ``twine upload dist/pygobject-3.X.Y.tar.gz`` #. Commit post-release version bump to pyproject.toml #. Upload tarball: ``scp dist/pygobject-3.X.Y.tar.gz user@master.gnome.org:`` #. Install tarball: ``ssh user@master.gnome.org 'ftpadmin install pygobject-3.X.Y.tar.xz'`` #. In case the release happens on a stable branch copy the NEWS changes to the main branch Branching --------- Each cycle after the feature freeze, we create a stable branch so development can continue in the main branch unaffected by the freezes. #. Create the branch locally with: ``git checkout -b pygobject-3-2`` #. Push new branch: ``git push origin pygobject-3-2`` #. In main, update pyproject.toml to what will be the next version number (3.3.0) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/packagingguide.rst0000664000000000000000000000225215074674453016773 0ustar00rootrootPackaging Guide =============== PyGObject uses Meson, here are some notes on how to package PyGObject. Source packages can be found at https://download.gnome.org/sources/pygobject Existing Packages: * https://archlinux.org/packages/extra/x86_64/python-gobject * https://tracker.debian.org/pkg/pygobject * https://github.com/MSYS2/MINGW-packages/tree/master/mingw-w64-pygobject Building:: meson setup --prefix /usr --buildtype=plain _build -Dc_args=... -Dc_link_args=... meson compile -C _build meson test -C _build DESTDIR=/path/to/staging/root meson install -C _build Runtime dependencies: * glib * libgirepository (gobject-introspection) * libffi * Python 3 The overrides directory contains various files which includes various Python imports mentioning gtk, gdk etc. They are only used when the corresponding library is present, they are not direct dependencies. Build dependencies: * The runtime dependencies * cairo (optional) * pycairo (optional) * pkg-config * setuptools (optional) Test Suite dependencies: * The runtime dependencies * GTK 4 (optional) * pango (optional) * pycairo (optional) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/_static/custom.css0000664000000000000000000000073615074674453021004 0ustar00rootroot.toctree-wrapper .reference.external::after { content: url("data:image/svg+xml;charset=utf-8,%3Csvg width='16' height='16' xmlns='http://www.w3.org/2000/svg' viewBox='0 0 24 24' stroke-width='1.5' stroke='white' fill='none' stroke-linecap='round' stroke-linejoin='round'%3E%3Cpath d='M0 0h24v24H0z' stroke='none'/%3E%3Cpath d='M11 7H6a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h9a2 2 0 0 0 2-2v-5M10 14 20 4M15 4h5v5'/%3E%3C/svg%3E"); margin: 0 .25rem; vertical-align: middle; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gobject/basics.rst0000664000000000000000000001600615074674453020742 0ustar00rootroot.. currentmodule:: gi.repository Basics ====== .. hint:: In this example, we will use GTK widgets to demonstrate GObject capabilities. GObject Initialization ---------------------- GObjects are initialized like any other Python class. .. code:: python label = Gtk.Label() .. _basics-properties: Properties ---------- GObject has a powerful properties system. Properties describe the configuration and state of a gobject. Each gobject has its own particular set of properties. For example, a GTK button has the property ``label`` which contains the text of the label widget inside the button. You can specify the name and value of any number of properties as keyword arguments when creating an instance of a gobject. To create a label aligned to the right with the text "Hello World", use: .. code:: python label = Gtk.Label(label='Hello World', halign=Gtk.Align.END) which is equivalent to .. code:: python label = Gtk.Label() label.set_label('Hello World') label.set_halign(Gtk.Align.END) There are various ways of interacting with a gobject properties from Python, we already have seen the two first ways, these are setting them on initialization or using the getters and setters functions that the gobject might provide. Other option is to use :class:`GObject.Object` builtin methods :meth:`GObject.Object.get_property` and :meth:`GObject.Object.set_property`. Using these methods is more common when you have created a :class:`GObject.Object` subclass and you don't have getters and setters functions. .. code:: python label = Gtk.Label() label.set_property('label', 'Hello World') label.set_property('halign', Gtk.Align.END) print(label.get_property('label')) Instead of using getters and setters you can also get and set the gobject properties through the ``props`` property such as ``label.props.label = 'Hello World'``. This is equivalent to the more verbose methods that we saw before, and it's a more pythonic way of interacting with properties. To see which properties are available for a gobject you can ``dir`` the ``props`` property: .. code:: python widget = Gtk.Box() print(dir(widget.props)) This will print to the console the list of properties that a :class:`Gtk.Box` has. Property Bindings ^^^^^^^^^^^^^^^^^ GObject provides a practical way to bind properties of two different gobjects. This is done using the :meth:`GObject.Object.bind_property` method. The behavior of this binding can be controlled by passing a :class:`GObject.BindingFlags` of choice. :attr:`GObject.BindingFlags.DEFAULT` will update the target property every time the source property changes. :attr:`GObject.BindingFlags.BIDIRECTIONAL` creates a bidirectional binding; if either the property of the source or the property of the target changes, the other is updated. :attr:`GObject.BindingFlags.SYNC_CREATE` is similar to ``DEFAULT`` but it will also synchronize the values of the source and target properties when creating the binding. :attr:`GObject.BindingFlags.INVERT_BOOLEAN` works only for boolean properties and setting one property to ``True`` will result in the other being set to ``False`` and vice versa (this flag cannot be used when passing custom transformation functions to :meth:`GObject.Object.bind_property`). .. code:: python entry = Gtk.Entry() label = Gtk.Label() entry.bind_property('text', label, 'label', GObject.BindingFlags.DEFAULT) In this example **entry** is our source object and ``text`` the source property to bind. **label** is the target object and the namesake property ``label`` is the target property. Every time someone changes the ``text`` property of the entry the label ``label`` will be updated as well with the same value. Property Bindings with Transformations ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Sometimes you may want to bind two properties that are incompatible, or you simply need to apply some transformation between these values. For these scenarios :meth:`GObject.Object.bind_property` also accepts custom transformation functions that serve to this purpose. The transformation functions take as first argument the :class:`GObject.Binding` instance for this binding and as second argument the property value depending on the direction of the transformation. For ``transform_to`` this will be the value of the source property and for ``transform_from`` the value of the target property. Each function should return the value to be set in the other object's property, with the correct type. In this example we'll do an ``int`` to ``bool`` type conversion between two objects: .. code:: python def transform_to(_binding, value): return bool(value) # Return int converted to a bool def transform_from(_binding, value): return int(value) # Return bool converted to a int source.bind_property( 'int_prop', target, 'bool_prop', GObject.BindingFlags.BIDIRECTIONAL, transform_to, transform_from ) .. _basics-signals: Signals ------- GObject signals are a system for registering callbacks for specific events. A generic example is: .. code:: python handler_id = gobject.connect('event', callback, data) Firstly, *gobject* is an instance of a gobject we created earlier. Next, the event we are interested in. Each gobject has its own particular events which can occur. This means that when the gobject emits the event, the signal is issued. Thirdly, the *callback* argument is the name of the callback function. It contains the code which runs when signals of the specified type are issued. Finally, the *data* argument includes any data which should be passed when the signal is issued. However, this argument is completely optional and can be left out if not required. The function returns a number that identifies this particular signal-callback pair. It is required to disconnect from a signal such that the callback function will not be called during any future or currently ongoing emissions of the signal it has been connected to: .. code:: python gobject.disconnect(handler_id) When creating the callback function for a signal, the arguments it accepts will depend on the specific signal, but for a signal with no arguments it will look like this: .. code:: python def on_event(gobject, data): ... my_object.connect('event', on_event, data) Where ``gobject`` is the object that triggered the signal and ``data`` is the additional data that we previously passed to the :meth:`GObject.Object.connect` method. If the signal had arguments, they will come before the optional data argument. The ``notify`` signal ^^^^^^^^^^^^^^^^^^^^^ When any of a GObject's properties change, it will emit the ``notify`` signal. This is a "detailed" signal, meaning that you can listen to a subset of the signal, in this case a specific property. For example, you can connect to the signal in the form of ``notify::property-name``: .. code:: python def callback(label, _pspec): print(f'The label prop changed to {label.props.label}') label = Gtk.Label() label.connect('notify::label', callback) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gobject/examples/listmodel.py0000664000000000000000000000266015074674453023131 0ustar00rootrootfrom gi.repository import Gio, GObject class Person(GObject.Object): __gtype_name__ = 'Person' name = GObject.Property(type=str) def __init__(self, name): super().__init__() self.name = name class PersonsModel(GObject.GObject, Gio.ListModel): __gtype_name__ = 'PersonsModel' def __init__(self): super().__init__() # Private list to store the persons self._persons = [] ''' Interface Methods ''' def do_get_item(self, position): return self._persons[position] def do_get_item_type(self): return Person def do_get_n_items(self): return len(self._persons) ''' Our Helper Methods ''' def add(self, person): self._persons.append(person) ''' We must call Gio.ListModel.items_changed() every time we change the list. It's a helper to emit the "items-changed" signal, so consumer can know that the list changed at some point. We pass the position of the change, the number of removed items and the number of added items. ''' self.items_changed(len(self._persons) - 1, 0, 1) def remove(self, position): del self._persons[position] self.items_changed(position, 1, 0) def get_index_by_name(self, name): for i, person in enumerate(self._persons): if person.name == name: return i return None ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gobject/interfaces.rst0000664000000000000000000000351415074674453021621 0ustar00rootroot.. currentmodule:: gi.repository Interfaces ========== GObject interfaces are a way of ensuring that objects passed to C code have the right capabilities. When a GObject implements an interface it should implement an expected set of methods, properties and signals. In the Python sense, an interface is another class that is inherited. For example in GTK, :class:`Gtk.Image` supports various sources for the image that it will display. Some of these sources can be a :class:`Gio.Icon` or a :class:`Gdk.Paintable`, both are actually interfaces so you don't pass a direct instance of these, instead you should use some of the gobjects that implement the interface. For :class:`Gio.Icon` those can be :class:`Gio.ThemedIcon` that represents an icon from the icon theme, or :class:`Gio.FileIcon` that represents an icon created from an image file. Another important interface of reference is :class:`Gio.ListModel`. It represents a mutable list of :class:`GObject.Objects `. If you want to implement :class:`Gio.ListModel` you must implement three methods, these are :meth:`Gio.ListModel.get_item_type`, :meth:`Gio.ListModel.get_n_items` and :meth:`Gio.ListModel.get_item`. The interfaces methods that you should implement are exposed as :ref:`virtual methods `. With these methods any consumer can iterate the list and use the objects for any purpose. .. tip:: A generic implementation of :class:`Gio.ListModel` is :class:`Gio.ListStore`. It allows you to set the :class:`GObject.Object` type that it will store and provides methods to append, insert, sort, find and remove gobjects. Example ------- In this examples we'll be implementing a :class:`Gio.ListModel` in Python. It will store a custom :class:`GObject.Object` and provide some helper methods for it. .. literalinclude:: examples/listmodel.py :linenos: ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gobject/subclassing.rst0000664000000000000000000002452515074674453022020 0ustar00rootroot.. currentmodule:: gi.repository Subclassing =========== Before entering in detail, you should know some important points about GObject subclassing: 1. It is possible to subclass a :class:`GObject.Object`. Subclassing creates a new :class:`GObject.GType` which is connected to the new Python type. This means you can use it with API which takes :class:`GObject.GType`. 2. :class:`GObject.Object` only supports single inheritance, this means you can only subclass one :class:`GObject.Object`, but multiple Python classes. 3. The Python wrapper instance for a GObject.Object is always the same. For the same C instance you will always get the same Python instance. Inherit from GObject.GObject ---------------------------- A native GObject is accessible via :class:`GObject.Object`. It is rarely instantiated directly, we generally use an inherited classes. A :class:`Gtk.Widget` is an inherited class of a :class:`GObject.Object`. It may be interesting to make an inherited class to create a new widget, like a settings dialog. To inherit from :class:`GObject.Object`, you must call `super().__init__` in your constructor to initialize the gobjects you are inheriting, like in the example below: .. code:: python from gi.repository import GObject class MyObject(GObject.Object): def __init__(self): super().__init__(self) You can also pass arguments to `super().__init__`, for example to change some property of your parent gobject: .. code:: python class MyWindow(Gtk.Window): def __init__(self): super().__init__(self, title='Custom title') In case you want to specify the GType name we have to provide a ``__gtype_name__``: .. code:: python class MyWindow(Gtk.Window): __gtype_name__ = 'MyWindow' def __init__(self): super().__init__(self) Properties ---------- One of the nice features of GObject is its generic get/set mechanism for object properties. Any class that inherits from GObject.Object can define new properties. Each property has a type that never changes (e.g. ``str``, ``float``, ``int``...). Create new properties ^^^^^^^^^^^^^^^^^^^^^ A property is defined with a name and a type. Even if Python itself is dynamically typed, you can't change the type of a property once it is defined. A property can be created using :func:`GObject.Property`. .. code:: python from gi.repository import GObject class MyObject(GObject.Object): foo = GObject.Property(type=str, default='bar') property_float = GObject.Property(type=float) def __init__(self): super().__init__(self) Properties can also be read-only, if you want some properties to be readable but not writable. To do so, you can add some flags to the property definition, to control read/write access. Flags are :attr:`GObject.ParamFlags.READABLE` (only read access for external code), :attr:`GObject.ParamFlags.WRITABLE` (only write access), :attr:`GObject.ParamFlags.READWRITE` (public): .. there is also construct things, but they .. doesn't seem to be functional in Python .. code:: python foo = GObject.Property(type=str, flags=GObject.ParamFlags.READABLE) # not writable bar = GObject.Property(type=str, flags=GObject.ParamFlags.WRITABLE) # not readable You can also define new read-only properties with a new method decorated with :func:`GObject.Property`: .. code:: python from gi.repository import GObject class MyObject(GObject.Object): def __init__(self): super().__init__(self) @GObject.Property def readonly(self): return 'This is read-only.' You can get this property using: .. code-block:: python my_object = MyObject() print(my_object.readonly) print(my_object.get_property('readonly')) The API of :func:`GObject.Property` is similar to the builtin :py:class:`property`. You can create property setters in a way similar to Python property: .. code-block:: python class AnotherObject(GObject.Object): value = 0 @GObject.Property def prop(self): """Read only property.""" return 1 @GObject.Property(type=int) def prop_int(self): """Read-write integer property.""" return self.value @prop_int.setter def prop_int(self, value): self.value = value There is also a way to define minimum and maximum values for numbers: .. code-block:: python class AnotherObject(GObject.Object): value = 0 @GObject.Property(type=int, minimum=0, maximum=100) def prop_int(self): """Integer property with min-max.'""" return self.value @prop_int.setter def prop_int(self, value): self.value = value my_object = AnotherObject() my_object.prop_int = 200 # This will fail Alternatively you can use the more verbose `__gproperties__` class attribute to define properties: .. code:: python from gi.repository import GObject class MyObject(GObject.Object): __gproperties__ = { 'int-prop': ( int, # type 'integer prop', # nick 'A property that contains an integer', # blurb 1, # min 5, # max 2, # default GObject.ParamFlags.READWRITE # flags ), } def __init__(self): super().__init__(self) self.int_prop = 2 def do_get_property(self, prop): if prop.name == 'int-prop': return self.int_prop else: raise AttributeError('unknown property %s' % prop.name) def do_set_property(self, prop, value): if prop.name == 'int-prop': self.int_prop = value else: raise AttributeError('unknown property %s' % prop.name) For this approach properties must be defined in the ``__gproperties__`` class attribute, a dictionary, and handled in :meth:`GObject.Object.do_get_property` and :meth:`GObject.Object.do_set_property` :ref:`virtual methods `. .. hint:: Changes to custom properties are also signaled by the ``notify`` detailed signal. But remember that it will normalize your property name to hyphens instead of underscores, so you will write ``notify::prop-int`` and not ``notify::prop_int``. Signals ------- Each signal is registered in the type system together with the type on which it can be emitted: users of the type are said to connect to the signal on a given type instance when they register a function to be invoked upon the signal emission. Users can also emit the signal by themselves or stop the emission of the signal from within one of the functions connected to the signal. Create new signals ^^^^^^^^^^^^^^^^^^ New signals can be created by using the :func:`GObject.Signal` decorator. The decorated methods are the object method handlers, these will be called when the signal is emitted. The time at which the method handlers are invoked depends on the signal flags. :attr:`GObject.SignalFlags.RUN_FIRST` indicates that this signal will invoke the object method handler in the first emission stage. Alternatives are :attr:`GObject.SignalFlags.RUN_LAST` (the method handler will be invoked in the third emission stage) and :attr:`GObject.SignalFlags.RUN_CLEANUP` (invoke the method handler in the last emission stage). Signals can also have arguments, the number and type of each argument is defined as a tuple of types. Signals can be emitted using :meth:`GObject.Object.emit`. .. code:: python from gi.repository import GObject class MyObject(GObject.Object): def __init__(self): super().__init__(self) @GObject.Signal(flags=GObject.SignalFlags.RUN_LAST, arg_types=(int,)) def arg_signal(self, number): """Called every time the signal is emitted""" print('number:', number) @GObject.Signal def noarg_signal(self): """Called every time the signal is emitted""" print('noarg_signal') my_object = MyObject() def signal_callback(object_, number): """Called every time the signal is emitted until disconnection""" print(object_, number) my_object.connect('arg_signal', signal_callback) my_object.emit('arg_signal', 100) # emit the signal "arg_signal", with the # argument 100 my_object.emit('noarg_signal') Alternatively you can use the more verbose `__gsignals__` class attribute to define signals. When a new signal is created, a method handler can also be defined in the form of ``do_signal_name``, it will be called each time the signal is emitted. .. code:: python class MyObject(GObject.Object): __gsignals__ = { 'my_signal': ( GObject.SignalFlags.RUN_FIRST, # flag None, # return type (int,) # arguments ) } def do_my_signal(self, arg): print("method handler for `my_signal' called with argument", arg) .. _virtual-methods: Virtual Methods --------------- GObject and its based libraries usually have gobjects that expose virtual methods. These methods serve to override functionality of the base gobject or to run code on a specific scenario. In that case you should call the base gobject virtual method to preserve its original behavior. In PyGObject these methods are prefixed with ``do_``. Some examples are :meth:`GObject.Object.do_get_property` or :meth:`Gio.Application.do_activate`. .. important:: The Python :py:class:`super` class only works for the immediate parent. If you want to chain some virtual method from a object that is more up in the hierarchy of the one you are subclassing you must call the method directly from the object class: ``SomeOject.method(self, args)``. .. code:: python class SomeOject(OtherObject): ... class MyObject(SomeOject): def __init__(self): super().__init__(self) def do_virtual_method(self): # Call the original method to keep its original behavior super().do_virtual_method(self) # Run some extra code ... """This is a virtual method from SomeOject parent""" def do_other(self): OtherObject.do_other(self) # We can't use super() ... ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gobject.rst0000664000000000000000000000125115074674453017472 0ustar00rootrootGObject ======= GObject is the foundation for object-oriented programming in the GNOME libraries. For example :class:`GObject.Object` is the base providing the common attributes and methods for all object types in GTK and the other libraries in this guide. The :class:`GObject.Object` class provides methods for object construction and destruction, property access methods, and signal support. This chapter will introduce some important aspects about the GObject implementation in Python. .. toctree:: :maxdepth: 3 :caption: Contents gobject/basics gobject/subclassing gobject/interfaces Weak References ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gtk3.rst0000664000000000000000000000035115074674453016725 0ustar00rootrootGTK3 ==== You can find help about using Python with GTK3 in the following resources. * `The Python GTK+ 3 Tutorial `_ * `PyGObject API Reference `_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gtk4/application.rst0000664000000000000000000000611415074674453021234 0ustar00rootroot.. currentmodule:: gi.repository Application =========== .. seealso:: For more detailed information about ``Gtk.Application`` checkout the :devdocs:`Using GtkApplication ` tutorial. :class:`Gtk.Application` is the foundation for creating GTK apps. It encompasses many repetitive tasks that a modern application needs such as handling multiple instances, D-Bus activation, opening files, command line parsing, startup/shutdown, menu management, window management, and more. In this example we will be also using :class:`Gtk.ApplicationWindow`, it provides some extra features over regular :class:`Gtk.Window` for main application windows. Actions ------- :class:`Gio.Action` is a way to expose any single task your application or widget does by a name. These actions can be disabled/enabled at runtime and they can either be activated or have a state changed (if they contain state). The reason to use actions is to separate out the logic from the UI. For example this allows using a menubar on OSX and a gear menu on GNOME both simply referencing the name of an action. The main implementation of this you will be using is :class:`Gio.SimpleAction` which will be demonstrated later. Many classes such as :class:`Gio.MenuItem` and :class:`Gtk.Actionable` interface implementations like :class:`Gtk.Button` support properties to set an action name. These actions can be grouped together into a :class:`Gio.ActionGroup` and when these groups are added to a widget with :meth:`Gtk.Widget.insert_action_group()` they will gain a prefix. Such as "win" when added to a :class:`Gtk.ApplicationWindow`. You will use the full action name when referencing it such as "app.about" but when you create the action it will just be "about" until added to the application. You can also very easily make keybindings for actions by setting the `accel` property in the :class:`Gio.Menu` file or by using :meth:`Gtk.Application.set_accels_for_action()`. Menus ----- Your menus should be defined in XML using :class:`Gio.Menu` and would reference the previously mentioned actions you defined. :class:`Gtk.Application` allows you to set a menu via :meth:`Gtk.Application.set_menubar()`. If you make use of :class:`Gio.Resource` this can automatically load the menu, otherwise you can set them manually. A detailed example is shown below. Command Line ------------ When creating your application it takes a flag property of :class:`Gio.ApplicationFlags`. Using this you can let it handle everything itself or have more custom behavior. You can use ``HANDLES_COMMAND_LINE`` to allow custom behavior in :meth:`Gio.Application.do_command_line()`. In combination with :meth:`Gio.Application.add_main_option()` to add custom options. Using ``HANDLES_OPEN`` will do the work of simply taking file arguments for you and let you handle it in :meth:`Gio.Application.do_open()`. If your application is already open these will all be sent to the existing instance unless you use ``NON_UNIQUE`` to allow multiple instances. Example ------- .. image:: images/application.png .. literalinclude:: examples/application.py :linenos: ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gtk4/basics.rst0000664000000000000000000000252415074674453020176 0ustar00rootroot.. currentmodule:: gi.repository GTK4 Basics =========== Main loop and Signals --------------------- Like most GUI toolkits, GTK uses an event-driven programming model. When the user is doing nothing, GTK+ sits in the main loop and waits for input. If the user performs some action - say, a mouse click - then the main loop "wakes up" and delivers an event to GTK. When widgets receive an event, they frequently emit one or more signals. Signals notify your program that "something interesting happened" by invoking functions you've connected to the signal. Such functions are commonly known as *callbacks*. When your callbacks are invoked, you would typically take some action - for example, when an Open button is clicked you might display a file chooser dialog. After a callback finishes, GTK will return to the main loop and await more user input. :class:`Gtk.Application` will run the main loop for you, so you don't need to worry about it. A :class:`Gtk.Widget` it's also a :class:`GObject.Object`, so to know how to interact with these signals you must read the :ref:`GObject Basics `. .. seealso:: `Library initialization and main loop`_ in GTK documentation. Properties ---------- Read: :ref:`GObject Basics: Properties `. .. _Library initialization and main loop: https://docs.gtk.org/gtk4/initialization.html ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gtk4/clipboard.rst0000664000000000000000000000275715074674453020701 0ustar00rootroot.. currentmodule:: gi.repository Clipboard ========= :class:`Gdk.Clipboard` provides a storage area for a variety of data, including text and images. Using a clipboard allows this data to be shared between applications through actions such as copying, cutting, and pasting. There are multiple clipboard selections for different purposes. In most circumstances, the selection named ``CLIPBOARD`` is used for everyday copying and pasting. ``PRIMARY`` is another common selection which stores text selected by the user with the cursor. :class:`Gdk.Display` will allow us to access these different clipboards. You can get the default display with :meth:`Gdk.Display.get_default`, then get the clipboard that you want; :meth:`Gdk.Display.get_clipboard` for ``CLIPBOARD`` and :meth:`Gdk.Display.get_primary_clipboard` for ``PRIMARY``. You can set any simple value like text with :meth:`Gdk.Clipboard.set`. For more complex data you must use the :meth:`Gdk.Clipboard.set_content` method were you have to pass a :class:`Gdk.ContentProvider`. A content provider is usually created using :meth:`Gdk.ContentProvider.new_for_value` where you only pass the value. To read the clipboard values :class:`Gdk.Clipboard` provides three async methods. For textual or image data use :meth:`Gdk.Clipboard.read_text_async` or :meth:`Gdk.Clipboard.read_texture_async`. For other data use :meth:`Gdk.Clipboard.read_value_async`. Example ------- .. image:: images/clipboard.png .. literalinclude:: examples/clipboard.py :linenos: ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gtk4/controls/buttons.rst0000664000000000000000000000357115074674453022276 0ustar00rootroot.. currentmodule:: gi.repository Buttons ======= Button ------ The Button widget is another commonly used widget. It is generally used to attach a function that is called when the button is pressed. The :class:`Gtk.Button` widget can hold any valid child widget. That is it can hold most any other standard :class:`Gtk.Widget`. The most commonly used child is the :class:`Gtk.Label`. Normally you will use :attr:`Gtk.Button.props.label` to set the button label, or :attr:`Gtk.Button.props.icon_name` if you want an icon instead. Usually, you want to connect to the button's ``clicked`` signal which is emitted when the button has been pressed and released. Example ^^^^^^^ .. image:: images/button.png .. literalinclude:: examples/button.py :linenos: ToggleButton ------------ A :class:`Gtk.ToggleButton` is very similar to a normal :class:`Gtk.Button`, but when clicked they remain activated, or pressed, until clicked again. When the state of the button is changed, the `toggled` signal is emitted. To retrieve the state of the :class:`Gtk.ToggleButton`, you can use :attr:`Gtk.ToggleButton.props.active`. This returns ``True`` if the button is "down". You can also set the toggle button's state, with :attr:`Gtk.ToggleButton.props.active`. Note that, if you do this, and the state actually changes, it causes the "toggled" signal to be emitted. Example ^^^^^^^ .. image:: images/togglebutton.png .. literalinclude:: examples/togglebutton.py :linenos: LinkButton ---------- A :class:`Gtk.LinkButton` is a :class:`Gtk.Button` with a hyperlink, similar to the one used by web browsers, which triggers an action when clicked. It is useful to show quick links to resources. The URI bound to a :class:`Gtk.LinkButton` can be set specifically using :attr:`Gtk.LinkButton.props.uri`. Example ^^^^^^^ .. image:: images/linkbutton.png .. literalinclude:: examples/linkbutton.py :linenos: ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gtk4/controls/check-radio-buttons.rst0000664000000000000000000000163615074674453024445 0ustar00rootrootCheck & Radio Buttons ===================== A :class:`Gtk.CheckButton` places a label next to an indicator. Check or Radio buttons are created through :class:`Gtk.CheckButton`, you create one or another depending grouping. :class:`Gtk.CheckButton` can be grouped together, to form mutually exclusive groups so only one of the buttons can be toggled at a time, this create what we usually refer to as a radio button. In addition to "on" and "off", :class:`Gtk.CheckButton` can be an "in between" state that is neither on nor off. This can be used e.g. when the user has selected a range of elements (such as some text or spreadsheet cells) that are affected by a check button, and the current values in that range are inconsistent. For this purpose use :attr:`Gtk.CheckButton.props.inconsistent`. Example ------- .. image:: images/check_radio_buttons.png .. literalinclude:: examples/check_radio_buttons.py :linenos: ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gtk4/controls/dropdown.rst0000664000000000000000000000341715074674453022433 0ustar00rootroot.. currentmodule:: gi.repository DropDown ======== :class:`Gtk.DropDown` allows the user to choose an item from a list of options. They are preferable to having many radio buttons on screen as they take up less room. To populate its options :class:`Gtk.DropDown` uses a :class:`Gio.ListModel`. :class:`Gio.ListModel` it's an interface that represents a mutable list of :class:`GObject.Objects `. For text-only uses cases GTK provides :class:`Gtk.StringList`, a list model that wraps an array of strings wrapped on :class:`Gtk.StringObject` and :class:`Gtk.DropDown` knows how to use it. :class:`Gtk.DropDown` can optionally allow search in the popup, which is useful if the list of options is long. To enable the search entry, use :attr:`Gtk.DropDown.props.enable_search`. .. attention:: Currently :class:`Gtk.DropDown` search only works fine in Python if you are using a :class:`Gtk.StringList`. If you use custom list models with custom gobjects you must provide a :class:`Gtk.Expression` through :attr:`Gtk.DropDown.props.expression` so :class:`Gtk.DropDown` can know how to filter the gobjects. The problem is :class:`Gtk.Expression` is broken in PyGObject for now (`see bug report `_). So search won´t work for at all. :class:`Gtk.DropDown` stores the selected item from the list model in :attr:`Gtk.DropDown.props.selected_item`, and the position of that item on :attr:`Gtk.DropDown.props.selected`. To know when the selection has changed just connect to ``notify::selected-item`` or ``notify::selected``. Example ^^^^^^^ We are creating a simple :class:`Gtk.DropDown` using :class:`Gtk.StringList`. .. image:: images/dropdown.png .. literalinclude:: examples/dropdown.py :linenos: ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gtk4/controls/entries.rst0000664000000000000000000000623615074674453022252 0ustar00rootroot.. currentmodule:: gi.repository Entries ======= Entries allows the user to enter text. GTK provides a few entry widgets for different use cases. Those are the generic :class:`Gtk.Entry`, :class:`Gtk.PasswordEntry` and :class:`Gtk.SearchEntry`. Although none of these widgets derive from each other, they implement the :class:`Gtk.Editable` :doc:`interface `, so they share some properties and methods. You can change and get the contents with the :attr:`Gtk.Editable.props.text` property. You can also limit the number of characters the entry can take with :attr:`Gtk.Editable.props.max_width_chars`. Occasionally you might want to make an Entry widget read-only. This can be done by setting :attr:`Gtk.Editable.props.editable` to ``False``. Generic Entry ------------- :class:`Gtk.Entry` is the standard entry. :class:`Gtk.Entry` can be set to show a invisible character using :attr:`Gtk.Entry.props.visibility` and :attr:`Gtk.Entry.props.invisible_char`, this is useful to hide the text of the entry when it is used for example to retrieve passwords. Though :ref:`password-entry` exist for this specific use case. :class:`Gtk.Entry` has the ability to display progress or activity information behind the text. This is similar to :class:`Gtk.ProgressBar` widget and is commonly found in web browsers to indicate how much of a page download has been completed. To make an entry display such information, use :attr:`Gtk.Entry.props.progress_fraction`, :attr:`Gtk.Entry.props.progress_pulse_step`, or :meth:`Gtk.Entry.progress_pulse`. Additionally, a :class:`Gtk.Entry` can show icons at either side of the entry. These icons can be activatable by clicking, can be set up as drag source and can have tooltips. To add an icon, use :meth:`Gtk.Entry.set_icon_from_icon_name` or one of the various other properties and methods that set an icon from an icon name, :class:`Gio.Icon`, or a :class:`Gdk.Paintable`. To set a tooltip on an icon, use :meth:`Gtk.Entry.set_icon_tooltip_text` or the corresponding function for markup. Entries can have a placeholder text, just use :attr:`Gtk.Entry.props.placeholder_text`. .. _password-entry: Password Entry -------------- :class:`Gtk.PasswordEntry` brings some features for password handing. It can show a button to toggle the visibility of the text if you set :attr:`Gtk.PasswordEntry.props.show_peek_icon` to ``True``. Search Entry ------------ :class:`Gtk.SearchEntry` is an entry specially designed for use as a search entry. :class:`Gtk.SearchEntry` allows you to implement the popular "type to search" feature. You can use :meth:`Gtk.SearchEntry.set_key_capture_widget` to set the parent widget that will redirect its key events to the entry. :class:`Gtk.SearchEntry` has the :func:`search-changed ` signal, it differs from :class:`Gtk.Editable`'s :func:`changed ` in the sense that it gets emitted after a short delay that you can configure with :attr:`Gtk.SearchEntry.props.search_delay`. This way you can get reactive searching without over loading your backend. Example ------- .. image:: images/entries.png .. literalinclude:: examples/entries.py :linenos: ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gtk4/controls/examples/button.py0000664000000000000000000000221515074674453023543 0ustar00rootrootimport gi gi.require_version('Gtk', '4.0') from gi.repository import Gtk class ButtonWindow(Gtk.ApplicationWindow): def __init__(self, **kargs): super().__init__(**kargs, title='Button Demo') hbox = Gtk.Box(spacing=6) self.set_child(hbox) button = Gtk.Button.new_with_label('Click Me') button.connect('clicked', self.on_click_me_clicked) hbox.append(button) button = Gtk.Button.new_with_mnemonic('_Open') button.connect('clicked', self.on_open_clicked) hbox.append(button) button = Gtk.Button.new_with_mnemonic('_Close') button.connect('clicked', self.on_close_clicked) hbox.append(button) def on_click_me_clicked(self, _button): print('[Click me] button was clicked') def on_open_clicked(self, _button): print('[Open] button was clicked') def on_close_clicked(self, _button): print('Closing application') self.close() def on_activate(app): win = ButtonWindow(application=app) win.present() app = Gtk.Application(application_id='com.example.App') app.connect('activate', on_activate) app.run(None) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gtk4/controls/examples/check_radio_buttons.py0000664000000000000000000000271015074674453026241 0ustar00rootrootimport gi gi.require_version('Gtk', '4.0') from gi.repository import Gtk class CheckButtonWindow(Gtk.ApplicationWindow): def __init__(self, **kargs): super().__init__(**kargs, title='CheckButton Demo') box = Gtk.Box(spacing=6) self.set_child(box) check = Gtk.CheckButton(label='Checkbox') check.connect('toggled', self.on_check_toggled) box.append(check) radio1 = Gtk.CheckButton(label='Radio 1') radio1.connect('toggled', self.on_radio_toggled, '1') box.append(radio1) radio2 = Gtk.CheckButton(label='Radio 2') radio2.set_group(radio1) radio2.connect('toggled', self.on_radio_toggled, '2') box.append(radio2) radio3 = Gtk.CheckButton.new_with_mnemonic('R_adio 3') radio3.set_group(radio1) radio3.connect('toggled', self.on_radio_toggled, '3') box.append(radio3) def on_check_toggled(self, check): if check.props.active: state = 'on' else: state = 'off' print('Checkbox was turned', state) def on_radio_toggled(self, radio, name): if radio.props.active: state = 'on' else: state = 'off' print('Radio', name, 'was turned', state) def on_activate(app): win = CheckButtonWindow(application=app) win.present() app = Gtk.Application(application_id='com.example.App') app.connect('activate', on_activate) app.run(None) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gtk4/controls/examples/dropdown.py0000664000000000000000000000176715074674453024077 0ustar00rootrootimport gi gi.require_version('Gtk', '4.0') from gi.repository import Gtk class DropDownWindow(Gtk.ApplicationWindow): def __init__(self, **kargs): super().__init__(**kargs, title='DropDown Demo') dropdown = Gtk.DropDown() dropdown.connect('notify::selected-item', self.on_string_selected) self.set_child(dropdown) strings = Gtk.StringList() dropdown.props.model = strings items = 'This is a long list of words to populate the dropdown'.split() # Populate the list for item in items: strings.append(item) def on_string_selected(self, dropdown, _pspec): # Selected Gtk.StringObject selected = dropdown.props.selected_item if selected is not None: print('Selected', selected.props.string) def on_activate(app): win = DropDownWindow(application=app) win.present() app = Gtk.Application(application_id='com.example.App') app.connect('activate', on_activate) app.run(None) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gtk4/controls/examples/entries.py0000664000000000000000000000621015074674453023700 0ustar00rootrootimport gi gi.require_version('Gtk', '4.0') from gi.repository import Gtk, GLib class EntryWindow(Gtk.ApplicationWindow): def __init__(self, **kargs): super().__init__(**kargs, title='Entry Demo') self.set_size_request(200, 100) self.timeout_id = None header = Gtk.HeaderBar() self.set_titlebar(header) vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6) vbox.props.margin_start = 24 vbox.props.margin_end = 24 vbox.props.margin_top = 24 vbox.props.margin_bottom = 24 self.set_child(vbox) # Gtk.SearchEntry search = Gtk.SearchEntry() search.props.placeholder_text = 'Search Entry' search.set_key_capture_widget(self) header.set_title_widget(search) self.set_focus(search) # Gtk.Entry self.entry = Gtk.Entry() self.entry.set_text('Hello World') vbox.append(self.entry) hbox = Gtk.Box(spacing=6) vbox.append(hbox) self.check_editable = Gtk.CheckButton(label='Editable') self.check_editable.connect('toggled', self.on_editable_toggled) self.check_editable.props.active = True hbox.append(self.check_editable) self.check_visible = Gtk.CheckButton(label='Visible') self.check_visible.connect('toggled', self.on_visible_toggled) self.check_visible.props.active = True hbox.append(self.check_visible) self.pulse = Gtk.CheckButton(label='Pulse') self.pulse.connect('toggled', self.on_pulse_toggled) hbox.append(self.pulse) self.icon = Gtk.CheckButton(label='Icon') self.icon.connect('toggled', self.on_icon_toggled) hbox.append(self.icon) # Gtk.PasswordEntry pass_entry = Gtk.PasswordEntry() pass_entry.props.placeholder_text = 'Password Entry' pass_entry.props.show_peek_icon = True pass_entry.props.margin_top = 24 vbox.append(pass_entry) def on_editable_toggled(self, button): value = button.get_active() self.entry.set_editable(value) def on_visible_toggled(self, button): self.entry.props.visibility = button.props.active def on_pulse_toggled(self, button): if button.get_active(): self.entry.props.progress_pulse_step = 0.2 # Call self.do_pulse every 100 ms self.timeout_id = GLib.timeout_add(100, self.do_pulse) else: # Don't call self.do_pulse anymore GLib.source_remove(self.timeout_id) self.timeout_id = None self.entry.props.progress_pulse_step = 0 def do_pulse(self): self.entry.progress_pulse() return True def on_icon_toggled(self, button): if button.props.active: icon_name = 'system-search-symbolic' else: icon_name = None self.entry.set_icon_from_icon_name( Gtk.EntryIconPosition.PRIMARY, icon_name ) def on_activate(app): win = EntryWindow(application=app) win.present() app = Gtk.Application(application_id='com.example.App') app.connect('activate', on_activate) app.run(None) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gtk4/controls/examples/linkbutton.py0000664000000000000000000000105015074674453024415 0ustar00rootrootimport gi gi.require_version('Gtk', '4.0') from gi.repository import Gtk class LinkButtonWindow(Gtk.ApplicationWindow): def __init__(self, **kargs): super().__init__(**kargs, title='LinkButton Demo') button = Gtk.LinkButton( uri='https://www.gtk.org', label='Visit GTK Homepage' ) self.set_child(button) def on_activate(app): win = LinkButtonWindow(application=app) win.present() app = Gtk.Application(application_id='com.example.App') app.connect('activate', on_activate) app.run(None) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gtk4/controls/examples/spinbutton.py0000664000000000000000000000302415074674453024434 0ustar00rootrootimport gi gi.require_version('Gtk', '4.0') from gi.repository import Gtk class SpinButtonWindow(Gtk.ApplicationWindow): def __init__(self, **kargs): super().__init__(**kargs, title='SpinButton Demo') hbox = Gtk.Box(spacing=6) self.set_child(hbox) adjustment = Gtk.Adjustment( upper=100, step_increment=1, page_increment=10 ) self.spinbutton = Gtk.SpinButton() self.spinbutton.props.adjustment = adjustment self.spinbutton.connect('value-changed', self.on_value_changed) hbox.append(self.spinbutton) check_numeric = Gtk.CheckButton(label='Numeric') check_numeric.connect('toggled', self.on_numeric_toggled) hbox.append(check_numeric) check_ifvalid = Gtk.CheckButton(label='If Valid') check_ifvalid.connect('toggled', self.on_ifvalid_toggled) hbox.append(check_ifvalid) def on_value_changed(self, _scroll): print(self.spinbutton.get_value_as_int()) def on_numeric_toggled(self, button): self.spinbutton.props.numeric = button.props.active def on_ifvalid_toggled(self, button): if button.get_active(): policy = Gtk.SpinButtonUpdatePolicy.IF_VALID else: policy = Gtk.SpinButtonUpdatePolicy.ALWAYS self.spinbutton.props.update_policy = policy def on_activate(app): win = SpinButtonWindow(application=app) win.present() app = Gtk.Application(application_id='com.example.App') app.connect('activate', on_activate) app.run(None) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gtk4/controls/examples/switch.py0000664000000000000000000000221715074674453023533 0ustar00rootrootimport gi gi.require_version('Gtk', '4.0') from gi.repository import Gtk class SwitcherWindow(Gtk.ApplicationWindow): def __init__(self, **kargs): super().__init__(**kargs, title='Switch Demo') hbox = Gtk.Box(spacing=6, homogeneous=True) hbox.props.margin_top = 24 hbox.props.margin_bottom = 24 self.set_child(hbox) switch = Gtk.Switch() switch.connect('notify::active', self.on_switch_activated) switch.props.active = False switch.props.halign = Gtk.Align.CENTER hbox.append(switch) switch = Gtk.Switch() switch.connect('notify::active', self.on_switch_activated) switch.props.active = True switch.props.halign = Gtk.Align.CENTER hbox.append(switch) def on_switch_activated(self, switch, _gparam): if switch.props.active: state = 'on' else: state = 'off' print('Switch was turned', state) def on_activate(app): win = SwitcherWindow(application=app) win.present() app = Gtk.Application(application_id='com.example.App') app.connect('activate', on_activate) app.run(None) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gtk4/controls/examples/togglebutton.py0000664000000000000000000000177215074674453024754 0ustar00rootrootimport gi gi.require_version('Gtk', '4.0') from gi.repository import Gtk class ToggleButtonWindow(Gtk.ApplicationWindow): def __init__(self, **kargs): super().__init__(**kargs, title='ToggleButton Demo') hbox = Gtk.Box(spacing=6) self.set_child(hbox) button = Gtk.ToggleButton(label='Button 1') button.connect('toggled', self.on_button_toggled, '1') hbox.append(button) button = Gtk.ToggleButton(label='B_utton 2', use_underline=True) button.set_active(True) button.connect('toggled', self.on_button_toggled, '2') hbox.append(button) def on_button_toggled(self, button, name): if button.props.active: state = 'on' else: state = 'off' print('Button', name, 'was turned', state) def on_activate(app): win = ToggleButtonWindow(application=app) win.present() app = Gtk.Application(application_id='com.example.App') app.connect('activate', on_activate) app.run(None) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gtk4/controls/images/button.png0000664000000000000000000001600515074674453023330 0ustar00rootroot‰PNG  IHDRdw©Þ-sBIT|dˆtEXtSoftwaregnome-screenshotï¿>&tEXtCreation Timevie 09 dic 2022 08:40:18Ö@HWeIDATxœíw|SUÿÇßI:èLtQ–@K‘½A–²EÅÊr=¢">è£ ø¨ˆü È,X@¢H)¤”ÝÒ½'m¡Mòû#Mš¤I›¤¥Î;¯ûJrï¹çžóÍ=Ÿ|ϼ @ @ w!’&§@ ¨ªºŒ¬. ¹©8„€ )Á¨•X[¸ Ï“˜yL Ԇ 2ó˜YXZ¨ „¤šÏÖ^G X1‘PUóÙØyÕbI6‰Î&5ønJ@Aý`(º›Òà»aø1·P `Û„x ‡1ÑPšØ EE÷|“ؘ‘S†Lç]xÍWÀ¾"n!Aý£+åÀM ÈrEŦÔy×=WB âQ“pŠ†Æ£Ðˆ… à ´ýySø£={tŸ„wTB(‚Fƒ•J©Ê=sê§G'MÚ\n  •â¡Å£¦nX5Ñ [À£gÏž½6‡oX%‘ ·:c ^PAÞø çÄÆÆžr€2Ô¢ñBŒU]ªPpèzOæb³\{ôèÑë¦ ß©TfUyA#@‚¤|Ì„‡§ž9sæ(PÜB-åè·}€ ñ¨I8Œyv¨Û0:Ç_¹ÂÓš’Üà6ížÎ nш‡1Ï£ RS±|Öˆ‡¦Šâµaýډњ(*÷×~ÿê [Ôe[†~o(˜p.j.®[E±Eíi8í¯]¹¸QîµN¿@ hTJeN«v.%¨=M›‡ac©ÕµMëIш»D¢r«Ûi3 >‘H¥î¨ÿümÑo$•RCÏŠ¹ã8 …Ã¥èrš6* àˆ~UE3€³ZÌñ8 …ðΆ@pG`Ge¹ÖÍfQã¨SÕY$Y 44ºeÚpʈIŒyƦÅЇ´Ž× ƒîôS¢QÅó0gȹ± m2¡Á®h› jSÂa¬/WWÃ…Ë—µß]œ]ð÷¥]ëÖ8::6`ÊVbX®•{‹ºcuOÖDH„Ãa9‘¿àZBB•ýãÇŒbúÓO˜ÏÁÃr-> ãÆàáî@~~[vDÐ2(aƒÕYš 9y:–‘{«ìwuvfÊ““>ä¾ÛvmÁmÁª5tÌi5Œ¨â³±õAÄVó?|ùë¾úŒ9Ï=ÀÎÝ‘Þ(2;Ž“§O³3r/ù…ùÚ}EÅEìŒÜËñ“'ë%³ŸÊꕲxá<8vEÅÅ|þõ·D?Ñl|çmž˜Â‚w—PPPù›²pñ{LxbJ­~KL¯ìg’š„âªR ìlmpuueİ!ø ,WpâïÓ„oÙNZz:eee„oÙÎÞý8CBb2{=Ȧ­;((*â—½¿”œFø–휋»¨½žR©äÄ©XvìŠäHÔ1nÜ(ÖËÍË#|Ëv2³²¹r5ž‘ûøýÈ_”——W›w77ZøzÚ‘iO=άéSX³öÿôÂeeçpà÷?‰Ø³+WãõŽmÙ±‹³qÈÌÊfïþCüvð0yùÄ]¼ÄÎÈ}ŽA©TêWxãG¢Ž±cW$'NÅV9~'àÏù¸‹¼µt9òß%Ëùç\~~µ‰Úª²lé¬ÖÊ‹¨ª %¨ž ±OMË 3+‹°ÐŽÈ]]A'OŲ{ßo´oÓ_oÊn•þó6Zµ bÄÐ!üÍõÄ$öüv©TJÿ>½Ø­Ž”ÂÞ†L*%¤ý=äæå³ä£z…ÖÓÝ·æÏ#8(œì<ÂÞÆG¢HNMÕ†ùõÀï,Y¸ Æ€»›œ­;v±~ÓÏzaŒg¸Ge$œî>¥JÉÑè<ÜÝyü‘ øµðeêSãîæFÜÅK”Þ¼©=¯m›`ºu £{·{éÛ³)iéÕä¢ê= ³Q trvââ•Ëãæ.ç¿¢8ôÇœP($§¤hcrpp`èàtìÐŽÆС};:…v¤Ÿ^t í¨NKz:WâHKO§OÏîôëÓ‹À@fM›ÀßgÎ4øï{»_2™ v¶vZûÛÚØbkk[«8­Ex ÀÄq£™4qÓž~œ—gÏàX̉:¿N^~>7oÞ«¹‡¶ª •JñõñB¥R‘Woô<¹›zµ…BaÑõRRÒJ¥ø·ð¥¸¤€ââb’RRIJIÅ×Ç›}{ãæf|57¹z¿RUÙfá®Ù§T’ž‘€—Wå?l _$ ¹yÆór§›—¯®ª$&àçG€Ÿ)iiüwé ’wëWîmÖ£Ó>Юukò Š@…zÚPPTT¥¡ŠÍ•ªÊ}ï*Uå>'g¤R)i(J¤R) …‚ø„Dd2^žÞ¨’&ô]šªi7òùXÌ Ò33éÚ9 ;[;|½½puqeÞ‹sŒÛÀT¾ŒíS¡nB-PšãW®& R©ðõñ¾£ïÉŬ )9…??-œÀÛK–“”’Ââå³â½Eõšáq4 ¥¥RIn^ž¶nÞ©c{¼==uãdüõDüq¤ÊùrbN¦¬¬ ׊}—®\#?¿…B !Ú“Ÿ_ÈëÃIÏÈ`kÄ/””–Ò»{W¤Rëþ¼‚|2³²¹|í[#v³bÕWØÙÚ2ó™ÉÒÂLJ —.óËÞßP*•ääærþÂ%«¯Ù&8g'G¢Oœäàá?IMËÐÚ¯OEõêNåZ|­Z±há|ÜårÜår-œO«–A\K¸^ïé©ÅZ¡w°¼ßf¦ÌzQï{`€?3¦>¨¸o@?¶DüÂÙóqÌ]ðÎNޏ8;W„TÛ|Pÿ¾ìÙ ›·¾e_¬X†—½ºu!úäßLñ_ êß—Í~Ž™SŸâÝå±g{öÀôÉObÚ¥©É€Õk~ÐûÞ*(fNÇ×Ç P!“IyiÖ³|ø¿U|³îG¾ßNyy9îr9ß®Z©­:™¾FU—ÃÉÉÙÓ§ðéWßñéWk´Gú÷îÅÈaƒM¦õN`Ûúïu¾©óé.weÅ{ïêí«/ŒuÁè/׬¿Ñ õ¼}—Š­Ïå gWÔW"ïöí?Dn~e}ÔÉÉ‘€-èÜ)Dïß?7/¨ã'±³µ¡{×.\ºr•ÜÜ<6X&)%•S±g°·³§W÷®¸É]Q*•>NfVÁ-ƒè ¨ÛNÅž!+;ÿ¾téÜ íµöø@?úõî À¹¸‹œ9wž^=ºÑ*(P/ÇþÃ…Ë•½-Í== ð§M«`£LÑbbÿ9KfV6¾>^´ n©íغs7R©” cG–žÁïGŽÒ¶U0Ý»Þ @ÌÉ¿¹ŸÀýðöò #3“3çâ(-)¥Më`:ÜÓΚŸC´mú …zÑâB (E%°*•V!Á]ŒµÂ!Gň6@`1¢WE XŒÕ‡ð7‚»ÑÆ!,F´q‹mÀb„p‹£ÀbjÑ8*¤C ¸[U@`1V{ÉׯÕe:AÂjáè=pEydgePZ\‚RiÙŠQ‚J¤Rxxùàìj|…,CîfÛ {YŽ563E-Æq@fZ ¹9´ ÆÙEŽL&žEm- …‚¢ÂÒ’(-)¦¹O‹jÃßí¶ö²KmVV GQA¹9´ é¬]ÛA`=2™ ¹›;ÎÎ.\:K3G“ÿ ÂöÂ^Ö`ÌfÖbuãhvV-‚‚ïêâv ³±Á70˜œÌ “a„í+ö²slVV[²´¤'gW³Ÿ"0gW’ã/›<.l¯°—åÔd³š°ÚãP*”we=±>Éd(ªy¬¡°½>Â^–S“ÍjBŒã#„C XŒ@`1µlfM ‡°½e{Õ%µÑHÝpÛ[†°WÝÒhª* …‚sçϳ=bÂ7òÇ‘#ܼu €Ä¤$6lܤ ›ž‘Áöˆ]fÅ»-"‚ /Ö.¯ €o¾ûž¬¬l“aþŠŠbWä³®Û”(**"êX4Â7rèðájm °ì^½SiÂqåêU¦<7“…ï.âØñNÅÆ²ü㕼½h1ׯ'²>|£6ü¡ßóþ‡QXXXcÜÛwDw±æç•æçåñõwß³nãÇoݺŢ÷—ñË/fæªipôØ1~âIV¯ù– —.±æ‡uLxl›¶lmè¤5J,½WïT|(]VV6Ï=ÿ"³ŸÎcLÔ{¦¨Ba|"Ò£æþáÃp©xÐr]²c×.¦?3·Š'£kصg/yyy´4x$bSæÒå+¼¶à?¼³ðM†ªÝÿëþý¼»ô}ä®®Œ¸x¦°qaͽz§Òࣟ~ñC dÒ£«Ä)“IÑúœú=9%™?ŽåÉIjÃ*•J¢¢£‰OH¤]ÛÖt ÁÁÁAç|õ¹¿î?€B¡dä†B}¼[×®lܼ™YÏN׋ûÿÖo`Äða¤edè¥13+‹£Ñǹy³”~½{ãïçW[“˜IímÿÙê/;zÇÑ‹ïþaC‰»x‘ÏVÉýÆ •J9v<wwNž:…››;û÷ÃÑÑA/Îè˜._¾ŠŸŸƒôÓ>OVs~y¹‚ÓgbqttdØÁ89Z?_Â2æ^Õ{ö,gÏžÇÓÃ~}zá¬}8Ü(.æðŸ’™™MP` aBðôðпtù §þþG'' wnCÑàU•Ãaü¸1cè–””0ç_sùjÍw$&%±ê«oØûÛþ*çüý0|¼’Ð&ãž6åi6oÙJqq‰v߯ûâãåŽÃôž<õ7SŸ›Åùóq\¸p‰ÉÏÎ :&Æ¢¼4J¥’˜“'3j¤Ñã<4ôŒ ’SRˆŠŽæ•ù xgé{\K¸ÎšÖ2mÖ ‹´ñ½öæB¾úæ;2³³Xóü<ï5í0ï¨èh^˜û ¬XÁõÄ$6lÜÌÔçfqóæÍúÉp`ͽ °ì£¼ýî®_gíúõ<ù̳¤¤ªíšÍ#O>ÍÎÝ‘dçdóóöí‰:¦=wCø&^{s!Éii8t˜I“Ÿ!;'§Îòd- Ú«’ž‘Áâb‚«KsÌÔûúðMØÛÙóÅ'+õž˜®Òq6ÎÆ]`ÑûËùè½¥øT¹žæ{XH(mÛ¶eÛΞœôkׯçÅÙ³HKK׆U*•,Yþ3§OãÁqc éȪ/¿¡ç7=¬5‰ÙÔÖö)©i”••àçg4.oìíìˆO ÀßTàïïǪ•+J¥”––2uÆL~Úü33¦=CäÞ_9w›7"•J)++ã‘'ŸæÈÑcôïÛTŠeïpãÆ ÷ ‡üÅð!Cj—3h¨{õè±cúãO6ý¸gg /Í{•U_~Í’wþËÁßÿÀM.ç‹OVV‰')9™Ï¿úšðu?ÀÛ‹³þ§¼ôüœÚe¨–4¨ÇQZZ @qII !«gÿ¡C<8n¬žhè’ž‘Á¼ù ø÷ ÏÓ­k—ã›6ùiÖ‡o¤¬¬Œ#E‚„¾½{ë…IIM%1)™ÒÒRvGîawärr󈿞P«¼ÔåååÜ*+3z\"‘ ³‘aßÌ^»Ï«¹—ÖÆÍš5cìèÑœ:}€¨ã1¹w»#÷°ï·ý¸ËåÄ'TÚÃÙ©ÒÅvrr",4””Ô´:ÏÛíÀÚ{õ÷?ðÀÐ!¸TT/d2O=öÑ'Nмys“’Ù´e+yyyzçž<õ7r¹+±gþÑÞcH¤\»~½rT;´q4Àß®\½Š_ ëINI¥¹‡»Éã;FAA:´7+¾^=zàíåÅ/{ö¹‡©“Ÿª¦ Hí¢çæåi?L›2ÅÂÔ7 þ~~H¥R®_OÄÛË«ÊñììlŠ‹Khd2ooíÍ^XTÈ­[e¤¤U AÿþýèÒ¹³Éó›ÌŒUkïÕ´´tºÞ«o???òóóQ*•Ü7ps_|õ7±âÓÏx`ØPžŸ9__ ŠŠ ѳi`€?Á-Mÿ&õEƒ6ŽÊdRºÜÛ™ÚÈÀþý¬¸žú»““#YY&Ó3aìX¢cNðÆÂ·Y·ækœª‰[ýþÌä§Yòþ2\\]6ø>ƒ¸Uø·ð`Р„´7¤ú( µ»†Œ°N¡lˆ G÷®UŽGDFÒ¦u+¼š{b˜w Ù9Ùøúú ±G2©Ì˜6µ†´~VÑìeí½êáîNJZªÞõsssðñöF*•*ž0ž‡'Œç\\Ÿ®ú’EË–ñÅ'+ðkáKIi ÏNlÄ›nXÁmðÆÑW^z‰Øþá£ÿ}J™Û¬ÔLû•Hªíî eçîÝ•á H`á¯akkË;K—šõ/7h@?î½7Œ™Ó§­É]]érogÖ®[ßdþ5 yiöL~;x¨Ê`º'O±öÇ üû…çõºcÏœ!¿bìLyy9‘{ö2 O_ÈѨh³ÆÌ4U¬¹W{vïʯûè ªÛ¶3‚Aú韄tèÀ˜‘ž®nKëÞ­+$lÚ²íveÉj|GÛ6­øäÃå,~9&,4[[[ÎÅ] ¬S(ïügB;’_PÀ§«VóÈêÄ1{ƳÌyùßÌ~ùßt ã\Üî:„uZÀøð½ÅL1›uë70õéªÕ]$ ½ÿ^µa^Ÿ;—¹¯Ïgæ‹/Ó«GwÒÒ3ðpsã…Ù3­3F=Ó9,Œw¾ÉòV°mÇNÚßs‰ÉÉ\¾t™¯Í£w¯žzásrs™<í9úõíÍùóq¸¸¸2nÌ(ztïÆcbÎKÿbÌ葸89uü8/{OÛÛÔ±æ^qÿpö8À”3

½z2ø¾ûÔ‹·H%tlßOOä®r:…„š–FÇöíõ—’“HhfoO·.Õ5žJðòô¤]Û¶€Ú 7znr9ÅÅ%´mÝš1#G`o߬Ö6ÉLOÁËÄb²Yé©Ô•íÛ¶nÍø1cðóóC*‘0°^œ3›ú]ÖÇŽÇàãíÃŒiÏPVVÆÁ÷1ëÙéÈd•6ìÛ»7½zt§´ô&vööŒ5²¢D};øÑ2¨¥6¼ m[·ÆÇÛ§Öù¨/{Yz¯º8»ðÀ°a´jŒ²\AßÞ½yaÖLÕÕåíÛàçB¡ÀÙÑ‘'ŸÄˆá•cŒÚ´n͈áÃJ¤”—+èÕ³'}zõª“…‰2ÓSøúÛï÷IÀ­Š­ (”›QwZbbŸF44‚Ñ p\*¶>'Ž^rïíïv¼[9w:†Ž»=v>ö$õmûO¿XMvN.ï.|³^¯k.Í^Ms§cèÞwÐ+@PX±¥è H•†¨9*°–ú¶}}6dÞšjº' Þ8*š Þ8*h¼ÜÀ# áq‹+€5Q„í-CØ«n±Z8¤R) ¥™‰ù!ëQ*&çÝ€°½!Â^–S“ÍjÂÒ3µMëÍ(.,°úÂÓЬ™éu*„íõö²›YÕ]V“p_•T.rO2Ó’QÞe+ÝnŠrÒS“qq÷0Fؾa/Ë1°™ñ `5‰9‡nDÚÑd.r9N.r®^&tEXtCreation Timemié 14 dic 2022 21:54:11ǹ§ IDATxœíÝyXTeûÀñïÌ00Ã&"*‹¢‚¸ä–ZZýêõM­,³,s/ÑRs)—Ì0×7µzµLË4MsÍ}·Ò5wsÃ]Q3d×Td‡™ùý1Ì030 ¯ÜŸë:×À9sžóœ¸yæ>Ïœ!„B!„B!„B!„°CQ†í•vÛBQÞ øúžÜK2UØ<Ún“D-„¨h ØOЛÇb)I2µM–ß[~­,I‡„â˜>ïÑ2aÛ&ï‚’yŠ“¨mGÐJ‹G{ ZUœŽ!Ä@—÷h›°õvÖ[>ÊÉÁƒÛ5+m¾VÚ¬—µ¢¢Q‘Ÿ˜MzŒ9± ä\d²vdDm;Z¶MÆ*òµeÂV;жBìÝÆÔæ­ã2žBˆb²¼õ†½ ˆvëÔ•>lߨÎ[œÍ‹äi!„(.g‹Åò]Š*ìßi'=°öì?Àîý‡¸CzF:~ÕªóÔ­éòr'º÷€V£aÉ7³ËäØEµ?bÌ"£¢P*•Tòô¤a½ºôêö5ü>NVV6:].¥RYäú²`y. …‚*ÞÞøùñÌÓÿâ©'+Óc‹Š£Ä‰ZÔå“^¯çÓ_r4üjÖ¼¹Ã՘زù@·ÕþKÏ?GN®Ž§ÏpðÈ1.þù fáprýíBöüƒ™Ó¦R'0°ÈõeéÿkR© þÚ5Μ?Ï©³gÙÿÇƼ7ì¾_<ØîaD-©º<Úôã6ކŸ eó¦ ò6žîî€1gç˜n•kòO¥jãú¯uÆÕՕ̬,Þ2‚[‰‰Ü¸u“êU«³}{Ÿtdo}Y0¶?t@_\]]¸|å Ÿ|þ=ÆÎ½{i÷¯§Ê¸¢´uîJÃõøpä»xz߀’šÊô™³9{>‚Í«–Þ×þHéã¢×ëY·q Z­–ƒâ‘—¤ÁXbи¸˜¿ÏÉÍaþ¢e8|•RÁs힦Çk¯˜·gfeñýêõ9NZF:Õ¯Oÿ¾½ÍIT¯×³qëOìÙ›·©X“]:ópÓÆV}ÊÍÍeô¸ˆŒŽæƒïðDëGïê·ÆÅo//ô:U«TŒ} ¥~H0Ó&O`ѲlÝþ+ŽÎþC°ïàaF†M@©T²qÅbfÌžkw½©Ï¶üÈÞ‡¸që5èÙåZ6ojîK~y¢õ£h5>†Þ §C»§éÙõU‡!ÁÁ„öêά¹óùmÇns¢.*¦=ú äñV qÑðÇÑã(•J^x¶­iÁwK¿çÒ•H|ªxóö›}hÔ ¾Ãç$Нf.D\bÂÇÓ˜2. …BÁ¤§M ÇËs¥¥ä<ƒ,åm‰‹¿FfVuƒêàáîQðsÔÔtÂOž¦VÍ$§Üaõ†Í?e~Îg³¾fÛ¯;¨_¯.­Z4'üÔi>ùlz ðí’ïù~Ízru:mÙœÌÌL4Í]Ûå«×ÍóÏ´ã‰VZmߺí6lù‰¯¾Y@l|<¯w ¥Bi€lóý­ZX³Ú·¥Ç« ]oêóеP©T4oÚ„¿"¯2eú Î_¸duŒ]{ös,ü5ü¹s'•5·püÄéciÕǼ¥uËæÄÄÇ;S€ß÷àÄé³ÔðçvRËW¯cDØx²sr¨RÙ‹è˜X>ÿrÙÙ9ŽŸ“,Å^þ3æ}ü|«Ë„©Ó˜0u‘QÑTóñaâ˜Q%o»„dDý¹vý:žîE<<Üܘýù§8«Õ¬Þ°‰Õ6söB-›7#2:šã'OÓ²y3F½3€¬ìl>Jüµkh5~Ýù;þ¾¾|9m*jµý»Üž:{Ž­Û~¦N` ý^ïy×öÕ6[}¿éÇí4¨W—ºAAEöÿñVpðð¢cby®ýÓæZtAëoÞJä׿S³F3>þ•JÅo¿ïa΂Elúq5¨gnÛÍÍ•93þ‹““·üȲ5ë8{þ-v|”ªÕjÑjµddd¢Ó鈎‹+4¦¦Qš››+sgü¥RÉÊõY»q íþõCôàÝÑO\|î(ž*ÞÞLÿ!ã§~JTL,U}ª0y|Õ||î{îábâ=ü{e¢Šwe®_/òçã¤vB­v€zuƒHMKÀظxŽŸ8Eç^¡VûÝIMåúèõznÖ§¼6leeçðå7 0 êß×|,K+ÎÅÕÕ•ŒÌL–¯ZÇößv²zãƽ?Ëá‡i?ël~k¬í­¿ƒ^¯§yÓ&(UJ xòñÖÌY°ˆ˜¸8«ý•J*' „Ô3Æ&9åN¡15Xõ²³³ÉÌÌÄ·zU”*e‘15í«TªP(R/ØøK¡R˜·‡OJênݾíð9‰âS©œpV;›¿W;©Q«ÕÿH\eDý ð÷C©Tr5*†¨˜Xj啊¢rRY}ïžWÛnÙ¼ý^ïaµ­šGއ¿Ñü ë¬v"¨N-oßfûo;¨Ww`ÏÕj4ty¹#ÛÛÉ…‹—¬¶étE~J‘C23³ŒíéuæuYYÙ( «Ú½-'Uɪƒ§ÏÇ`0P«¦qD_TLí±7ûEeÑŸ’ž“(Úí¤d&~<ظxó«Øøx&}<Éãèìu?ÐJjÔÐâ¬væ…gÚ¡×ë™ùõ<®]·ÚnY ½k‹Ÿk`€?J¥’K—þÄÓ݃_?ó¢vRã_Ý€ã'O›k¥¶m)P0¨_´Z-»÷äÈñ“veZR’ïàãí pqvA¡Po>FNN®Õ¾N*ã?˜´;©VmÙ[_3À€cá§Ìí…Ÿ<…Á` v`ÍBûfw]!ÛþfѲU(•Jº½ú²C1µÛ…¬+Î9ÉRìeÊô/ÌIzòø0&£†¿?±ññL™6£äm—Œ¨0½ºuáÂ¥Ë\‰¼Ê°ÆQ;°&îîDÅÄÒ¢Y†x³È6¼+Wæ¹¶O³}ÇNÆLšÊ¿Ÿ|‚›·IËÈàýwS§v-5¨Ï¹ˆ‹Œÿ7mLtL Ý»t¦AHˆ¹*ÞÞ„öèÆ¼ÅK™·p1 ?û77óöu›·¢vv&99…c'OÐéyãmÎÕj‚k׿ÏÈHÂ&N¦²—§Îž³êgíÀš,\¶‚G[ùÈjÝýbïnM–wÉ3ÝãC›·¸î@ë?/žûâ~uR!uë7z8 ¤é@FÞ’Cþç(šîùa&·+Bˆr®ä¥yU%„÷…Ô¨…¢œ“Ò‡B”sr›S!„(ç¤F-„åœÔ¨…¢œ“µB”s’¨…¢œ“‹‰BQÎÝÃÅDIÕBq?HéC!ʹ¨ã¢#K³B! PâDÝú©v¥Ù!„Ò‡B”s’¨…¢œ“D-„åœ$j!„(çJõÃm¯^¹ÈõøØbíSÝ¿µƒë—f7š’Äë×HIN$3#V‹g%oªV÷ÅÝÓëîaù&ñ+ÇÒQj‰úê•‹ zþõÌ‹(•Ž Ôõz=gùzå¢$ëRy9‚”äDüü©‚›‡'iwR¸y=+—ÎãYÉ›:! þáž–O¿Ò!q,=%þpÛô´T«·=¼og±’´‰^¯gïo?Êt¿RqæZWW4iQÄóÂÉHO§A“æ÷©gÿ$~¥CâhŸ«›û?ÿá¶ÅMÒŽî³k÷^Þ ûN¯u£]‡Ž„x›Í[ ßÀÁlýi[±ëˆÂÚ.Ëã–Täå‡þ84iÖÕ•ÈË>gÂä)<Ö¦-µiËãÿnÇK¯uç“Ïf””Tâ>fggóX›¶ÄÆÅÐ3ôM–­XYâööìÛO×Þo°~Ó–·aR‘â§×ëY½nýÞBÛç_ kï×Y³~c‰ûe©"Å1-=¥+V:àmÚuèÈ‹]ºñß3IKK+qßì)÷§~:ÙßÌã™vmùjÆçÌ›ó¯½Ò//©mYJMI"%9Ñ¡?“MZ’œHjJÁ¿ð¯v~‰Û~àç­›˜2q".2qòÇ¥ÑeÚ<ùÔ¯W¯ØûE\¼Äá#™9{YYÙ÷ÜŠ¿»vs,üï ÈŠÅ‹èݽ;_ΙËÎßwßS*Z333‰‹O`øÐ!¬ù~OšÈ¹sç™þŬRë”òÅÄÒöëŽ];y‚‹¿ÃÍÕÕ¼>$8øìUùtãú5üü‹½ŸŸ 7®_+𢎳Z››Íš6æ½aï0døHÒÒÓ­~&%5hÀ[%Úï‡mÛyºM:wêȨ°±÷ÜŠ¿ömÿͳíÛš¿ïüR'ÂObßC´{úß%îOE‹cooÆŽeþÞǧ £Ggäcî¹O–Êu¢^¸d úõ-ò~’Í?üDäÕ«Ôð÷çýÃiÖ´1999Ì[ð;wï!3+‹6O>Éð¡CpuÕ˜÷_½n[~ø[‰·iܸ£G ÃÏ××êiiiôüíÛ=Í[¡}8pè0«Ö¬åï¿oðPÆŒ~o5kÆ—–ËW­æ§í?“x;‰¦M›Û]¸d)»÷îcé‚ù¨T*ÒÓ3éÑ'”ýûñb‡%ŠUJr"µ‚BнŸOu?Nvøù …'''rrr˜ûíö<Èß7nQ½ZUúõyƒçŸ}Æü|NÇ·ß-æ—;IOKç‰Ç³j¯ßÀÁ¼òr'^êøPxÜ,9¼ØçZ˜Š?{%ÇÊ^^ÜJ¼]œÓ¿KE‹£=YY8|.Ž(·¥ÌÌLbbãhÜè¡"Ÿ—Àè‘ÃØ¸j=ÄØIÿ!''€_}MTL,‹çò…ó‰gÎüùæ}M?ŒIãÆ²bÉwth߯J•¬Ú×étŒô!!Áæ$ pãæM¦þgË/ÄÛ»2ƒ‡$33€…K–±k÷>üKÌÃY­fèˆQäääÚ»ºÜ\ÖnØÀ‚Å‹¨Tâ$ ™‘a¾ª^nžæiS…1 ÄÅÇóÍü…¼òR'\œQ«ÕÔ`ÚÔ)¬\òŸïÀ”O§cÞoîü:r”Ï>™ÊÒ…óÑh5…¥ð¸•%‰œ>sއÜÛ쫊G½^Ojj*‡eÖW³éÕ£kñP„r›¨ãâ0 Tv Ý©ãó4¬_ŸÊ•½íÝ“[‰‰ÄÆÅ‘–žÎÖ¢ß>T®ìEµªUØ¿{öŒ xÉò„Iƒúõ¨êãóíÛ¢Õjó7˜ñÕlÒÒÓöÕq;wêHpPüýü6…BÁÎÝ{ÈÎÎfåšµŒ5’à :øû3iìÒÒÒØwàjµš°Q£X¸x ýÁ¶_~cìè÷K5~¥eõº æ‹8]z¾nYXŒf»t~™ :Æs íÝ ?_Î_0^ÊÊÎfý¦Í|8ú=B‚ƒñóõeä»C :ŒjU«Ò¨AÃR=ÿr[úð©â @\\ž Ÿgéçë‹V«%==ƒè˜ôz=c&NB‘71W—Kzz*ñ ×ÈÈÈ a!£ˆ·ÿÌ…‹—Ø´z%.ÎÎ>ÏÙÙ™fMM\Â5rss­.NhµZ5zˆ«ÑQ<ܬ Ï´kËûcÇ3ql>>U>G{\4ZÒî¤{4“v'¶Àí]_íÌ»ƒ¡×ëéݯ? ¥õŒÎ¤¤$~ݱ‹SgÏ’œœLâíD²ò^UÄ'$ Óë©’ÿRØÞ|PGâVV*rün޼Ŵ39ìs¸¤*jû÷ åÍ>opí«×o oÿ¬X²_ßêœ}ÑÊ툺R¥JxW®Ì¡#G‹½¯Baüôw7͛˦5+Ù´f%?¬_Ë®íÆiu©©wãË–‚<Ò¢®Z-k7=uÉY­F­V““…^¯G§ÓݵÝÅÅÅü}@€?z½çÂ_†9³’7¯'{¿›×ð¬Tð«•J…³³3†7zõ`õºõ¤¥§žžÉ[ƒßáÆÍ›ôïÛ‡iŸL¥np]ó¾9ÙÙèõúBãkÉѸ•…Š¿¬ìlÂ&LäÑ–-yñù’—ÞL*jÁX÷ð÷gÔ°wñà×]»:ž#Êm¢èÙ½++V®&.>¾DûûùVÃM«eÿƒv·ûûå…‹ lÃ×·:“'ŒãûÕkسo¿õF‹#3 œ¿APÚÔ0^P‚^¯gê§óz¯ôêÞ† ðÕÜy÷+J^¸{xq&Üá}"΄ãîá…G!#KÎÎÎôîÖ•UkÖ‘žžI•*Þ¤¥¥±qóV’’’øeÇNþ¼|Åü|7­–ŽžcÚŒ/8á·o'±xÙ÷¶_TÜÊRE‹Ÿ^¯ç?B|B‹N§###ƒŒŒ ÷ðy¨-ŽÇOœä«¹ó?yŠk×®süÄI>Ÿõ%±±q´ùדÇ (¥š¨}iáè>NNN|=súõeÇï»0týeã–-¤:øÎŸ~o¼NhïžÌür6í^èÄáïqñâ%óöña£ ®S›·ßÎK]º±rÍ:RR’í¶Ó¼Y3ÆL˜`žÙñH‹‡ ?‘®¯÷!:&–9³fâäd,û¿7ü¬5ŒŸHï~oq'%•YŸOC¡P°bÍZÒÓ3èÕÍxeøýï²ã÷] ?áhØî¢R©¨DZZšC$gÂIKK# V*•Êáã¼Ü©ë7m¤VÍš 4o/¡ëë}Ø»?­ZYÿ"þ.-›7ç½1ãè3` 5køØ~aq+K-~ûâ·¿óWd$_íÊÓ:š—ë×ÿvø|lU´8V«Zœœl¦Ï˜IÐ~Lœò1·™7{ÕªVuø|ŠRj÷úøëò hиE±oÊd0@PHé^%­¨222ˆŽ$õN~þøT÷»ëf8 ñѸ{xáXÇz†‹ø•‰£}%½×G©%ꬬ,â¢ÿâÆµâÕ“«úúTæ‹*’ÌÌLRï$“œx‹;)Ide秺h´xxzQÉ» î•ÐhJ¯†ö ‘ø•‰ãÝJš¨Kmzž‹‹ ATõ«Y¬ýîÇýŠF£Ñ V«q÷¨„N§CŸWsT*¨T*Ôju±^fV4¿Ò!q,=Ž&jÛ« v Ë...’tË •J%÷@âW:$Žw±Í]¹-ª˜l°ùÚ`ç@B!§'?Ÿšš° KÔö’´å"„¢x Ë¥æUG¦g˜²¿ÞbѺ‡B{tXçR‡ªE%j½Å£©ARþBˆ’°Ì¡–IºÐœjïb¢íܲ6­Ã8}$×ÕÍý]À9oQçµ¥"z_Ù¾CA!ÊËêƒ)_æÙyKnÞb™¬msí]%¢f}Ø&iÓš¼Å”¬ÈOÖ ÊùÛÓ…¢ ˜’¯yPK~’ÎÌ[L‰Ú^²¶« Dm™Ùíýw0𱨮BFÔBˆŠÍ6gêÈOÔ¦ÅôÆËzu¡5 Q”¨-“°åzËD­@µ¢â±W…0½ëБDmWA5j…Åצ*°NÀ¦m–£l•ç !DEa926%bS $Çf±­U[¶a¥°µé*¤ëdmjÈ´Î^ÉC’´¢¢²W°¬YÛKÒwÝßÃRa5jËò†Âf›e±Ü²Üaª[Ë…D!DEUдfË„my1Ñ2A»Fm:ÒNC¦Dm9жM˨ZQÑØ›Ölï ƒÅzÓKa#jÈ/{X®75n[ê’‡Bä³}«¸mr¶-yxA±¨Äj™|-Ëö’³m¢–¤-„¨hìÝ#ÉòkÛ›Û™¤Á±dj›€•vÖK‚Bˆ|öfqX&c{åä9šT ª;K=Z! g°y,jý]Jš`e-„ŽsøÞÓB!„B!„B!DyòÿÆÃƒ~´Dz"IEND®B`‚././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gtk4/controls/images/dropdown.png0000664000000000000000000026326615074674453023666 0ustar00rootroot‰PNG  IHDR8/bÜsBIT|dˆtEXtSoftwaregnome-screenshotï¿>&tEXtCreation Timevie 09 dic 2022 10:18:03ª˜Iø IDATxœì½wÜvgU&z­{?ßÒ !"„RPÆŠŠÎOõ¨ã9þ,sz@QŠbÁsFgœù©Ã¨3Ç‚‚±  ‚e¡$„fH# $¤Bò½{­óǺ®µîçK)ŸæÙ!ä}Ÿw?{ße­kõuÛ=äE €ÁÂÀ† òs˜ÁÃÌ à ‡à6àø˜ ¸ˆÈ10b„€çûÍaXb0¸9G`0``‘¿Vð˜åË" ˆˆÁ—, ˆ X¾88@DÎÃúùÖ³8%,>`†Æ÷æ¸×¸9–ÐèsŒˆC®k˜±p^η0bá¬ù—ÓãߎC°7úiÃ×g«µÁà÷€‘oÓ^›!"×B#"× |ŽrªÁ .Ö0CøŠ0ãûµb€‡60¸WáZפ7‹°¼'ø=·Ü°ÁÈuÑ^™aDîSÒ-wГ¦ÌßëXôÓ €i¸n¤S³iOsNn@X` `p°È½Ì9®€†à¸„ÍF­éØsÃb8¼Á8#"©À87ϱM†(äña`ˆÌ´ì–kˆ07˜Ü뺇XW˜€5髨~aXÉ †€cY`#ø ˜{X ’®#½yX \Ãü¢f¢/ÑK®÷™ü:"ñb^ƒ\ÁÜU¾ÏcÔL6¹åIØa·üas|Nð~²V‘/3'ˆqâK¢Gɨ¡±E@˜Ä0Ü€aü¾áGhƒ [;üÕàdD.‘(!¸.ˆ(†x'QÕ—ÐPª¹qÎÄÀ|žñ)DfÀF´À6çËÍ/áQ0 hÄœK/‰,$R2VH~[ ÖóppQ,œs4´f7ôM‰(ê­¡Qq{íF«õ³shý¼”¶ÇéäŒ$|ÑÄ’_ ä»ÈfZÙš·žfH†Àô~GX¯fÓ rÜl«M7=IޱµvIŽ%,wHd`Nyªõãò[äÎÛ\TYÿ/Ñœ8H`¶À‡!Ö±Æ4O¿›†kïZä9Æõ0ã,Lo…(%y†ünäC œ ]̤c$¿“çB¼Ì9NÜÚÇ%„5"€V(pù¹Œ>ƒ–?K‹ˆ”Ä B%IŒZ̘Ü@XjÒ¤ŠP€—„‘{2×gÞö@,À ´vÁ‡ÖZÒ#µ%1on‘´&«…³Æ;*L$œ`”[>spôÔ0ŠE8«ûE<0AHj®N@̽¢äaÖO(̓Ÿç»“¹’ɸÖa^) vã\0iÐ?#Œà,9RŠr s\„‘%{=Àƒ„<™Ö˜SˆÐ0G`Í‘™£xgç"¹·ÜDÐ’Ð×u»v“÷×ßÂ,+Ô¦€ˆÔ Ss5j=HáÆõ“k#¨aMB¾4åHa#ùhpOŤú„‘à[Š'íYÈí ÈÜ»œ³DVQojžÔ%Æf¯q`Áº®8ÜE»A9RÃNЖ–·”R@š[U)¢+ÖQƒÀáE 9æQ´™k!àKa@$Qm-Gßf%Ѧ&PÃàaØC2ý(k*A óRìG5—H푱r¡¨­ˆ¾¹ i.%1„€lÀà|ç€aP½Ý3GËwa·¤fE™Àõ<W ©ñˆ1ELIÐB£”æbŠd„àF#¬„µ&Ž €˜EëM#µ3±EI`:#xšQ’4øPGÀ†¹KîFiV dJÀH H¢º9š”ˆ–«_ia·ÃjSÄHAf\O›‘Ð…I*¹§"{‘­9¦=Ÿc–‚HÚ-ÌB|h†8È €šM F0Dîa0º\<'Çê;6 ‹ˆÖ@Amµ„£è²N ‹5m¸†y­Ù(:0”?gpü0ÈXIT¥C…§àõ\» ÆãõNÃf\.ƒcMˆo³ÀlÁ&Ö½X¾Âœ÷U˜XHQ 0kí¶4á\[¯ß[Q¨šxL$º"¨ÄxRͬľmD*C„{ è\¥Æª¦®¤õÕ€ˆ1Ib) B΃Eª‘® ¹8Ìé¯%2}“Íœ¦%YÙRæÃW>ŸòÅ¢47ù 1ŠT‹h`H_R©–¹ðÁ ;ýn6½Ÿbò…ɘ. ähC¦Å6n‹³á$`äS¨38}RˆZŸˆ(ÿƒÖ8•YªûƒB ²ÀܹÞÉ@cŒ"`pí+—3jŽè–WNüi^‘ðÌFi ¥i–€Ë-p2É(C¹jýC²#ýU5?¤/µá©¡¹QãàšÃ­aþ»æn$]ñÎa"ÀͨpþX8P—)ÁÒþMÊ~Å]šs ²Éã4 ½dÒê¹vDϳ©–À?’@¤^–FDÚÎ禵a<iåØA¦·Üi® jç¨5—VYÚt½:Ò‹€}ØŒu݃XsCéœÐ[PôkmžÔÌ0Ý›ÏÔoiapýõµ›µ_˜‚@"“"ªx͵r Vk’ä‘ôµYĸÖlG• Å€ò/ ÏBtíkÆè“fƒ”0Xœ„Á§B$‰=oF:DÃÒÄtJæQ*ROPž»oYx¬ƒ_£i`šXI\a¥gr¡“øÒt˜a«8®f.G¯Æ“[±R­S@ †•Œî5M‰$ùÙ$1‡‚.@¾'4Ç”jØ–rÍNA ´ð¸âòY ý ?Ôô¤ZšÊÈŸ™j…$©qm„Úžø®´Ì¿þ¥µÛ(ÁV+ àÒØŒ¢+’å‰>M¥ ñÕXô3Š‘óë2õ ZøO@ ²¿4&K •‰˜tε†¼šAðJ3é_l+ÍYÚš'ïÑt•#À*'-õùËf#E%ßKÐÑ©F¦¥ø¦ÌkeaMô˜GjS§TéÇÏ’n2/Åù¿öí…‡|1Á蘅g„ŒÄa%{«œBFà&¬‹’Σ€®1qïo 4i"ZÑÁæÉlÖÓxÛí›ç•,+³Ÿ d­©€÷i<²&Ê'g‚(›îë¥nØ›Œ×i|V1ùÚsˆŽI1š䟜…¢`£z¹@ElOIÁ?“±¬™Vë\“áÑB»>$5$©P0]B Ê×|ieyi( \6,cof0ß`ŒÀfo`ÏW¸ïAJ=&iY!M•·Rlrö²‚l^‘RÓ4.:ÛŽµ™.+÷½FœþI=3ƒ #æ Ing©ô€"a1EÿÂ$c¨"Š€DQc¤V1ù¨DMÐ?80‰rI”´¬0šzzt/˜>ý¹qíK«yÀT9ét Äù›Æ- ä·Ð–Ži#@%éÕgiÂjãAߊîA®œg‘tCÐþT®Ì¥0NY)šgÐW5ŠŒä÷ ™Æ‚ežÖŽPÒÇDLFB§9^„gÈñq¤Qk~ÉO‚ÃÖˆk•*=„¯«ÀLƒoI¤%J¨Ìó·hï[°ñ=ì­@¸§ßR›§±“—"²´äT8]+A(NS´´k˜Ðé3a†Í‚FmÃrÄ[d:†3>éK׉‚æÈ}Ý ÃØìúçX×øÚ‚]ÂCÁ‹°À §kE‘lµøës\{°ØÀ½V΄s+=L˜f$"ƒ‰\¯뢄(cð"°‰Zà€G`!"‹âƒ iæJ–¢ÔIÙà܈«1´¹üž£Ð?„ JGÏ\VÃ:({R!ÜKVÒ§äöÌ6®„ŒZÛ"5 †¥¿ü(šW“Vƒ‘P©Ý-]LQ|E_Ÿ@'eŰCBѰˆ(~$‹L=qþ^à:Öv…ÞѾE …’Fs‡Ì{€5ÇAàË15h‹ÄD>(j½…L !®ô{‚ÚJ0@eŒ‚P:€èuh9Ph ò$”Í|š¯'(*é/•Ý8µF)½6i|ÒÚÊg®WTˆ#)mÉÜ5ÃH-òc+Ê^ÞhZ¢Ÿ°g©À,•ö!÷&ј`8€±&¯Ú€Ù‚u±\Ú±îØK­´ŒtÙIÏ^>LÒ,5âr5Uв-Á_æÚBî3É Î[7úƒÁºŒ"w¸õeIÅúRN@Djš€L”hm.¦2ˆœsb üý;AI¦@ͰIiÀ:iµlðöþHgª\82Xhß'Ç&$øNÑ x_‘ ¿Ó‚'¸ð¨9R¦µn;ïÐ4º&ÌÖnDÆÂi%˜ÚÄß2ÎS‚Ú2}ªµS©5ìÖí(¾¢½MšA‘µŽ $¡‰Hï°y@@í™Ì ˆè­ç/D5Ñš)s±WÉ`YfÄÑ&ÝO£T9mƒ1UÅ:GKƒ¢mŽ”æ˜ ³ˆ•Ù˜t-à1À}J) ÆËÇW¤K -× ƒ9rgôZç¤ñj÷lkôå·3½2Há6=±µ~Q–W s2ùO-”OH&)í˘% Œa°½ýðu±¦®Ö¯h¬_•–;ÜãB J1 h*O4_k+ X <Êy;• ¼ ȹ'ßR.‚c(Z_WF/ -6©^׿&K(Ÿ9hªˆáÅè>i`’.Ók¨)Lùw"‘@©ë±Ö°IS»úþ-†%YiåDÌ»€AÉžZjðÒ]+¿‰†{WP]’É‹½Na 1@éQ"C3dbuEÛ”—?G•{1…BÛ?-4´}bÌ9“v\™66 ¤}ƒE”¯¤aÁ*2[rÜÃà0µÎ>9„µI­òå–pI$+¡—îQ¥J8]ôM€¥êŽV ™’bÐÏ¥¼*Š?m–VAðú<`òI»aȧÇwÕ·mlÕØ€ðÖ(‚–H7Ú%åoö˜¤HÍjµ]Ì/g9×(jW@"jÎÉeåØÌëóÙ¤•Ë@ ¡ú[ ­¤+ Ñ*µÐÍ€}ˆ±—~9Љ—Õ7C+°ÄÊ% Äü-ùÖ€lù1ƒ¤¡­üU|_È‹6ÂP™û–÷' JCâ̘§“fw^Á!­Ã™F1õ, ”Ë¥•‡Ö`ò©KùŸ»ÈŠßÇè“€¥3ËZàL†¸/å6LÆuóì(LJ¹ÀÈá÷ÖŠîËüàž¬É=X]‚…ÿð2|MÙ@æ–÷1Í2éÕ„ %SXψl-µf¹‰“Ï ñ(UR€w7X`1cƒ±1øº•ÄdI+'«­0Sçã¥òÝœ…ŽY¡£àb°à`* ,¶GÎ9³úÊœ!Í%§>d”p ÂZ*:bÁâ} AIPù](êÈÚêIþèX»‡W(¬µ Ùf‰ JX>‚ã·–F[© ˜LfxEÇÄY‡§)R³)sÅ€1&çñÄ4eÚG°ä¥ÿnÀôþy>ô†dé°–”s›;SNEÞc[9tñ-S½ÞÂ÷‘É`lP{“oRɤ GLÐÊ|D2’l°»WiâDîy䇯Ѭ“+p@ÄZ­Ãm‚#«(ù¤mMÏöaVûôÃŽ‚g>ÇdîP6je'ÿŸ‰nKC³å3Yœ±?@m¢¢Íu./VËά\,å æ¾¸Kø’ƒ|T0,¬È ip,”Óâ½…RkG>5唉bÒ–,…yÔŒäi“zÂVvB&/ƒópµ @©?˜m°X`,ÛX÷î@Z#âÍ*7ª\ÅÖç¶óÖ*à8ÑÙÂW'm0IE= d¶)˜`R!ÅŽ˜IQÏÁVp¡61rÀP¿ j:ów ¬[#án˜œî)N ÇÀ¹°ìõí´Ö%ÊËù¤ä”&ZÍýª•ƒA&J›Èt¼#%tš Zei¨šÂ‘B“N(Φ>Ç-Ƕ|‹U¡ºÜÁõY¸7nL# 4^ä¤ƒÕæ¶¸‰Ú½1å3ɇV¦ð,V¨·XPs ªP;¢ "ÔØ5oƒ1ßJD‡rWXÍ>1lCAæU6—4°€E7 š”áÚŽžG!”A¦$À¦Á"xíì ¦—HGIMCu O¨«,(L‹¯Ô% ÙÂ.Ò–IŒéé´Î´ü¥vòÃ:‰Äa ú`¥F»n pæeÖ"º¬’s^$ñ+ê(Ech¦Þ !\*%Èc,—JãHÚd”Åçy[ ~ž‘¥¨¤×ЋbIþÛ‹-ãy>„¯wÒ"—m ·;L{™ëÉ6jˆâ_xË41…I#jÁëqÚþmFÏvÑÔÌ…, Uþ -¤TlvÛŸ?I@ž¼ ŽJÄìÀ $ŠF)lF`«CK*šePçØàçù÷üâ*¶y^’ò©ÁŒ¤%›L M q}J Ò•V$Rñ0j¬ F 3èRävÈÊ,.™W&YŽ}á;$€-×+¡ukŽ? ‚–¦J†.À„è&÷2J{ÐØúÑŠÁÎr¹Á½Í¦þ«LGªÈ¹/ç3ZëX_œ“Ú-2€Rß6)¢ù—%ïúS^ŸÞVë‰2éJÙ–{§Lè, öÏÓ^[Ñš8E¾í¦ï~s Ì5ZÃvÀË%órñ»ƒsõ(—Ô¶«dÚÐ(j@D6ÈîW[{ƒL{AÅ'´¦–lØ7ÜWøÞšµË¡ÜǶ´ô(c«™-w¾y@C ¶Kªé2BBG¡MÀ$ˆ)‡ß,UõÈYƒä ædܦ.ûDxUwiÈ &')f–Ä¡gI{õAyb9ÕQÄÉ :hGƒ›înéniÁåØGM•ªÁ väÚ,}Cs”ôÑûsPäµ¶¡´«–ðÁÜY}5¦û«É éyÍd¹EÔ Eô‹A-Só;ëË ¨O°>°Z IDATç£Ë‹°Bó´~’R|t€Lt¸U¢ùy1zÁëv¢ê˜„^¦$!-C‰ÐÚI.2T] Já1BýXß–0EšLj.ë>¹~U†”À¤’ƒ£¡j¨ 2ý–@®5Öj½í£ç™Û<ä£òVÊ¢™ ÝßeªÎ«V´¹«ÜTå’RÙZI±[8j'9wCJ`cäIzëc]åוƒd›ÖÊ{gµ?ʳ“›,'³Éÿfr+\E°¹Õª¦nšxHeÚÿ%IB‰C‘h ¦ddZDÑDüi)es"Ýö':"HÉÜ‘7áoð…ùœ$~Sêiô³''xHêlOÎM’'§6&óO’¤S:´¥IÔ¹Ønêð(Ó1Ï9P×ÒþF?C‚h3ÂFp¾{&œ„yΟ~ÅPËWÓ‘ˆ$ú¬ÖuhÅvñ°JÄ÷X‹Èrï0åµGý F“œÌAï0éYƒ´ž’‚œª0*MÅÒŸ”~´®!î•&Ù[¶<¯@ÓöGØÔ€Ù°šò¼rçVD÷ü—CÞ‚À6(:Yô†°¥*´ÝUlÊ¢õù ŽÒ·P7‘Õ=¶2ªQó©3@ɤNmù0‡Ç@ø2Em9È‘ëYê{ ÈüqÁt@ꦦ(÷ŠUš–jQËÚJ~WôÖ'© š.R!Œ¡±ˆ‚…ác`Ù ØÞß»X½üì‰)òHv‚1ò.›Š¼$9ÖbÀ”}¥äŠÑfñ–£Ku0Ú“—43ˆ‘¸ÞÑPzˆaTËëüžœúD{Ïn$yx‡2ûL‘›\ƒ@¨ýJi* LZ ›èÀAPÌm‡§§u ¶´dÏ΋Z›œ7“E+Ø@Id)ñ“ç‡,—¤½Pg¬<<ˆ•&BÎsÈÄ,‰N¢Alo ç"£ (ˈk…Cù3˜ ì©íf+ Å&d1°5Ž4zýAt2( ÙD³#û…é»!ÏV ¾Œë]£!´NfË9¾HãA ’Þ)À¸18(.ó á.ým¤ãܤ‚Î,ÏÛú~·Ó¤ĭ÷Y¾jâõĘÄiÀ8çîh¹R fâѮF UB Ѐ¸!Ëü´?é§Z4^º„“‰FEOâ/x) àþ‰Ï«å’ÍkÜ´° Ì´§ÎG«]— È¢Í>–À½ëÞ _³‰„´æ6ìÔ†éÜÄ#ßµQÒRÔ M%7ª0¹Ö&øˆÂá¦VD•$+xéfF¨¾cêVí‘YAî•Gk”Âê ’êj;ÕZ–†'ÿýC uW •¸`e:h~’Š*\*ŸA{‹€£žËtjUƒ„ºœMFÎ/¸â2²9,{ØG/J%–°^%SÔ¯ PÜoêYh ô}IH>ëPeCq4?5$È¡RW3Ày¦ƒ× €T޵ܓ¤1iPØ2FjÎ)  \B­XÊs\§‚|Xµfìqgšôú[€ÌÚé,‡PÜØºwú|H°p¤M&y’=ÒÑ;×f«—ƒ%( ¦V6Ê$r ­XtâqµÈ²ö¸Un›i7iõò©¢è× | Ò±ÌC»Jg-W”¡ÎÑ€p8i©ö—k2 ÀfÆ€¯{ð=ö/ ¢Ñùv‰Mm3­”€º‰Lw›BÏ1-vIý)ÅoôE./£¥jn8K(ë)7—Li´ÛïÎvÐJAHRƒlúLDR¾)LFܬ–Ë¿i:ù<ù#Ä#m!6°F}GC&ãP%*““óÖÛMŒ Ô30˜6l­UVÆv¿ƒ#ãC´,»ÃI+Èg/ó\, ¶çbJ-P&•öS³¥VPâ˜õ¼Êç¨qP³ª¨^®UÖ 'ð¥ Ú©Í¢“ (`.5w¡@ž˜4†°Òh\|ù_·š…¯ ^»â€@–ÖM $¬UÙD˱u»±‰ÄË;ûL[k1®r1_ãQÛ>9ÉËA µ ËÀÖጨF®1H‰‹£h&€êÜ.‘á¢õùÔ:€¼ã&Ì_ª+ø½jÇ6ÿ™€#ý‰—šoåôf°ØŒ Öð=Ö=À'^!{tY_ës€a“±6%¢¦T¯˜.9 £Ç–Ÿ—Mfñ)‚"  ¶³Ö"ÕkuãÔæU˜xü="󞘭õ6bb8 .oT»p˜ ™dž¹°êT[e_pZ®\*kbm‡®‚–v!¶I]¯ý’’¬ddk&i}k2‹BLªg,µN2‡kü©‹Úc^ª-–æ†㤿Bæ‘ös”o»Ø™¼©À“É”3±N/ê”…LmÑÇH&s0J«ÕË”g% R»f‡ >y˜4ƒº˜$v¨ªà®®˜Ö«}8QëÐt[†?µ¨¶P»ïŸ\2—1 ³3Á3Ê´€Ù2 KIÞÌ'“_»Æ+õ  %¿rÌPÅëb›dCHOK‰ÖQ¾Jj‚â«™v$ç@à3¥N׷ꥂ™ius]¸§s9¥—`Z˜ü·šÿX cA¬–ݺæ˜Éeݘ7{ÀbûáÖ"JFLeBY½;J"w×ÙtÊäSÕ¢eUªÔ^„¤Ó†•Ï’ÀÌ)UíP¤I8¢žH'´¤¸ºû.Ip@›ÜªªÀ¶MpÐŒa2æ AYkºoŒLzUE”ü~µ½ùž*c¥0Þ+zPïàÔfä ÏÑ¥ÀOI‘7Gki*›·¾€¦wƒ2Ñk`;(r‰ÑAod5-MÅ­ÓŽÅr™àŒ2çÅ1޵л³c®ÎÚ튙O ²$Xý’}æƒô®ŒÖ±“eõI÷㸩3skkŽ´þ¼ ó¹ûHûÓ’™ÒD5dôfiÛwšÝ`ÐHÍÆ¬3ûCHk³{ ´^‰›×¶ É•@lHÓÍjmüA'Ù‚ŠÌ·'5YÓ¹˜kd"wušË"c¡FOúŠ †™ã^-Ÿ”n" 8Yr9.c¢œË<›f·‹&Ä\‹¥|eøÀØ»#™u’Ka @°¤©6XGtŽ+Y¼Ø°$dYöÂ"æ»$Vð>«A¤ÚZl˜„èiFåbŸ491Eevq¼&â·~VUoK‚Ç,‡f“3¨DN™R–£l_ZžSC±’® Úe(+ø…ÖŠ²_^K[ó€×ùÜDJk¥„À´ÉVɤ–%µÊ4¯éÞ27F‰[íQõÔ?$&™#Œ‰Ðý¯2üKF; ŠP¥ÂÖZ§RþÇ–ÆúsMšgbÈÌ­ÑŸ[å–$MS PTm®s®>ʖ쬦‘ja5ƒ²´O ¯|r[* Ê¤åËŸJF-M- óKJÓTwŸEj¢©Åõ@FHEù|å~´ZÏI?²L6dQ»…³xNË—˜„+)Ük{Ë–n&*&¼Iû,±±¤º§¡´í ŠYªÅXohõ†È£>˜#º´6'ó¯‚Iá9®Lâ·}‡›q‡§6§Ã¨(¬$ 6-½ŒNíËA–©©…VLQ´ÈiMEhÞÆ—òØB‘‡´ xšGˆÒrÎÝ~F¥6d†Ù÷‚é½ ÆÙ?¾- (ž“ï­mðàhÐÇòI‹YÐ~ p㌥,2׌fP‡-‡ÌÁ±m"8ADD†ä! M+¿WóJ:M¹Ô~´2‚ì–úõíP&¯îOaÁ,|(jGB‘&ÕDùó¢ù¡ÁJø$@uÕ­7(UwYÔúV x,EØ :üW{Ó{_£ÃU¯*ä iá2ûÒzØàå[mN È¬xI•Þ/ˆX°gªfŒFI( -É8èü¶ äØäãj@—PV'° ®¿16û¥C¥-ƒ}ü„b–¹vZëÐ@Èk ʉ®S쇤<”-! }¥­òH:£T ÇRIÊ@I fо£\aRˆÀó6äã±#àûŒedÙßž+]i¤MwÖ×åcKês1†Œµ¢3ÞO˜ËY*1˜&STÀ™’š«¹esˆðJíÓT•)°åï‘ÆÔÝrÏ¢ÔªÖ6ÁèSk)Q;ÙxŠ£ï›¡Þe¹>Cë%€`¿´ƒúç h À[ÖÆ—Q­Ž¸fb¦Y{+ñ1¦lú6Ѐ×f3²%& è`jD%ØEm}fC¯»>‡©´GCÈÃlÖKÞ­r£r5Ç€´·òÅ jNM[žž2¿°×’è_?JûFôú‰$Tn—E/Š‹vuJ>Ó¡úlH „mH'|Õ>H¬eP@G(¶¹´ £©-@&ӡܵöä>C>`ù Q9µFC+qOà[VS%® }`x§jtZÈLƒóGñ—„NX¢ylkM–{S™|†Íê é3Œ³ † ¸­pVE¨ÿ¦Ta.€KúÕƒš1øº-ç§6qŠd×—h¦ä•¯"¤úëÞhuRx…ú+AÓ* •bB@Sò'·%7<Ðïìµ™‘Ëâw1PdªJú^ŠLkÃËÓæÏ&Wi½9•¨mÀ†oØÌ3%dçUzÞQë¢Èj±‰\þ°$C-·FRZIsz›¶Që(½CWÉ{ë¼Ç¯|¶Õ³õÜn{c6%¹½ÈôMþµ¬Eä½í€ÌÖ›(Ñ `Ú?wõàËgU©çAÎÚSÇ÷L1¨ó†NzR®GÏß³* |4€: ;PîˆJÑbZÓp¨š$?MáÒUÒ2%r3 [Â$jO±Î}Â2`ž#|ZŸ\÷dÓÎ:p) “r£æIbÈódµßM×i} Öôg[W#…³}”Œ¢†É6Ÿ£h#Ùa°òC‹DØdÓGì š­kvÙÓð„Ì ’O ˜´'ßC­z&ª“b¶Å€Ê×)STÍ"íÿƒžW;`4›21pÌ6I-ù‡Ô+EðŽÈ2ÃL´•ÚœcôN~¯ô•sˆß¸³ù—~E9¯s-VI“VÎõÝÊ ™ö<÷¾|„Jɱ d¹±Ô€·LMïꜵ½ÉÛXé:ajœ}½*Ó+ÈHCšsºêKøÑoHr¡ È$ì\õjQåe­r&caó'ê#}‘*¾HÓ.[gËDÔ¶ó?ÙÉe¸ÃF¶øòÊgóSsv¤íã$’žy8õ#(ÈÕ î ¤äÙ!ùº)TóK¦zc€µ‚ ^n‚“]Q`£×J£KŸV1VÄV‡ˆþdÎOŠà`¢9_k ν ¨Óµ¤frï¸Y%þý‡Xî{¶Ü’‚ ¥Å(ôj›˜£pX\–Œüƒ©ƒOÏË)}ÏÂ`ËÀf,ðuïíaÓfŸ|$„ù f íèK¢–¶‘w®ÅwüÔõ Õáaò;´LÐ ËRМ›ŒÅÊ_+­en¬ØZJ9'KVwBn:>£º“˜Þáùù"È ý‡”iX|’˜õÝ&Yi<Õ]• Ï¸¬KÙ¶”°åý‡ùl_rΤ?"AÌåX (z€nOÕ¾KéãƒfC¾zE¦)1÷:C 2»•¨kÓ¼´ÆÔ|”`¹–'9™Î0€ 2àqÃ6¼Ë˜šˆÀ¢–褽Ü;jãî9¿ˆ¾ ú[S;êE¹×l;U (¬aˆuü³¤¬ÈDfÝKd*% |Žt@• VÔ2,ýš•M‚í6Êå»US íqÒ½@jM_€Ÿ„šæï(ˤhˆ–©jq>û½=<é¨4M›™|4Êu£ª‰lPÙ ]>å+pe;'3¡däâki‡rã‰3ò_Æ*ŧ}Òm¦s7"32 À² ˜íÃ&¼0´¥~è—r“È©IL‹“$’Ža-€@²vsèú"%»YE@¡0B&òV\ÌNF•M1“=òÞTô)Aœ!èa”°±ÁäÄCgTÏRF gíüQcEùjtš»Ê+”®ÍEµÕ%Qn°¼g]v’o^¡ž÷]mÒyyDpKòª(IéÅ(u6™ßTMa¹ziN:*//ÖÞÑÞ|î ¤=ÒDÁvNfdê\/c|‡+i.É#Ïj3 §æm®}•¬]³Æ Ò4VŽ+Y¹ŽY ¾æª/Ô CÒ} ¸Öíîn—A2a·üAý-…\Àb`‘ÀàŸË9kiØÒ¸š1×-^Éfž˜Ü.é§4Íìb-¹ïxhúÊG,U@îœIF§“§ÌxÔÞæ^¾äÁEC¿óðlHhÅìKûÐþqV‘Ä„Áu€’ªBDÂGJN¶“p-ôÿò4¶ÓÄÕJðóVk´Õ`PZ€¤(S3:v$ ˜u„è£?->$)U«$®hÈÀ¦IÈ€3‡r|²æ°ýQÌâKÐÚBÞªèKJxç{òðàc•«”SVR°O÷šËyÇJ¿”ÈÌ”)•sRý¯}‰™xÓLrú ûüÙ™@iR#_:¯qMºôMc”t/B]ÒRZù\ ccš»Þ?GnÙµ :\9£g^ô ”†u&Fù‰Ö…õŽÞݼ$l r• ³NÚ‹ü=z®¶”+%W+`Ï?´Ÿ1ô&ÈÔÐ<ÓÐÎ{ˆG=W‘È|º ³@¨ûéS™—gAà.¯A–ÑìíÌs.Q&ZJ”t2Âîà£ö/¦ü{%lô{Ø¢h1m,‘â6|EÕ‘J…x¥•¦eç[ô¥«­ƒºË8…§ è ãµ3½~ZƒÐ§ÆZ *…MDùµôõm”Ó£öHâ‡eÅò)L{ŠŽ²H†kpÒšêŒI>3˜›léˆW«œ5§æ‘ˆžzc3oV&{*£ÛÑe@-gÙô!£ð=ò)z˜º¿Š±Tt^jp>Y„¿RëÏFrÞ®•c4ŠëVÍ '^4!ºS…ˆ:úÀÑFŽ%Ï\?åN‘Ï”dP“ËAÒ"[DS¸YÏ5@¦NR6Ÿª÷a+™=Ó@bÖ¤ƒÂ‡ø«6WÝ=&:Kih>âÐd㻨INyçŸbfâbXiÎI£Q·¨¡Ì»ò­FO^PµxjnÝI£ûÄ5 èÃ"áòº[=¯Zc¹ö ùa¨ÍF6A¶£‡M؉Šêš0F¬éË i=äAG~îèyD&ÿÂ奤pÖÁ”/ ©]+0Ë®Jƒ“G¹×µŽ¿4•yÊŽÒªG­­î›ÉQ]½¡U¦¢´AI›$T°V-Ts í Vg@òŒÌR±W¾L&¨^g¾Ö$óC]IX…£•Tk”ºî9½}½ w¬·àŽø(+ÜNHTÓæ*;¡ú,¹[‡ÏznÀp• ¥“;¬á»êJRI.³Ð‚$[7kÓ¨R«¹§ˆ±aùéójÀBmT;C/(éVÚT¯·Æ*3_Ò°ºóÉå níF)iÔ¢&‘ `!’Èé¬7EêT³f­px ‰­ç^Wí¤ó{ZÓ8‡C¦"޹îÌ…DL¦Ùä‚Ý1:*¾¤• Ñ;­LÂ)¿Ñ|%è¨WË1ã Tž7‹œò¿LKR.¢µ5Udm±KHSµ«Ak¬ï•8,š* ÝPv о03 Û`‡aÿæžØ¿‘ ï `lÿÄ€›’¡gA¥âø|jF€Õ½M‘XΖ® Gæ¯Êk”ƒô¢ ¸±F·;ƒë|_wîå.m¢fÙD¦ p™ˆÒFjeÞE-Ž|í’ì ßB ;ojÔroýN3TÒÌ”L¹{{Å->Œ/ûšÇ⫾á‰8â¨ýÛ„²»v×îú”_à–›îÀoüÚñû¿ù×8rßIXÆa™¤jz }¥VcbLCvNv‹êÒPÅþbs P©‘bF­]-Ü™(Žm!žÀ™H]Oð‹ˆAzlÿQvéÕ‘¥¦§NºEÝöÈié“‘†Ö:íc¹'QúêMp8ÖXáëmØqþý¯~7Ž8rß§vw×îÚ]×uë-ðÿüß!î8û—Ã1 اSQ˜Íc(u¬ñ¢ýÈA d0ŠÙjÄ [©ÔfΡ,ÊRøP5I%³ÓýÐÁ ‡=ýA?…Àüÿ)¼ÀPqT]¢",é˜I·m{½!O§EÀ(gjåíœ Š^:„ÊVQÓù¥Ö&À‘m®÷pûz ¾ì9Åá÷Ü™¥»kw*×Gî×|å£qûz V[qŽÕØöLõ,à‚uv€0¥'Äž‘?&®©Þ4m ´¿~9ÓaS`6‡Ô(5p6Rç”07ê¶ ˜²×TúªŽPJc%ÞV_Ó°…¢¥ ‹~ó9Ì ¬¢+[;úb¦¶»kwí®Cìb­ Á}FvQ¶Tt6¦f =Y»o­É1çv¨*; ÏùJ ÑÙC.¬Ý^ÙÀÝKè6S±€š‹š›¶,(žüy+œj¥4°¼úÐEbe?£†áùh"³¾×ñ ùøªæÕø!#ªÛ0þi_ôš?Åõ7Ü ×á„ãÇi§Üg?às0Æø{¾ý©¹8€ßzåïÕïc,8åä{áÌÓOÇYgžþÃÇ{ýcë?Õ+h± 6rHM*áIÇyNúÌÔܲT±)À… Æj¦a:Fanõ/<‘—.ñBO ˜›¨Šfv$¢j¾Æ)ž‡Wzžu¢ ŸžŽœŠey°m¢ dnœ V3TþòÝâúƒ?~-.¹ôÒ;}~æ§ãÿøß¾ :ûŸö1Üqà~ý7_q—;ÿQÄ·ó7âÄNø´ãã¹þ1õŸî5ûÚåNrX,•*ÒY¤ài¦ Sq¾ YoØ£NïªÎ1S” •%5íè3X6‚‘£XÙŒøƒ@`a1k‡2Ôk Š ¬TKÖQE]ݳEP ê N™zWyܳý²’ï>—óü™!;l?®ºê¼úµ¯Ã_¿ù-ø‘—þþÝO¿'žpügd gœv*ž÷ýß‹Ûo?€K/¿¿ñŠWâ¯ßü\wýõø©½à3¦Q~ìëÓX?»×³¾î_àÁz ~ð_}Ž>úhÀM7ߌŸü7?‡w\t1~ç×å“|2w‘å– ¬,´RQºzþ‰7©…|ekX¶pW;w5µd!oXª`Uîŧ6ð¥Â¶IðËôºa“¢§§Ð @ê×½Œ7›­µŽŠ"Fcb°½6ŠS)X-‘ÑÓÈl•‰A t÷ºî}¯“pÄGà´SNÁ£Ï{^ös?׿ñ/ñòÿö›øWßùí¸þ†ðG¯yžð¹ç#ÜñÖ /Âýïs<äA©á]uõqÑÅ㣽|Àýð€ûß¿žýú7þ%6› ÎyðÙøë·üO¸ãuî¹8é¤mMg³ÙàÞ'Ÿ 8ëÌÓñ¹y¾ûûŸ‡÷ýÝûñÚ?{žö”®.y×{Þ‡÷¾ïœù» IDATïp{†sú`œ|ÒI€ßûÃWãæ[nÅ3žö8ö˜dª þèO°wà¾ø‹ž†}ûö!"ð¯x%Ž>ú(<ãi_€ßúÝßÃÎ~îuâ‰øÛ·¾á+>÷üÇÔ÷ïêúxÇxë;.Âe—]Žc=ç?ú<Üã°Ãj]ööV<îüGã¯Þüf|ä#7ã܇ƒ3N;W]} ÞúŽ ±Y6xüc#Ž8bëýÿ«ùJ×§Ÿ†w^ünüÐK~/zÞsafxÁK~—\zN?õÔOú¹¾­`d»š”U¦„~¦ŒAÿÙ.ßÐÈRªèÇSßBÞè^w†lç¶}RËf¡­êD¸¹w¼ŠBR“mœ"ûíoy:‘¼|zfkˆ@6©£ŠÈH`–oînud—ÍW<¯ã_âÝï}À‡¯»ÿí7_w\ôN\tñ»áîøš¯|&röñüüç—ÿöööêû_ò…O÷}Ó7þì/Þ„w¿û½X6›ò÷~øáø¡ïÿ? ã qðÚ¿o?žõ%ÏÀ/üÒÁ»Þó^<í󟄈ÀÏþÂÄë^ÿÆé¾}øÎoÿ<ù ÇûþîýøÓ×ÿN=ùd<é ソøË/Üï>gáa}.»üJüÚoü6žñô§üÆï¼Gy$núÈGpûíw~ý·~ÿÏK_‚c¹O`¬w8€ýäËðö ßY} O:éüÔ Çs4þì/Þ„·_xþëÿM\÷áöíÛ‡§}þ“ðÇúgµž¿õÊWág_úìß¿ÿïÿ¡týÈük<ÿÅ?ŽK/»?ô⟀™áý—]Ž{x"~ø¾ï“æ1é912ÜPñˈÄ:ûÃÖ¦£ìbL­ÌM­ØxÞÃ@Ýiè&¦zž:8§¹›fëèn¨ä+ÖeMVuEU°? lY\Ï© „ž!÷Ÿ© oSªƒ ìJ’¹pz`F[îî×i§Ü›Í×|ðZ¬kð|á;ß…/}Æâ¹ßû]xÊŸˆ+¯º ÿé¿ü*N<þxüÄþ0^üüÄ Ç‡ ^ý'xÛ…Õ÷nºùf<íóŸ„ÿ÷e/Å×|å3qÛm·áååï8Î:ó À•W]x퟽¯{ýñ¨G<?÷S?Žïú—ߊ½uÅø¥—ã#·Ü‚Ç>ú<À;ßýÀ[ß~a »ÿùöwä.~à1|D½çúnÄ·~ã×ãÇ_ð<<äAÄ7Þ„×üù>¡5;x¬¿ýÊ ðö ߉¯~Ö—ã×þó/àŸóÕøÐ‡®Ão¿ê‚úÎí·ß'>î±øé¿O}òçáÀxý›Þ„ïùŽoËž÷\œyÆé¸êêâMó?þÞùj× Ç?ÿqʽï…K/¿ï¿ìrœtâ xáóŸ‹{xâ?ìá´&óˆä{žGDJ»¢»«ÏŒÈûtPPD Ôñ˜ É(…0ÝZS®>ëäïà‡´ª4ÓŒ¬CYq0õ©ø!ÀISäð´SO|øúîòÙf†“î•üÆ›>ò1ÇñjCgœzZ¾ïš;¿ïÔSø¾nÄ=; ;ç!¸ôŠ+që­·âí]„óq.Î?ï‘xÿe—ã†oÂE¿ çžóPìß¿wuwlš¥{“æúñ\õÖ[o\}Í5¸âWáÚ_'>î±8÷œ‡Þå÷å{'ƱÇ Xó„é9ÿCíºþ†ÓD½ü œ~ê©8ýÔSñ«¯Æ ^ò“¸þ†ÿOnm&»¬ˆ:øf¤Ë+:Ȱñ¡ãgÔZMžˆ%Ú`Á<»yÀ‚>¾¹zŠ-Ñ}d½|æâ­Ø03jþ[`¤S{LG•ùžÅV7^ã=Ýà¡d«ÌWåÊLÝð †…'ê¤%œôÊ‹t7÷Áýîïÿ!àüóqg¿Óô»|TW]u ùð‡Þû¾K§ž|¯;¯cîŽ÷_zÆ8áøã±wàÀöóy¹;^õ‡¯†™á1Ç1Ç…\}5>pÕ58ëŒÓ·Þwʽò}ç?ê‘xó[ÞŠW¿öÏqãÁy?×ßp#.xõŸà^ý\Ãxô#Ͻ˱<†ÿå=ÇXO>ùd\~åUxÆS¿xø9û9qŸ|ý=ó?ÔhöE?ù3¸âÊàôSOÅ Ÿÿ\À¿ø'pÅ>€ýÄËð3?öÂOúÙ¥ÏXÁ´`@àÖþ{s™ªù­ P¡"ZÌSGXñéÓH<,ŠUW&מU/9uæ¡`:Æ“ÊéTí¬& ˜{楄ñˆ:¦€DÝÑ߉nƒ"ÚÉÚSSÜÃ’%_¡s05àè0ÍÝèúÐuƯ½ïxçÅøùÿô˸àÿ§Ÿv*žù%ÿìc~ïá}à·^u.ºøÝ¸äý—â5¯{=ÆxÌ£ÎÛº÷ÿ{Åïâªk®Á+ÿpË-·¦µ¯›ŠØÛÇ®½W]ýA¼ù-oŽ䥸»K.ÅÓ?ÿÉ8ûŸxÄÃ(~ñWþ+.¿ò*üÍß¾¾óbœtâ øœûÝð˜ó 3Ãï\pN8þ8œyúé8çÁÂGWýÁõˆsÿAëõñŒõñy4àW~ý¿ãC×^wÇE¿ùÈÇÖZ?Öõ±æ¨]—¼ÿRÜ÷¬3ñÂç?Çs Ž;æ¼ðùÏÅ}Ï:—\zÙ'ýÜ@úëuzºŒA‚˜ÌK6ä° oxÓ_á¾÷9 ',î¼Çwõû]ßóñŒõó?ïñxÛ…áuox#¾ý{¾ûöíÃðßüø¢§=ezöÁ|pðÏýî5ÿCf_ñ«¿4ý–c;ñ3?ö£[Ÿ}âW*!ª ¦¦éØPÈOtÀazp( sV÷ŒœéÈËœÙ1¥èn¥Ï¹±’R-MT3™ª¬0jj5ºLjÆÛ ìZš©£&Ü/W˜×±¸©›/¨’¶Öww¸¾è©OÁõ7¦?d§Üû^8ëŒ3qúié×Ñ:wܱxγŸ…3N;õNkóÍßðuø¼'|.Þýž÷aÿþ}xðƒˆÓN9åN÷½àþ5.½â yÄxÔ#ÏÅQG‰°Ù·Ïyö³ê¾ÃöïÇé§žŠûß÷,wܱ[ãØØ~¼ø‡~oyÛ;på•ÀqLJsÏy0Ž>úè­÷=çÙ_w½ç½xÌ#QŸùN;õ|Î}ï³uïW=óË0Fr 'à9Ï~î{Ö™wšÃ'2V˜á»ÿ÷oÃ?û§â}—¼@à~gÝgyÀç=îq¸ÿ}ï‹£>*eø²à9Ï~Ž>ê¨zÆYgœç<ûYxèƒÎF|óÿ§|E)HiÉèú#?È P5Ƶú›€ ²øŒGCË’ÓóÓ–®1>/tÒ»¡AW[,c ØÓÏ~a„1ÄçÖ—4n¡#ÀˆÃ–ç08U9Ì›wzý$ã[¨Ìƒ½ò``DõoÏ.Âlg+Ö8;°úG±®pÃm—ã‚׿ìÓ¾Qw—ëÇ^öoñ?þö­ø?ûÓ‡¤)µ»þq]_ò”çâ¸#Îİ{`û±±ýË‚ 6i>Ž4_µ©#¬@P‰hSjÿ³ÂÝ„Õê„g”<Z®ð‘xâȃ³v&ßäó•¿¢sQó õt#X ‡ì©NËV'ÝWou$,º°P§£VúES4' [uTR‘½ºÜmÄágâº+Ëkwí®Oò2¦uØÐá‰]Q *„ÉŸ^t—†h¦z0%-Ú}•¿b `¤_Íyï°´Aå§—j¦Ž¿Î\»4Q]/ïèEŒ_ÒÉX`”” &åW‹Ìm ˺ëH/Ó õ=?k–WzI›èU~:e<ï®OõµC¸Ýõ©¸‚fevçÀyør9ÖÛª±²i$>8‹óÍ䣕ù¬€ñ°ç`ŸÉ€B#Û‚òägžÂ‰S™¢ ø ÓøÔó¼¬OD >X¡Þ1›³hŸ^/†Z#%úªÚ£Ìï-Wßîú”]ÿ÷÷}Ïg{»ëŸØ¥0ˆa…ÃFššÃ2‰Áhë¬$ÑÏ®ö¿ê"R…ô ®«­–ìT˜Aêe v'*j›|¼Ìеöê§žcè`mÀãÀêÑ‚²ä5û°Î(«Eu-Ùn·í Ü]»kw¢—šY’aÊV#{tDhJ*ÏÍØÀC§D§¢“?»)‹ú›Ž# 6R .(;C%ž¸ƒ>¸üî`(€Ž<ÓAÁ†:Ð!º¥¥!%ŠÓ®&üÖó :A¨­NÂ+Á»Ð´Y ¹»v×î:ô®4WØØW¾´ÅS“Ó y•.ÁnD páÙ7`¶…¥ææÒÎXÂésÙV¡B9aYwj1*--ÓN„›ÒDr¨AJ¦d°ÇÛ@µ2)«fððŒ’ª=Š`+<vÈyµBjËIûàä´ß6½uwí®Ýuˆ]Ù| ØÜÖ̰ZúÜâ}ùÖd/ƒ“V¾7þkøA% G–>ᓪò“î犈f±ýdvê+ ¨žl±^~µ¾ú{¨†w RD8²œ4µôµ¥cС³R30ѶtÖ® Fn5¹Ý©Z»kw²W0hÈt1P몃ÁãüÌ–B›·¯?Ï\‰V|FÀ­OØ«t4Eb3Påt¨4ÍÚ:#&t£†Dé›]úi–Êy¨¶ÂŠkÊ€Í÷-È.NŒŒ=Û§Öš_/Š*¶×ªúÅ¥Þ¹ÓÝv×î:„¯ªEbÀQÚJÂOÒb—a£À/3+:­D^5)[ uªÑ®aiÓ–o® §ñøçòÛ3hjžÇްj6—ÑÑQ¡‚˜šSfÄ‚¡Š©Éxi]Š&ðÞŠT`:Q‡ÑRÚèéXPÛ%cà!Çj;Û]»ë½Z)‘—^G<Ó?65ýæ¸ö1qp]VctËòÝ#µE±jô :Q#˜¡‘Õoà£#%EM-°F`‰ìµn0¬–N<+½I!ÃØu„]Í6·bhv&a«*2”œ“pNJ4Þ]»kwz&,Ù-ÝSê\è@,ythº¿¦Bûh@̶i ŽèwÈçV¥¡t…±4 è¾–Â6Ý(.D`!Å#o¥üUÂïÖ£ª4"êEôÃY§” t ‚ÀK®Ni³Æf­Éí®Ýµ»¹+X²Ë7dÍ­eŽÊÂX²kï„ÛW¤æ•Š29œæ¦â±Ù­Cii¸p ”/ ÀÕSÁL¤ –bùR¹%™gÒg v:É` à2Ç¥ËõórÔ8§>êF^ÃÓä.ó:ÑíÊË.ùÔìÆîÚ]»ëSzeˆÒ32™`†²Ò2—Í*0ˆrg™­P)T­ Ê( ™P7”$L?½©*Pp)Kب ¹Úþ:TSÆèƤ¯É–N`S;ó6! ÁÛZ"dZœ‰ç06Ò´ Üô†l,ý¼§n¾é\wíñÑ[oƒû'Öáuwí®Ýõ»ÆXpøá‡ãø“NÆ‘G“Ú/Â1ôJ׬ÍÏ-€Å”ÁÊ™gú.Pù²õVB­ôÕ ÊO_ŠÌ©­ ©çï›Y]Ì÷ƒ“B²<¢B´Ó Y•·fÕõ-‚ “) ³*€í6*Þþ? #!̹à ª¸ü’÷âÖ›oÆa‡Ž#ŽK—™a³o–Í·Ütn¾éF”!ÎT2ᇲ0èó2áh®Ê×–Å¥éÕË:€i1²)‘¥º¥"`ÞMb‹Ç^Ry' ®õ"uä…OÅð³Z ðV}@¬‘„.×`0ƒU ‹MåpÄð©£Hàºk?ˆÃ?|n»kw—™aÿá‡ãÃú`¢±LAÆÈHjY{Œ~º¡Ê5ê:ädDtÙdB¯ ÀWjnÄ Û*1j€ÛŠ>pÚ86ÒªRµDED£ÌG£é*V€ef&;ˆ Z LÖ4:ñ7ßcžu¶“LäËæ—¬y…᣷݊#îyÔ§w×v×îÚ]÷µÙlpÛÍ)¬ÈzÎô«çÑV:✲Ӯï=œû~žûzöpík#Î\fìU%FˆjštÃð ''—Qñ1ZBÈDb§á´iòxÊ¡µÎÕä¸ BêŠè^(àÀXkN¯z&† ¶:­‘)(a„‚ ;¢ª°”«†R j¤ú/,Nü©t29Sb–p^L-T&R0Ö5‚L5`î \'8NWb‘RÊšÞU=ûÌ›h Ùpïds!™þS-—ÿ­2lذÕg 9Ûƒ=C“Yb L!Ƕ¯u(ͽû›gZJÎMÉ}Cv©I,…7ÇíUŒÐ‘.z'1Д4ë:ô - Ö C \…JÃmI Í)~'D%ª;*&ëX#,dd?šy“¦Û %‘‹?üQ|ïÖÛîòï?uÆiøço]‡­[ïÀÉO<ñN·ù·›oÆÿ×Õ8ýßÿÄ.Ÿwذû³EëfƒÛ„$6d¸c—ªFñoÆw]x—¹ü,L8ÕE8K5õ‚åiŸ„QíÃjª6Â^a l<°Òeun¸SÜ1Xã NÕjVm3w,(0'—=e¨ÙÞ…:Å…»š7z²ðÝÛ–ÛïÀ–-[°eË|ñê/㣗~*ß²e ju|ñÊ«ñ??{Å]ãŸ>w9Þüÿ¾ ·mÙ²Ëç6ìþktiÔni*ç³x÷躩8T+¨VÚó¯f{QÌò¸¬ÎZèDÖé.qgÅ“wCz–®±Žh¶6.ª¤>bÁÍyŠ ivÉ6–w}a@×oj ¥IDeÈíẠ¥ìºg9lؾ²¿~ïð×ïýÀ.mûœsž‰çœóÌÝ:~¤°¬õœ"Õ Ì§da¤˜¸·–N’H²¹=h1ò9öŠÿ²Cky´BqΫ6T1c"9€"õŽà¬É© à§–7o:O*HÄq*4¿ëcÿi4æu¤oäçYM¹[÷y·ì³W|oþÓwâ;›6áÂK>ŒßzõǶmÛ×_ÿ\xñ‡rÛ¿~ïðü\÷¯ßÆ×ÿù›x×_ýÍèªöc» Z{n@Ãp~Z Uê½AT…°¶¼À~M¹V µŒm Ì­åשEŽNEŽ™Ý®ØàEsQ š,/a:ÍfP…B t´–$’R€®‰¯‡„9*¬–|}QÙ*Ü&$—–q6$µYkÚËö¨G‹WýƯÂÌpûí·ã—þ˯ás_øžròI;mûÁ~/záóñcOzâ^_ǰa÷… ¸îÊ“ÛSp“:U­É]€µÃì™'N1÷j¿nêaÏÝ: ŽˆJ%‹Bn)¥×@î­2øÕ€™ZMÆHe ÄœI˜·™6òãjòS¤ùTaXACbaÔ¼D;ëÆ„U潿O{Ù:ð ôÂÖ­[‡G÷ÜpãMwºíy>ô±Oà+×|µŽ²a?˜öœsž‰_xÎÏÞéë߸)—æÞ)BPJáV‰€RoøA1¤Ø%¥¼£81[¶0 nû Ð 1dºÌÁ‰+ê'Õ,rrÏJM«¢m€b… CºÆ \IÄõ,6XmÕÖ<ŽY$uᨠ/Âd^"gz }?åÞ·ý×íÏ2÷Îö/{1ÞpþÛÿøðÒW¼ûä§ï“5 ¶·íœ³j ä¾op(ŽAÊGú+Î9/-߯0]øhškŠ ÷9Ta(Õ1U ºŠMË)+F“f+0—8N¥Ã¥t ÑÉ p3ó}Æá lƒ0ë¢Æ4ù©±·j*Ë¥ÁsË’…<<ƒUÁcg¾²jÙª› _^ïC;êˆÃñÿ+øå_üy|ê3—áÍú.uÄøÑG=rß.lذ=°sÎþ)lßùæïÜ€FA——6ýjLUÕpbrÖ©g¡BTÌ«”ù(ýÜ‚$3dé Ÿ9ÛÏâZ8CY˜ R RA%ihœÎšw§ø±9¢‘vÙhå5%ËÓ×ã¬BQH4Ü9\מ‘¼”wܧ¦°ô€õëñOû÷8ô‡àÆ›ï<œ6ìÁö†ç& KÎ ¢HêQç +cËɽP(·Fd²Yi²”PŠÃeÚ <Õ)ÕÓÎ-%ñëо}'ƒ–*V±<;@qv“#Y“Љ9<3!tWEÍjI†ž%VÝBêšH[óRMâ+ÍÅÝV«ã¿üÆÿG÷qøƒðÍk¯Å<ÏxÂc³W5lØ*3gž>;–8J°…t0+èÝ(4–£b"‘¯. (¹r"É™˜•yyB ÏýáDßØÈ€2A²âpU<=\†R4†mr¯óMJá®s]M×ÓÝQUÔûU¢ÕÛ·@qBÅÞóGpðÁ;½þøÇ=[·Þ±ôÚO<ùÇpØ8ê¨#qöO=PŠá÷^õ›¸òË_Áw7?þc'ã×_r"Ö¯_·‡«6ì‡Ë"ÚŠJ¦½…ÝIî+ìaªÂ‘(OLñ6ˬA«”U^/ IDATüX›SŒ›…LRÀEÌ4$Z#œ%4ù) /‰’Ñí0'pEìÛæ¨Ò ~±a)Ф‘"ßæ¦ŒÙÇÊ´eÒË{,0Ìé¾î™=êøGâQÇïœ'{üc½Ók§žrrþ|Ô‡/‘|{ÐqÚOüø®bذró(´‘:HMº ‰Ú%Š PªF1Òø Äs+äÀIɨyiá^EÑS=¯áTEñ""ÔŠE*mrÑ@’÷¡_»¨9›¯²íÕf@­sŒÿ²Â(ÙzÚÖT§TK7Ní[ ‡ ¶M)(€Ï·MígDBM"˜KIu+(î®Rõ¶æß+Ìg„â‡Ñ's?Äq¹I‘—ÇÂa9•ÞàéXYzX‚¥JÝ·ÒåÕtúMc¾´ÈXN€yÓ“[$·ÔtŠVPP(š·Ïk Æ »[cϹRatÜU:è°@¡«rq¦Y~U£Vý6ϼ¼ó$f–P o5,PKV5#¹O58zý67V4<´ MF®•lÕy ö±QÌã™hz‰EûRU@íyãÀ ¶šÍK°#"ÕT‰€}eׂɳŠâ‚¤Óô”0öõU€åƬwö=óñw¯¢¬¨Ø/Œ®#CéägTñã”7s Èyñ`]ó+j„¹U ÂJ6ñÔo ••Y0`Ž2³óï6'+º´+6lØ*4©öæ\e4J˜#ЇR ÷ XéFšúÕKóº’râ R± [­)½Ô¹ s…¾cjÂ…GrIÊÿIòHk墛?vªTÏΠ–6ÃÔèBÊm4´ò°åm®`Zvòó¶94tfذa«ÕLåÌnìAq¥µ{BúF•zR,*JþÃ’¨;±J}¦V#L5¦²sæú²f€ù”øµˆÔx“'×UI)öª¨`1K!{ÏD Fr£î)ŽÎ8–®,GÖ0¬Kj”QCÏ5‘¶e*¼À°¶ÌÝ1Ñ‹Jç CeîÜP¼©‰¸ÂFù=5ÒQE¡(¢©ËÝXXª¸PQCoR©2M´'†Z‘(&q¬äî%XÕ³,|¤;—Q5/R?*ïÖS=âõ¥^‡8!‰ì%wWZ’院4¬Û=æ•,Ö¬Ù[ïϰaþ[YÙŽý×À–)h $¾ §zyUÚåϼ•a…^;A¯IAD…ë0A5 ï VÃ,+N¨nY4ˆÖ-BPVCýeáñÉ õ\¤[‰\œÉ EÄÙV)ŠWR\DÀWªGSmVMu;,OxèaG`ëÖÛï²!~ذa÷¹Wl½ýzøá-ŠS‡“Q Òjt&åœCÓžÔö…y3 "ƒßJ ÊïSZ×È®È këÁrHk&@´U­*ÜÊ‚âjšRUu¹ìëªÀ*'g¡´é¾Üæ„a‘øâFq«J¿°°›äzpàAã€Âm·Ü‚ýÖ­Ãb±áê°a÷±¹;VV¶cëíwàÀ áÀ g¤g™‚js“Õô^ tNbZ_%@™SÁH¢XñÈËE +@S’•‘¦™§®dRÒ2÷ï™j³âX8Ý@ÍŒ®¬ˆÆl˜YÚzÂŒ1î’_ÈcMïN2Æ ]ÆÑ›ëºÃÂô 3âu©ý>ä˜cqë-ßÅÍ7Þ€-·}uˆaÃîK+SÁºýÀCöð7Pʨ‹¶Àç? Œ¯ùÌ΄ªAÞI«µ½8¬D+ªg$ZÅfn̽I IJšajÀ±-+(ejü6¨¡•ˆÈƒ˜Eÿi8[‘ôÒ-˜ÈÝÂM q:,&r™Rpª¶€ &4ZÁƇÿj]Aõîsª”Hl3´§Ú¹Z§‹ÿ[ÔŸ¯`§}Ú:F¿‡ú}S¾OIzû‘7â¶{‡äö·¦å;ùå*û•9š4Š=;^yžGû.gMw¶ô±ó–·Ô{¾ãb}§‹v¥?ДôåÈÏEÞ?k»õ×´ãõô§ÎTñ[¿¿×ú»Hž|¹;f Æû_þ|Ýû“‡n׸ãWj¾§àúÒêyÒ^ÌBÚi9‰ï®î»q^I÷>j|'rk cñn’UûlÛï¡îcöªw¢ý– ¹ŒnvB B-ÔÚ`¥ÀlB±ý0•ET:LÔûPc=S¸,.ÂYíøm-̫횒Ƴ>ïw\w¡ã—®1¨á .ª~hL¾SM»i¥Ë[!ZˆÞ) ÕÝ2±óÍT¿)ŸøÊ‰®á­˜0™aŶ…&´öh̾sÝ÷í9®3γ¯¥_VrM¾a~$Èîz½‡ÉØŽ¾ØÚy®|(ŒÊPKaPÓÃoù.AN¤._‡ˆÐWP{Pú­ÿ‚jk‰- š*K«mëhíè*üè®uŒ­/Þí¥”ÆÒu,?,[úBÈ#›¡ziûv9š%Ü7g?´ç—ŸŽ‡îê´{ª÷Ú<')ÝÉÛ—ŸCç§ ¾•eº¥¿[í=Ðqôgy=Á¡ŽKOqŠXwÜ_ïîú2ê=×—jÓ[¬¨Lß8–æðu÷=Ä.xöÝõyÓ}1ä-[rH‚»ü…j®h‹ó¨h– Å&”²@±5X”ýP0Á°†ŸÜôåÞ>}º&ý·\”·÷^ïßï¸ݳj —VÙ'`@™©UÜ»îÍ^`ç½}y5n˜Ú'Ò£á»nAôŠñ éÔ@éé…`]{€œç*j&Å<¼Ê_1±x ¦üàà+ü!o˜ÖÞÎß-ßgÐpX½eÉëë]kÿ1è™ï°tठȫé> ¢KŒ¹÷à, ´ê>GÉg†·¯0¥©®:ÓÍâ\X2OsPâE:÷S¡68yæ€/¿†nxé8I>% âá­üêKÉ*ÍôºbœI87ë!?>Îf™(¼|*0a~™9¼,Pª¡ú„ɦh<ŸÉ•5]hƒN$#žu±q ‚Ž8ñÌ›Q\^f|Ý’®È®‡D»ÚL„Îݪp©&á9–7¡:íé&¯hòtÑ-Ã;'¿ÏH\Ž›ä{§ÿê°=ž‹Ñƒ邸›óƒÙ|³)LÞ:ƒ/±Ú”#òýè?ÕíAnß#ͧÓÝžðÉïŤ_4°9ÞC+‰7m,¥¶Ëo>$¿~òlYt¬v}èÀyëB$ƒ«èÞ8}ÈÌ»´é+ýùaüü¡T|ž¬=÷çÌûÁÏ_¼Õâ>5ÏÉ&:!í-ÜzA~ÙNz'D¸ç}lï‘HËIòFÎ ŠM€BÔ"”/Ìás(<Á –8F©º›|‹>S­CÝÒ{1VGu à+Qd°ã2ëÞMäã9f«á°ˆ[lG ûtã—¿‰½Z^´ó+^¯zX d¶ü€¨åËÝù¡NãcÙæåÅ1Õ˜³ZøI2) ù~|"–¶žvx ´AWe²•¾€ÎЭîÙ°úãæqÿ ,0ÚP]CóÌ':-ãtÑMwŽâ ÈÛ#o–ßín¸@‘ßþօΙ€Óg &€UzX6òÞÿ$…ØÌ@%cu½½çh‚7Ÿ:6rw§×]Õmßïˆââ,S1ŸÅ"ïPŸT§h£*TDø¨-½û(èóˆhWBGŒÏó{~”›ë¼®½,åË4}*ޤ9u \¯ç^"µ)ƒÉç–»ËUÝY†Úº+Wú*‚Qó S­ ææ¬ Ýf7À'‚-˜j ·¨b@q6 0?§;T¬ kÚµ·¦µ¯¢IÏ{+=8Æ®U¾iƒ–cò ]œ9…ø’³ü»nsBh—¯Ñ·kè5Åm-0‚[ñ8g5÷ÝçûÚYdh®©@«ä,ßßLúoéZâ-ôJäº'Y1?háå5¯6Ÿ[È»“• (̉TkÁYñ¾µ0I¯õ§m©©Ò¼FzOŽð„[Tø¸ Øøe`+ÎèâIj "D’V9 m [åkÅj«¦““4› ‰'¾§RTuà­>À‘§š  Ýá%$ÁŠ># »ez#~|Mny÷'c~*óQÛÅ!Ĉp±¤gV¸HÇÒ;$J<Ï_ó]=PX¬CmC—Š>l¼¼÷â<Åíc‘1X%Èü²âjÝL€Íèy§!0YÑrrJ/µ/]±LyŸ9á>¼^>Ñ™‡½”}Iék¢…£Ã¨ôàè@´tˆTÕ®i¨Å*о¨âöFêÁZÞ®¸'ÐægÏâÓ0“w Ý]wÖâÅ…r0¦7D‹.f郙o‡µº-ÞWøÒci PiIZ{0…´üÆA‰Äád(ÎÆ}z"+u+æ•-Xñmp_Aª,?ãÝGSŸ¾óLJ•7ßZØŸuçG%«Tú§Á'ŸÞ¬ ™1nLKþòeJš,&ph®ò:\ ÃN¡ÌiäEùÒÞ¦<^"tm-ÐzŸÚµ9]¾Ò.=¿È°¼Ÿ~×7v·ï‚†éôý}Ò—%!®ÃÏÚ§ëσ{»7Œ%@È×»÷¤Û­¿(âèÝÉþGïvñ¶–þ8 û¯¬ØXi ãufý³Ë5êxЬô°ëm3>3ÖY˜ƒ{—ÇUò½ÝçuÆ&µ[k|‘kž¨¾nÚÙÚm|x™Ã,SÙkÊ:,¦ýùzkÍ-xJ©Y<Ãî­pY2wµ”üˆué³âÖ1úçÖòÞ何³¤7ª{³2'[ ‹ôhzoÃúM-O®†xÏØ Ý öìðÞ€/ÝÊxøó–ßýòé­âaPa Ú ¶lÿ.|ÌðŒgŸÿÉðЇ2âÆíM»íÖÛqÝ77á?~%.ü»OãÛÿòpÀ~‡Ø°¼,CÁD¨0[° ¬è-\µ† *Y5¿¡'ô4À×—pa®Ï²&NmíB};㑯v%¯›ç«©h®ž¡£\8C ç°U¶ezÕU 'Ây üê0º¿ê„¨p,èΠüÊì ç8>*ê¼ [ý»xñËŸ…ÿüâ3ª 6ìÞ¶yeÆ»Þúa¼åuïÇþÓ¡(Ó~^ÅPjÁäšle^™†`+V:(L¦;$^¹\4ƒbÕ [ÎI­–ÁÃìÍ“+à|ã¼ÑwÙ”ûÙžàšÔ:‚¹ ¹‡´ õ`(¥À<´šTåÒ¿ ómj]fÆÍ©PV¢ºWlÇ-xí[_†?ý„½úæ 6ìîmZLxáùgâ¸ãŒÿzþ±®†E‰ÊefLºM'ÈIrC-u)Ò ~a;HpSú!Å,Š3aV}9í…ñ*9ΑoKþ¨ÈfVsë ¨’Öl¤u憪-wD"’¯^bn¡q’s燗ZPêpi¹;&x) +‡VpÛöÍ8ï?;Àmذ}h§žþ8œû«ÏÄ–mÿ'òÈž²Q-tk|«¥s¼ä†R•ņ€VUÅGT1&@3j´D#B•ÛÌcÎé Õ…ó‰ÃhTóq‡±©>h6gtÅàbjóòœ‰>Ï€]‚˜+Íü¼0š<ªŽí\hŸL +u+|Ì¡xþ‹ž¾÷ß±aÆí–=ÿ¼§ãÈ9µnÇDzH5N[ä‹#}G8©‹,¤œôƒâ‘ÿ™É¶T´RÝ ÍwcªXD‚ŒâߊÂy…Y‰% [Þ­z­ô@¦ H U­ ONd\¬G¥É”—¼Å·Í·ã¬Ÿ{Êȹ ¶ lš ~úœöù¶`_XAåô«¬ ;RÕC¸¤êhüÒWÇÑXA°6±ž;AǬ«p*‡ÈRCÔÄù§ÀÅÉ“«¨‰»9Á§2‰”މ^˜¸VÖåÖà—gº Ã’ŸØJ%ºàÖNâ0¬øV<å'{o½_Æ ÛMûñŸ|æyk+$8;€ÀêçáêlÎ>K¾¥ªžé¯[`Ž Lkq;¯³Í,Ì€×$öVCd@­[nÑ$P‹Ã‹±ÈÀ(ÑQ¢' û¼‚ã,õ‚^fP@Ä ï(x™pŒUW#‹w^z YýðèíõÝr¦Ñ{®+xð1‡Ý«oذaÃvÝrÌa¨¾+ž¼H Enh¨@ù|mÁ¢f Ϭzã°Î%õº;[YxesT'öÀ.‡G/«W’Ê#ü]„W¥ÊDœ¸2UgA°'ý%ÚXm›m<†EV4Æ´%ºÖMãRÓ{U€’ÅJò•8ÞÏmذÕb´Ž }ñY[›d%K»0l¹z6Ú€WV8‘-w‘¯“O$ìñÀŒv:MÙ_è|±M ÑÁ  ‹&lÑç¥Ä˰"×i†t¸˜•ai6?¡5”ÿkÝÁÿ@J¢$A°‹ßK…ˆaÆ­S~=hg¹h…€hYœµÕ{É=ê:yr„·†11ÀÒ» = •¬’òlñï…])Õ‚LRñÑ÷6+ùïmS<¸˜‹Vì™r‹0ybóûèœúêòR»ÖsyzH_Ô-ÊÌ%oΰaÃV‹=–^h …«,>²§ÙjÉjiX_ÿ4dïi–)H+QYTý ÊHíÂUcÞ¾v¢ÒÜXÈ£Ê!ËDÄ"!•R v¼ “¨Ô°RAhÒH†éûµ¼==áqeÏffù¡Ó[_.6l5˜údC´A zþ‘Ú|ú_(€‹)‘5ÒH…AÚ ÁÍr J* ¨[ÔW§;ÐÑC,j æÑËÊò­%{¸QE ¹.,®>¥÷Õ7ËK‹EIÎÐÐÙrá€QÙ‚Â ¨€‡A7lت4ɰwâAŒòØGÚ F;;+R‘ˆK@×dzž(þ[î6•#ëÅ%X@.šTÇök vX ÏDbžbߤªº¨¹s`w6ñ{*ß@ÉD#tº·`2²5tKÀ ¶êÌÊÁµ5‘"¼ªØ  $6cCÅ ÔƒšŽa¿¿D/Ý¢Ð4ð‚ÛV] @äñ£ú x ¤®@ÐDàÒ»’ú­`‘×PZ‰Z¨{!pµb°@­iÁªË”Ði¡Õjœ¡2ƶ¶PPn@›a0nذUgôÔ‚áz‰yô†‚&ÀìÒ Øe|ë(Ž€¨OinϽkŠÂ‘êÐUúmæ¡Ù×/$a^Ù/j ]rÜ,±¥¦ÒªHÀqÐFømÕ’eiJ]üÄEo où9 6lµ™šç‰RI¸“sR󙎇Z2KlÑBÄPÂVN ô©V›rHQ;о:_(U~«W,+§¼œÕn'ÇÔ ‚p° Âgd=$CR Aê 5ã°.¤’ë½Ã† [U&…! ÀºÐ@ eV‘˜Q;*Xk„—ÄGŸ‡UÍIz£¯G÷C2Q8ODŽx¼ cݰ¨Å—€Ê¨Ñ>9[ªŠˆ¸ºUY‘ (oË©7µÈXjpÚ\¿^Þ¬úÚWÞ¹¬ìÎê°a«Ï¢{¡Í=HùfÁ̰n¼¡X$æˆ9%}—Oö±ºcæ°3±.*©!Ìãc”eœ¿ ±Ñ@+`‘Y2R32zæN9]‰àS( à¶à¤dFT¼‚x8Ât,¥ä´Òtßã®ìŠÿö†7¼7ß|ó]þý¥/}).¿ürÜzë­8çœsît›ù—Á?øAüʯüÊ.œqذû·€É'Ω-ßžÔË®%Ï}¡7 ©œÝK Ó–>E£}é”}ã8Æ)í ­@ZZ…6_w³à˜Ä-ÉB6qUІ«h]q@"™âÆU ^ÂÈž£´R‹Æ=ÎPH~J6uç¿'»å–[°yóflÞ¼þð‡ñ¶·½-ß¼y3æyƇ>ô!¼ç=ï¹Ëc¼÷½ïÅyç‡Í›7ßãùvÇ6oÞŒ“N: §žzê^=î°aûÜäÇIˆèµ’Ò*Hæå¬:h¦±¤x"ÕC<†_¹̦ÍJ+l¸…À¦MxÎE¶G•¨:(DkÏãNp¶l;©DQù—¢™‰¤Y&GE%ˆš+VJu¶cy㯴rÄ®‘D^õªWåÏø‡ˆK.¹¯ýëwë½zéK_Šç>÷¹8äCvk¿»³mÛ¶áYÏz>÷¹ÏáÄOÜkÇ6l_[…cE’^ÏÔ$­ÈÀØ)f!¯æ•ÃߺœÇÈK©‡k°k yºƒžÇ¨2fDxUZ± 2TTa QXA­ /O6%#O/›/\?Gü\‚‡­(p›³¨P4>OÁ1²%Û·ÀÞ²Ë/¿Ÿüä'qÐAáÙÏ~66lØøÆ7¾ /¼¿ök¿–Û~ö³ŸÅg>ó¬Y³7nÄÉ'ŸŒRv-+èî8÷ÜsññGuÔÝzÆý ™™Åd+÷¬z*w®ÜšK Ñ¾‘³­ YW¾ÎR¥DQ_¤°Èï°‚êŽÄð€&†g¡!F›zau#¦ã´¾ÐÊrnÅÄ&VXiòåfæ(VbX±£^SŸ+G1·˜sA ]¸d>/°*-¨æåíMxûÀ>€óÎ;_ÿú×ñú׿'tn¿ývÀ5×\ƒ×½îu¹íïþîïâÏx®ºê*üÓ?ý~ó7sI·îžì·û·ñÎw¾6lÀE]„cŽ9f/^ɰaûÖB˪9òR<¼ËÁ[—ÊBĤ•¬ ˜2wÌí3ú+$‡j¸a9“W`°ÊʬE!"ê˜ ?8Ùž±nÀ.=aÉ-q´JÁ®ÅÙ$ûõÔ‘nh[Wx€}ÚÍóxRi¨/ÞËÞ´SN9_|1Ì ·Ür ;ì0üýßÿ=žóœçì´í\€7¾ñxÖ³žµÛçyûÛߎ׼æ5˜¦ ï~÷»±qãÆ½±üaÃV©M3š˜JŽókù3Ró™{ï† [-f5žSx ,‹ƒÒy늆lÀ⯠“bŸÄùOz­lýbz4GÈ;Ͷb¤†²N©õ†R©¾iídXc³ÍTøh±sœ²(™TÔ‰¯ÝÔRØ`0»PÞœ³jËõÞ´ 6¤ÆûŽö7ó78üðÃqúé§ã¸ãŽÃ;ÞñŽ¶Ùºu+>÷¹ÏáôÓOÇ 7Ü€+®¸Ï}îs±²²‚W½êU8÷ÜsïÕõ¶¯¬é¶Å?Ñ]PÃc«‚·‚Ù …>ú&ú(`ZÊ’=±µ„ÄRüøäœÍ0¶A®Iè’ëÉü`I±‚b‰» ¥¨ÐéE-gÁbn©F ¢“/ÑaMºŸ!þ\\D±&ÕîÃA®™ÿCŠÖuïÜÝÙqLJw¿ûÝØ´i^þò—ãÅ/~1>õ©O-msÑEá±},®ºê*œvÚi8묳ð½ï}Ïþóñû¿ÿûûhåÆÝûϺ°£U4Í=ç"ä–Ô”Mâp+8JϽÍê+K M·|ÉaRkŒ¡q‚cÉs¹¶3<Š îê$­ 'B›>£Ô «À„ Í@ùn#ÃJaŒZ›.ºrŒ_3ogÝÂ…ôŒ›ÃÕõ¬Œ¤»¹Laé!‡‚óÏ?G}4®»îº¥m?üp|ìcÃã÷8\}õÕ¸þúëñ´§= o{ÛÛv« 1lØœ¹…Ȥ3Ü ÇÛœbä°yžqì±Çâ”SNÁ±Ç‹Ë/¿+++xúÓw>}Øa‡á#ùÎ:ë,˜Þ÷¾÷aíÚµû`ÕÆ݇¦öÊ²ØØžó~Ê‚Dnc߬=&/85 $ætÂz,`%Uû]¬ëžÀ±PÝ“ù2—¯Wé=Ƀ$ kôÉÞ«V&.Þ@²tŽVMÕå;¬¯Fúr †»a§žz*Ž<òÈ^úÓŸŽ[o½u鵟ÿùŸÇCúPÀñÇ_ÿõ¡¶Y IDAT_LÓ„O|âøøÇ?ŽM›6áyÏ{Î9ç|ðÁwzÎÃ?Ÿýìgwo¡Ã†ý›IÒm…@¥ Ø›ª'Ÿ³X4@*ùo®b¦Óû#d‡Ä”L…©¡u82퓇žœý‡G¼Ú³²Y‚ˆË£‹œ § \´±VÊÍû¿ ®Z Vñ/[¶_t|QR<šúuáÙçJœûîÿŠËþå­{ý 6lØžÛ=üE8䀇òy5”ʈ”BÍ6X⨔_ l¥úP‘—gʸ3JDplSüÒ[,m¥"ùJÒ-ûª NªR,Ê  $;ÞzÉ8ëÐsÌj²“ÕVÑ™ñclj^‘ dèë-ÆVŽ­–N ÓC¥y¾–‚6lØ*²&¢>ºMËÍæðT<¤„š3ÂtÊžŒ#Z6;å7n]Rl7>ë|Ô›érãGÕ‹j­–¡ðÐc*–¥Ï×BÑ Qrr}JmY¸¨&wŽ;Тh‰ ÏÆd9; ¨,'—œd1lذÕdMû'º }å@* å$b0ŽIpO`ŸÖ1§ªˆÃ€j-ͧ×Ý0ù'ÓXÞD)ẎER …¨˜: ŽèªîФ{ bàTõÍþ³&S΃C<·¾›Ó•X¬,Vx –Ãɯ6lØê²ÀKn[æß¬5Ö»#ç%Hð*Þ9TD‘Àê‚è*X&®0TÍy1.‹ºAA‹£È@Lòà‘ +¦ Q2£¸dÕ“3SKaÅ3òy,£vºpN4Ï’†…š@çÖqwc£¾ÐÆ [mV€.Läs”£Í5î„rõo#Màç,BZæô4ÇA‘]8TSÓfx©KX ù :¶¼Å…rƒÕŽ‹„ PY úbÅ„aá¿qÀCQ–ª"˜›4 ÿÓ¨9yËj å¶lè|šŽÓˆt÷Êû3lذïÓ4нÊùñhbÈdyp^*f¯Ô…$n:PD†»0zdá@…ŸÞ8ÑÚ4E™­İHðb>Ð*aŠ“êZ љӴbÆÆ%Ô½ÖÊb&¨%¤ˆ³Zâ¼ nàó˜ª5lتµÐ ’çæ¢iÈ¢AiÆx9œªVX §ÐT^Ž©± A B.©ÎAï®5á†Eï@"AHTt ØóÊâj‹µ=ÃÎŽÓâÅ&¨2j‰ÜÔðþ‚2Ãf\¶péÚÒѵø6B·~·aÆ­&›ÝPkTD-“R =Ä—HúỦ-åÔ,¥ÍMJ E-ìhòÖ%-Xô•ÇK­²€àçæXòڈìtF ¶DbD^XWòíBHBÀVå£T¬î1œÂˋݬj«åžÃ† [mfHîšùœù·œŽÇgÛ³èh1LÆf ¢RÚSÂô—’Qª5-Óg•…EôA»¨ÄÆø/oò'Àº¤È DìœÁ&Q6¯¼ÈÚ•k;É#qã¬óØ0IÄ×6e‡›0lذÕeÙÑäÈB¤e 94)ÿ!bI'ÉF¦fú0cB-öeXêìM5¶ƒcT™u4æE üc„ƒµP[EêœeR¯ZrÃud¡|Nï«oÇðœ8-Î[tDˆ§Ê‰s[·¨ÝŽ¡ÏÆ­V£oå…Ïz8E+¥µi)ÿîTñ]ÀÒ‘I߉MèF.[¸Wµõ­ ĉõæZE§Tì7 l‰;ߡՀ•!¤¹.ùœ$¶UUélyºLþ![_ÃÅ$q8‡ËÉ8žž›ÇW]‘ݺ† ¶š,ªŸ -re6k `¸,щÀ"ƒ¼ž4‡RdñkÈ(¡hŽžC]TÊ¢cY°í+…9@lª-X\˜À‰;/B™.ºNm¾BßUP»„¡¹¡T4­7™0Øé!b % «¹½'¢g‹Æýœ·¼[ngŒ§Q Mõâ–]y“† ¶ºŒ„ ïµrxCÃÌ*ŠUÀ'äÌûÃUa‘y·ÔZÑž˜R_\NäógX Ìrw,`QÉŒ4 šp“ÕÓü&´™ Öɘ‡£%~œ±RcøM± ,gƒÁE'×ÎÁ®´±‘6l5šYô…¶R •Àώ–Pª© ÖBS°—UMüæùYBIxv *U(°Úæ6€mÖÈs&oÊÙ7ÊJ­И-ƒ›6Bû³…pÎ8­TS ¹6OÍu•y ª¦êØr{OöWõWøÒ—¾ôý½kÆ Û%sDûe<øzŒOW˜U ˆâ"Ì»T’öá®Ô–òt`Aë¢ ”PÈi] M´‘IÕXPÉI¶dgŒIÀ Æv.:”\µ@I-ÆCƒIbuˆØºfI-áì†èB-láê’Ž.w¶Uv5 ÷’—¼o{ÛÛöôý6lØnY´fY-(>¡Ô¢ŽªÖÚIkSìܪ…rxåø?‰r¨D*æE–¬6þ›[3`dvpNàªIà`³½šôÕ*6EžÌTThn¨ïàSE°Ér0—ÕO¸ÖV½úf†«Ði­Ç<µnì ŒyvÍ5×à ƒÚ¥m‡ ö}Y¤"¯ ­wÝ,ÀHQ+%ØÀ:¥‘)žY!YrŠð2×Ê‘L"••!ràU„¸€­$Òzíøh.@‡®Îž©aÊ›! ´1ÎKb)ž9gK—sqá¦Î¹8ÕYàºQ»–‡{Ï{Þƒ'=éIظq#àºë®ÃÅ_ŒÛn» 'œpN9åpÀ»þ6ì.Í­bfºÉ¨"ÔÂIK/ÊXu3xl)NTAÀòRW"Dƒa,)'%È$Sõ,R€apDÌ>¥ÅÀ¬dŸè õ¦¶‚@Aõ’] €êêlh”‘â¡'¨dÌx;‡Á äâR%o’ºRrWw£„ú–·¼—_~9à#ùó˜Çàcû¾ùÍoâw~çwpíµ×~ïè°aÚ±´Y­¢R Î à(˜Õ¢É¤—î iæ1Û³Øtl8kÙ¢•ˆŠlvJ;®ÃåÛªW ±ŽEˆZªüŠl›¯TrÝtA¦Q‚D#€½ª Q™S3‚î\,=Ä X]:$êþ]vÕZHÚŠ»ko}ë[ñK¿ôKø“?ù“Ýßyذa÷lÊ•;PKt&œX„5ónMGäí@@* N#´-|Þ§‚ }g 1Â\sc ĦŠÔ¤ÌP¶xâð­r)npAWEà˜”˜ìz©áJŒá¤UÔÒÍ<ÍL]«‹zsÙ¢“£¶FÚœ”m»žƒëíè£ÆE]„÷¼ç=¸ýöÛw{ÿaÆݽEOhðX5—4\–Šâ•ì ¼ÐŠb$DeKW‰‘š8#`EÕ Ü'þ ¨JÈ1²®u´g^¸£XÎQM לúÖä*×2J)šsÖŒt6mFµæÛ„0SE””\ï+©š ±'L¸ßû½ßÃsžóœ{î¹8òÈ#ñÊW¾wÜqÇiذawm+íŽq‘gS~½Vü\Y¼L19…±äБi^:Ç=X#]æJ,|Q+ƒFz¤Á†(ÍF¬ €DLxx}®,`J”0‡—$8¾®8ŒÓÉ}ËòñÔ€Óðéš•ݵ 6àþàpýõ×ãÏÿüÏñÎw¾¯}ík÷àHÆ »s šÇl3Ì“ULŒà* Õ+si‘‹†|°€ÝO3ęӸ?cîß³é5«t¼ˆ[Æ&…êô“°¸ÈdÌUv/ÄmÖ¡²p G½- >¥çÏ!ÙǨ–‚t¦Ë6$K9*« i»–Íö-O·û>\­¥ì·ß~8ûì³qÚi§áºë®Ûíã 6ìÎM4x<½E`*Vê)'ؘ;殕~Uš¨áƱpÐŽiéXÅkéü¥D׎]ìŒ \v1€ /ï2fNó6 ˜4œÍ3éW’2Òùˆé¹ñrÝ`s,¶&¨Uª°$¬3Š«ì ÷s?÷sزe N8álÚ´ ï}ï{qÑEíþ† vׯ"e±šÑ #7‹°UýåK|7 Üp«Y@pvA(äI˜B+˜yì”"cúËÁHÖQ]Ô:XÙª…V`0Öœd xqÎ}Ú¹EVQAÇ çÉéŒ-´, ¤J¦Äãâj–rã„->Vi6"L–[üTgíÛ¸Ê)p*$ÔH¼eE†)0­{¢—4lذ{Õ¤ŸeºÌ]-ŒÊª°–ù8(~‹.¬•£ä‹7úÓ«& u /4xÆÓÄ—îÞ§Æ ÀlÀä¥ ²£´Û$™Ô[6ç•X/Eí¦· M_ΓõÜ'Û)’··Þ‘aÆí=cšªºwž™þÃ.'„¤lj϶×&‚ˆþä8!µÞàÜ 3ºáÏĪhÇj:‡*´ÖÂax´É·FÕák—]“Ô®£°¢Òá%“{. ^+g™¢…¡±rcEÕ Õ`á·±;Õò,rÞb¶´.tE† [Æ®CëêƒÀFeåæS³³×hµêŠœÊÇÉùòÚêQ·ÈmBµ[³ä=…/U†…%€Ù2Ðò¤it%Å/{ºœE$=žÜË묕¹¼¸Hs_n=3 ‰rj¨·ûU[°ø1ü·aÃV£9 æ°ˆÂ, éñõ ô£¹T^Q0E^λ(P8Àä _è;B™|0Ê´@ÛÒù†E ƒ`=¤nSPÐÔ6Ø9×Z š@!øUT€1q¡'W=´¢"6âÎ(•9¾RRÓ©æñ‡ ¶ÚÌ¡¡ït,„Ï¢o=òj•E…¢>t œŸÌø§hyÛM}JŽ*˜ÞÑCTãdç ãL˜Ëtæå(xYËr_é²K^‰¤Éc}š`,ÇÆŽÒÚèA›Ûi¼ë.Q£Á¤dÀyŠïýwgذaß—&„¨;ø,›Sù@«uÊU‰¨/ÚªÒé’–d¶cAóôˆ;”mcܘþŽ,‡HÞ£XK+Äà©­¤œšê f¥BYH”®h`àÔARM`lÎ) ¶²±RŠ®‚Ú“Ž=™k?lذ{Û‚¤;ea@=™Y÷ìx¬ÕôlÇž• Ørv–Gmì26¤iÅIÏ}µ+¯É)QE•>àAÄÓt¥G«¨†×Ua(°j •“§í¯>ÖJ÷‘á(«' A©R-æªÂ÷† ¶ÊL©(sê½ GÂq‰Ñ èrjHª™|>Er/­œ˜a++ ªS¨TÀ­ÀÉã ü -J¹™5'¬$ˆt!§.ØÜ «¬@h@Ei±Ô*L­.ô­‰«yêš É'@&ùx‰±’Ýú÷î+cb™c欼*OÏ [ŽÌâe‹¦·Q KêÁÄc´ Û¯-¶/Ρ §–äëjYaˆ!+…´Ë1¸TÎqpÊ*Ug÷BáÉEá‚+JÒCÂu%gêbàÐ×]@¸íÛ·ãégž…‹/¾_ùÊWñêÿö»8ó§ÏƶmÛöä½v?¶g<ã8êè£qÛ–;°yóæáÉÝ…Eç‚Ãj…W’D¬¢b†ú Ü³FÇdçÀ xpn£7½’O‹H[Áà%ÂaW1Ò9îÔ[*m2‡f@({·0S¥[8¨`šß`‰ I 1 whîe‚ž©4@ÿ0îûª›ÔÎ-õsê´ËcÜ…/Ð5kÖà³—ýc~ÛnÞ¼'<á‰øÔ§>ÓO?mß²aÀ뮻ÿé?ƒ|àýøßÿú¯0û.>øàáÉíhzpå~qK?k¹'pT*íoy»j*>Êò•^I®°ÉèÑ›#k£ñá@JÈ*%Q$xmâ¤IE¤‰i!À4whLª[Ù„©j*×àUK¢;ÀWV9ä×¶âƒ$O4þK+µôÜvµÆPJÁ<ÏøÚ׾ޝ~õ<ô¡Åÿþö·wë=6lûöí¸öÚkñ ¿ð|<ìáÇæï~·ÜrËðäv2Gá äš”uõ#· ÈjÙwgZ*öŸà>Åû  :IÃŒl‹3¸3ªýæÙ!\¦Ì2ïE¢o£ËuUÝ>åÕÔßÕîô7Ób“ÎÑH/OíÕçÞĉa±cD,–xSKdÞ³½éÍoÅŸýÙ;ñ˜Ç>yðÑØ²eË.í7lXoÛ¶mÃöíÛñµ¯} ¿ø‹/Ä»ÞõN|ýk×ÀJÁ†žMáb:%0ý‡—¦"/3þn¢OêGe̩pÓÓÓ³À*+q¼®%¢˜c! Æ” ¾V äXµ y¶UM—ï Ãà–Ôª@ß8µ*œ³³’Šæ&V©Q,L1̳ÉY]‚.VDæZQ½•Žê.|[nÜøvØa8û™ç࿾òUøgž…n¸qOß»a÷s¸É“û¾€W¾òUxÌcOÀ¿Ýtn»m€œ›FüñÂÝL$çJË<ôâJ -P¦>«…É %ó÷ᕱ zÖkÔe½óÕ0ŸP{ ¢ ,Tƒ¨æÔkšuÉvk`Ô*ô»ÌQ ±(¿Ö0^ork IDAT5ÃP‹þ1 ÜP°âáC˜òå Æ<¶Ã”cwgëׯLJ?øøÀ.Äʼ‚¾à¸ùæ›qàîö7l€7Ýå—_Ž×¼æ5xå+_‰«®ü"Ž88à€î¿áj”i@ãÆ/n)!žyw›™ºR!¢ËÜsÜAÐÖÀY jœáóÕc jôª—àÚºh@Ì‹!™â0~¬<è2a¤Y ~@ÚO¼F¾ WÚ¨AkH½Ô ƒ5vÛÒ¡÷y¾ÈÍ•]ü¢<ôÐCñ¾`×66ì¬7ý÷²Ë.Ãk_ûZ¼â¯ÀUW~GY°nݺû%ÈõYô(Ð¥±ˆÔÌc) Ƭt–Ú8Ñ#Ì;lØñ,1,;DåµF¼èd–`¨ü\$ÐÝã$l`íÃÍ 1a0«Ùd¥b€«*´ ÷‘׿ ¡‰~®p·ÅåѦjQ¡ò–ã0ô’†í«µbûöí¨µâ’K.ÁÃö°¥¿?aãñÕ¯| kÖì‡5kûf‘ûØX…Z¨j‡¡y+/.k«@:DñênãÀDúH" Â¤¶ðÖ¢g€ÊÁâ­I¥(+»À¢rY•àKÂN fp©¥» V1-”E ìjH³*ÞmÏ.•wU&Ž9©Î¥Y‹F-t£¢ro¼5ÆݽsÌ18묳ðñxÓ›Þ„ç=ïyøÐ/Æø@, ì·f Ž:ê(<ðиÿ\5Ç € 5úнÁ˜ÂJ@0¡º°‚Ô_«“C½nÝœõ"m(V/Ÿ|&1¢v1`xp{}°džÒµNywÎVŠX(ú.¬L:+V2±XÝ1™aFóôâü¥a?/ÈÝéKvß۱NjO|âذaÞÿþ÷ã/ÿò/ñò—¿xÄqxıÃn,Ö¬Y³W»oL=ïmºRJ2ü-¶T ðèyµh†´‘¦<( GCÜ2êËr†LUù7ºFUcµ˜™SLkÞËZð …Tפú™lbgÍE­r'=zÄ&wþwQ‘žÅÊ¢€Å •xH –®:b<Ö°a÷•üñøô§?ËþçgpÍ5×à%/y n½õV¼ýíoDZxVVf¬_¿6ˆuëÖÝo‰¿áö(MUò' úÐW˜Ud°y8ˆ¿æ€ÍðL{…<›g¥´‚ôëŒ*Ý¢S ¦çmŠFäÎUƒ{ÐMŠú½¢Mk‚’sÙ"!ù"ñY:‚]Ô,÷Aw*¥¡)„°–»äñ9šäŠ,Î¥ ¿ëÂǰa÷†}ò“ŸÄ§>ù l½ãv¬l»/yÉùØÿýñ§ú§xÄ#ŽÃ 7Þˆ­[·îëe®St'aZïã¦ôíÝßV ¥ªÃIo R×Ï! I¾jpèº*ó ­T†Á5"Gbg4‹Šƒ™¸se#’xZFüN€cÀÜ÷Ÿ9 ÜJò` í\X´ÜÔŸÖÊÊŽv^¿~AÛæîøÇÿïÓ¨uÆÆOÀᇆo¼çwnºé&|æ3ÿˆZ·ß~ûýžW{µ†ñÂÐÔPq›Zå…¸‰ü.¢³¦*Fp´î5‹×¼„^\ü­ U9†@êXLë‡yÏ󄕨lÅ)díªÃwñ*Ukgcî$L¼)Ç&ã&L7ì¾°išpåÿúÖî·Oxü 8äC°~ýz¬lÛŠ—½ìeø»¿û;<ñ‰O·¿ýíû%-d'3o%ƒ.ÿ®'{"†8'Š’F1¥ÚmI‡FOês÷JY¤Þ à4dZý­3ØyÔ ud‘¦´ÜxR kØ©ÇL bËe°æ¤VTX —.öŒe’›¯°­`¹¼LŸÔ­¹ŸÃ†ÝÛ¶ß~ûaýºuøÑýwØÿý3·¶~ý:|éê+±iÓõøÊ—¯Æñ|äý›àK‹"äÔM±"Ëœzþ_„TQÕ4id‚M5ç»ÌQ}f¾?VÀ…iØÜD»p Ñ=]ÁWSb0/Ã4|:_é'× †T°Uõ³’6R9Ì&õÝä¢N¹09Åœž]¼”Ôñýûc4ì¾²R <ðX¯µk×âGò`ú€CPJÁúõëï·•ÓeSe´ïbb릃!£låHqÕH ¨¦†ÑŒra_ðÝìŒR P˜Në²ö„–šÍ ê[ÄôïŠÇ„Tg+EIÉq!¬p‘óL3$u*°š²C1Br)¹ kþ!\“¸âBµYáͱûy®cØ}cwå‘™Ö®];äïw0óBG'hÊhznv!¹¸ 1jÔ=0L ¾òôÒ\Ôþê-®œ2”íFpÓh\€3÷W`XxI®d¸Ž•6"eÔ)«$>œwC›óª³ëÊ©¸Äƒ `¬­½+ÏxSû ‰¥Š#ŽzÈ^xK† ¶·,"9 S6]páˆ*†©Ú-QLd°²ê%¥Ô¶ Rª3_oë•-efXdί""ÑX€@Ü"Rù¹!Ñ+2jr´j†*®.uNgHo‹UÖNÓõ”Jš ;–x'ÆòQÌ`‰8Arذa«É4ÒO&_'ç"›H·@áÀw×V½ˆö×¶MÍê|sñ,B´-›Xf@ZÂ&ÐmS¥{¹ßs† [­Ö÷“ŸÐx¢†™‰dl4Y£… œx—´R÷ƒŠ™Ê2äLfÕ¬E|†][dÿ¨Ç z`â³ôšN1—A•ïòh/kóo¼­0.›^^4á{¨sÖO{ ž)'7ší‡ [u£ JòU£ÉÑp‹FÁ ¥åVLÎ[@kßÝPZäç–ºr5}´À&—d[RÐI)™E>ŠÅ)'±‚Í’ÀIX¡ÂÒô>5uËòä5‰¿qCfãá†i¹Ò™«K~â°aÃV¥v'_¥;cœRŸ43VÑÄ’Ø·`Ê\]ÀG4gÉ »R\€uš”}$Ù^AŒ\@ ç‰/.àR4ïùgÀÌöˆQRFÐá…¾_*Æ9[¥¢ÖI3ëbîš’å3]ÈR‰¸áé99oG®ÁÔr1ÂÔaÃV9‹…•i±–6g'R`![.:G*€gþ=˜ °°œ7˼}5`&'W9ýàÊš¡4q!uM§X3_˜<èw*}¨qv‡K¥ëŽZ©ÕRò$^aÞMùÂÜw¢hž¡Û4lذÕhI'óŒ½R¥;sò+ïÆ´ÜÿqKàó ÷ò,]v>þ¦ áªÎfŽŽŽÛµB!$ˆµ\„ÜJã›.tÔš2¹Ç_ÍKÂZ¯í¤ø´¶ô B¬=¶+,·â1‡Íˆv—j 6l_ØNÅÒ †‰P¥{–u èŸÈ¼Uî8±ÞºC‹Ò‚_S䈮0*P±„¥\`ÁÌ(LU S}^æd«9~¦b¯ÁªÚà-¸dT^ƒÐë¡‘!­%Äeñ€JæËÝN°ÍZí.¦áÞúÖ·âŠ+®ØÍwiذa{bAçp©b ùq²šÿžÍ°‚–V“DšQ¹×‘£F¥Òa*Pàá€UC«DäY Rq„pÇlÀ¢‰PÆØ·ä%gõS±u¤ÂBŽ$ûB‹#™²&’m–~ ?T³«‰­Y-ÍûÂwà‡§–e;o´„É# ¬’ŠIäãŽE8jF0 D;Qm“ °Å ÞGô¡á†nÀSžòœtÒIù·¯}íkøò—¿Œ7â’K.ÁwܳÏ>øÃ—Žqå•WâÒK/ņ ð3?ó3ø³?û3üê¯þêž/jذ ÇÛ3ÊÍ2&„é„o3Ò›ÛQ`µÛ–ÉýÎH6:ŠëñšRfÁ‘+Ái zwŒ¦9öÅjVY[ÈM(Ôœº•Q¨¸3¯«ËÒsËÙܘÿl¶&ÿÂuì‰]qÅxüã¿ýÛ¿Åç?ÿy<íiOë_ýêüû5×\ƒ¼à8ãŒ3ðùÏ^x!ûØÇ⪫®Êm.¸à<õ©OÅW\÷½ï}8î¸ãðÇüÇ{´žaÃ~˜,ù6ÆO4¯øcüKÿ‹-Z¡1¶#_N`"ïV5RÔRzM³–È·ÝéÐ1/˜2[ê)•‡†œœbolºSY=£î­&b}²ˆ…(²ö8Én‡%1Lv*(ygPQ=X‘‡÷ÄÎ?ÿ|¼ìe/ÃoýÖo^øÂâŒ3ÎÀsŸû\<úÑ2ÕW\qÖ­[xò“ŸŒ .¸\p®¿þz¼â¯ÀG?úQ<ùÉO¼á oÀýÑíÑz† ûa2³®¨™ÁÙ øEŒ©~öä\°ˆS¯TQU.ž9¹têZAR,pˆ7@ÓßvÜ¢V­Rå Z‚ŠÉÕ$è˜5IàÊM ¤(Ð,ª+¬ O­š”æ‚X$ÿ‰^ݤŸÍîï.Q—lÓ¦M¸ì²ËpÞyçåk§vN<ñD\zé¥ùÚÚµkÜàÌ3ÏÄ·¾õ-À¥—^Šã?>Á ˆ™™Ã† йúÔ‡,𺀦\‰7 ¯lÇä?ÕÚ@)g&¾æà+ ÞÖ¤‡ð<¹yŒ1;µOi9‹@`ö†¢D÷€E1Àk¡ºfi:p½Tp.dʼ™µjÄ–¢d‹ªÊìŽÉ¦–»£·ØI”äó«ï]{íµX»v-9ä¥×=öX|ç;ß¹Ëý6lØ*×]wŽ<òÈ=[À°a?ìVC> FÈ©"ÝÎþG‡!ÆQÌÚØ­ƒݦb1d¾µ[uóäìôak"…ØjO?£#U ¨VÃ˲-PÑT``œ, È+1ñ&/&BÎ Àä–M} ©°ÑÁlŸ©8ÛI×½›¼¸[vÄG`ëÖ­;Ù¦M›v*"Ü•yä‘éÍ 6lÙ…á¢U‚ÊßëÙe!A!§«Ã@1fpä_ÿú×ñÿðùÚ·¿ýí]^ϰa?ÜÆç»Ÿ‡\ýp©VDU>ÄÿV&%†”Èé³€©y¨ÊÓ«J*0‘îäÙ1©pư(”v k‰û¦J§«‚aœ?¨eF…uNÕ‘P‘Ysáá¹[™•Óâ’[2Ba¥ü š¤J&+w äN=õT¼ùÍoƺuëð‚¼àÿgï̓.­ªëáµÏ½V@SAH€b" H' ? 8&€R%1œêLF£ñû$&ŽX΄à„5?  ‚¨ b™`ƒ±ŒÚ–ˆ *C;DAèî÷9ûûc¯µÏ¹Íô‚¨×x–B¿ïžávÝÅÞ{í½6ÞñŽwàiO{¾ò•¯`—]vÁÙgŸ7½éMØi§Õ-°Ùu×]ñ×ý×8üðÃqÄG ÖŠóÏ?lW"}´Š©kÌw –"•ø5JT^¹UWÕþ[ïlûYÉ+Í—%-Gï\©±2vŒ¬²^zI_áý#qPWßZ'¿êÂ2zãzA±1rH:•ö¬[x^Ýr[­Ï½5‹¬¯yÍkpÖYgaë­·tÐAøò—¿Œ .¸›6mÂñÇ?øÁùú=öØ/zÑ‹ޱÿþû/ÔÝ^þò—ã ƒÂ%—\‚v؇r^þò—¯êzþ7Ã`)äüº‡åQtxx÷ZÚ—Ö¯a]Ã?+õt%iy›–RÁK;¹F=rMv`N¨%Î^`¿·ÛËTç®_8j:†4Å4§ òR"Js^„Ñ*ÉK,¢ÈmZÖì’¡«uÄ2„Mæç²xÉ~ºë7|Ÿ»úïïÑ¿œ»‹w¾óøèG?º¶ ü2âwø\l³åa5ó0ǠИû €ˆè¸”‘ZÉB‹äè¦iµ‹ÊÐæØµžPû_ä'·#Õï&f”VkëœA’ÆXK)Sí¿ÈAÙ6µ ç»0š:]¼g[¾Ú¢™8”Ù¥ðj^eŠúÓÀ4Mùs­§Ÿ~:=ôПÛõ ,JN/!3.%^‘¹qDûxC0p˜M€ñ{Ævt¯u Á'úÌK ":Ð¥ÄáQƒËfS‡#Ç®ôtÄ• ™U?9y6«#9g!RÇh‘$dWѧ¸Èš`kv›¯ûâøãÇ7¾ñ ìµ×^¸ôÒK±å–[â9ÏyÎÏíz– ƒ'ª®EC axÙÂLóXy°s^,Ëkw¶vxË“'ŠW¦¢Q§›ÇÄË›1çŽö†¤Š3w–ÍRtÞÉ¢‰WóÓøëø }o$š¬ÕSuý#åœ#ÒÆÚ©©\Ì t$i]Co⪾ŒUºž¦¢žÍ$8ƒ1ãºDoY¯/…?Vù\ŸMG·‹$;00°è;"Ü=ÔnxÅZ¡+€ X‰r¸Q¹r4 F<öÍo}Š„ÕNl°|€u‹ŸÅÁ®Ù×™ÿ24#A•´7 §ÖQ’é¬[÷圊(´öâðZ©®Îॢ–Ê#Hq¼fò:00°d¨.ç!Ú„KX´®¶ey`Ÿ,³6cjÉè¬-˜¢ ›·@ÇaLk[šê¡!<#u"£ãoŒ…V ì’ô _Óq¤£ ²³˜ÑØÂ ɳJ[[q°²…¤¶ûj'á2TÕ’vÿEèâ僡P(LØ,w4$fKGËÎÒ37 R݂͡ù‰»U•~æO¦,Ryd,¶‘'ð$²Ø« ´€kób"kR„*iUóg‘XtSÀ »&ÊPO’™_sOÄ`î–M}éB200°|Ðz?oÆäÑEQSh—ÃG×¢´>õ v™ºõ…égŒxÎl±ÞOÏÞ¬ÅåñŠetÄ ,¨WpŽ•µ( õ‘¬ ~ çN ÚšÖ‚qB{ø–Hµ’¯K»ÉnBÂ7wX”Žä™NVP¬²$œ2s‘Y6R¤0Y»V°x¸õàª7®Ù¢³fo:PÓn3#Ï”T(ßšg—Z#sT«]É¿Eeº=ãÁÍ Ì f^4e%½AÈÊ‘½Ë©ƒÉgÕãýæ\îºúüÝï~7¾ð…/äïgœqÖ­[·ú ¬òfëкf Z ˆž°d‘\4Ÿ!­DÏ…K‰wÏ5±³Y¦kyUë—•¨é(ifidJ΄Yå4ƒWÌÌÜ¡mÓi''ñ  Ýeçr±&bxôºÙÝyDŽ\Í÷Ňá<“¡#÷;Ä©§žŠË.»,ÿ“?ù¼ç=ï¹Ó÷ÕZñ¾ßûÞ÷Vw¢\­´äëá\çWYG›ÕÇdŽ)÷žºV,†æ‹GëXQ ZaýΑ½°¦à¨22ô.Û$ODZLUÖ sña×p7*O¢&\5è±ì,ß«6ÌÂЇµkCq ±¤Á¢„öä$·Zä›ùÉ —_~9îsŸûÜéëÜ'tŽ=öXüÚ¯ýÚOpÆ_ …r…jlÝ•[ì]Q²iÝû;¡zEFGËÿÂtMƒQnÜÿâ”BÞ!êüýv¿9`QóW“ö¡ðhÞM ½­MÐyD¶)Ð19†1(ݤ¿n³?—yA±Â^¼)_swðáûí·öÙgÀ7ÞˆsÎ9×\s öØc<âÀðœx≀SN9¿ú«¿Š¿øÅø•_ù•»uÎ_DÖ•ÑLƒ²1‚qw©@;5ÖèåV¤tµ ¬Ë«G)K ¬“€&`ÀÂ3Î8ùTÊ]¨a¸ëæÍ¦¨gÖFv[@rˆ5„T6ïõn¼Á~I†ª”¶š§S¼­´í[’‡É¾ËÝ–N=õT”R°Ï>ûàÚk¯Å~ûí‡=÷Ü{ØÃpá…âG?úžóœçäÀÙl†ù|~7Ï60ðËµŽ…I¥öéÙBÝ<»a€Ñ0ÄTq[lk®qñ")¥°VÛ 5¦²x2ž_KiæÖ¨¢EWÝThüÛØç’³£´³¤tÛNÜ\Eâ}ó¨j Ë IDATªÆ§(hxF‡ªä9ä ¥†>¿Û×pöÙgãþ÷¿?.¼ðÂ[=÷Ò—¾'œpžÿüçãAzÐO|®_Ô,Iñ;뚺l|ন‹ßee{4Ç5—!RûžS­WSê<@#Ì|^A™ªø­ÆVQØœVÍ1e|É<[dê扭0%Q¹>CñJø÷ÆxøÅY–©ÅÂ(!—ŽÜ*¤Þª¶÷“aÇwÄW\SN9ßÿþ÷âã ü²£xl¾+…ßñ2AcW‹ÍùñŽ6š¹¡ëóȘ֤èÈ@J#¤ÍêäªÁ}RO|lS³ŠR•¢5štÕ‡RsÇ/[õ4WלD‡¸ÙÒ½7ÒÌšÊkmšu-Ⱦ¹Îõ³µ½5yá'§¶À¡‡Š·¼å-8ù䓱Ã;àÈ#ÄUW]u}`à—!"x’“`,U->Þ7÷^˜eHFyfµ‚Jk®ª¼F«8;ßÅ{rF4ZÍ®Èci±]ó·xÁA2ÂdZj]ƒž±êkâ|™ÈÒ)Ý’(Y¬0LV1¡­“²Ê{E±f½tOàØcÅå—_޵k×âꫯÆsŸûÜ{丿ŒH¿/,cËùs0+ä¦>}§YÖwV,6óU¶}X‰)(µˆÉï­cƈˆª&ÀbHßͰÖ먬–¨I9+É7©&CGõ®QpVÿ“Äz¦†ZH jÜÙR¸ÙZT¢QíŒ^QÝ] îf†•••Û|®ÖÖ‚¸fÍuÔQøö·¿ (¥`‹-¶Àw¾óÕh`` ƒž® ¶P'“â™ ¥)2c´WË[*®ÖOJ±ûBÏ̵º4+u|Ž™¨[4¸¹›}}žÔ—ÒÒÅ>õŒU€ÒNu‹ 1EpÙ9Ü&è( •Çhí$`°Mäz*!«ßõ¨Gá]ïzî}ï{㨣ŽZxî­o}+N;í4pÀpwœyæ™8þøããTfxž€?ýÓ?ÅÓžö4üñÿ1~ë·~k•gø%…#Û3~«®‡‰=iÙ„¡š‚%Tèš!J_UdÈ:\Ê– |ÊW1@{ZJšÑ `ê³C[¥ÉeDMÍzDæ”àk#dlJ¨Á0QII±Aù¹,ŠÅÌf¨é9´Y´ihtCM‚ºžÕâ5¯y Î:ë,l½õÖ€£>ûî»/à¸ãŽÃ^{í…uëÖaš&|èCÂþûïŸïýçþgüÓ?ýnºé¦|ÿÀÀÀíØŠf‡•nïq#õ]´SßýXK¢e«Ÿ‰7"3LL7ãøÙe‘Q>£kpiÁ’=~×ÿÏsõ–æM•²r©CÙŒ™gL´3/n€Õ˜W \™8Ȭôa89¼³Û9»š="ExÅõ¾‹K¯ù‡ŸæßÕÀÀÀ]Ä~|î{ï£S‘%© 8MŠm? ³ÃÙ`Q䆉jh EÈñ—P+™RÓRƒwjá0}ý2+Ùµáî˜+B s6㚺ën¥g`Ë'ØëyEqÌÌsY¨t°?¥Ít¥xÑ磖 Eµvã4TuÌ´Ò%;àì™Sv©B<…‰´/×H¨ßF®ÒO ^w¨‚*<+×_X‹Ü²§²Õ׸úÑ¥Ž¤™Ô’¯lekÝÓ1Fò»¢aW&„jx9‡æYrX*X˶j­*):öë |] ³Úöˆ:.â÷VƒÃ¢P$i¢µhrŠÇêææaŽyN : SÆ8†/(1d»GUÙâ X7º¥.äp®lÙCÖð]G²Ä С7v```¹ †Ýb˜"k ÛÛ÷QoG8 lâWPÔñY¼OuÿFry׬|¼Zýo›‡K†Š9ÜÚ½M(>o¯‰MÏОCɰf3D³/M+MÝË:l·9ƒE͈±8 Õùz7RR).S:·%ÜÁ~XW==«b Ñ•ÅÚŠ–±µWV½´~ÂLQ™Ü”çµÌ&Kñ½ì‹cöçnp/±tJV’t,]zÑK5“{¦‚ÇloZFv[óç¨ë±WÎ3Ž$2ôEVXÌj‰ER¦ .„³3ƒ¿déÌ›A‡u¯Mº€£zí–ÀÏ ™ôxC…&$BdíÎiˆé†Ú2Ͱc²ôý@Zé=zQ|Z€‰ad,gŽUarïäè~k€F³:éʵcãýÄ~­þ ¨JÕe```¹P•Ñ9"0ò)› •4"½ ·p2üaÆ9Óh´Îß\-(1Fß¹ü¸ ¦c†c®³yN(œ-iDs@[ô@CΜª–G/·¬Ûe}O·Þ¢>˃8ÃØÖ1g@ÜŽn``ùP‹Xè¶„¢–e «¯pìhP¿[: •žæâ+ ÂÆ{TäMIiGë+H y#ÿÒ¸…#šõ¢Ó}?00°<Ⱥ›ñ ½¬$5ÅB°Y×Øï’¯)Žê´ùö˜3…ÔÌãZ‡‡ÁáU6 (=FjêM#(n!2D¸¨å«5‹„@óAoÍ!ÑÊÑZIt„~ä>nÖL{êÑõŽžÑB¢80D[ê!ds͸ ŠX:tnÝÑK+W¬mықo­-y.¤ ª8{^ál%1&ø‡Ùf8ýD`ÇH@#`†Â½¨Æ\ÙÎQr/Nòë+j+Ò"E‘¢D_µ'Ù-ŠÎu‚ÌÉãá¨óÍ270°lhõñ¶r =L^QlF×^À+KaóíÚ¡,z2³pr˜jü aEúXX­-ëDDn‘P† a®œ®z-!1CÚ]˜&˜L_cfTyg_rk'î1‹¶²–X¯-TfŒŽ"CcX>¨Cλ­fÏ9uköhÙ˜ëJ0­E2|SæGo¼ÓPf¾"I–ªË¥T ÇÜLÓ œûúj_ÞjnÖÒW¥Ý¨Ù‚ûGE›Åˆ”`Y|1§–-Ìí¥#ÔöúAqˆÜd…>ãÄ—«W”¢Î`E¢‹[jì5JmÂcO’™¶Z÷Sbõ“yañ„yLà“y]ùðbR¨íó"µÈ— ¢›¸¦í¸÷ùµT«)%—Êyµb˜tYjæ•U“” $Õ‘  ,\ŽÜ¨åL!MvåŒ®Š¾À5ƺ¦Í2¼õ°uóP”T}Vª…WíØÎR–Êi`“o‹ð"Í牨NH!VÎ&dz#:] Üè®%ÏFåi†³¥f@ÛÛIþ—ÀÑÆÃúýeƒeM*fÑ7õ¸Ç2wX!Ï ’VŒΦº‚.d«ØÄ`l±hURMîQ˜èˆa{PëŒþ’˜­Ö˜4N®èŠ-Ï^¬WSkk‰¡ˆ Ç``ÊÞ`Æp2GDh©œð²P¹§v2 ܳpÙdˆ€&Pšem¿e‰@ff^àj SÂÉBšµÒª¥‚5¸FA›‡W¤Ódš|`ÊGGßÂËb8ÔXdzƨtÙŒ³{¶Žek7áΉ »Yzl7Üß,âçöµPT!íÀÀÀrAí\úþhå%eaô‹Œ/|i¢˜ ZVÒ2­u,–§2àJWž)®ç¯A”r$š§Ñ¤ÔB½ÈÖ]lMk¤Ž(Ѽ'y¶=Ó¢:Ð>Ÿ§ Ô;cÞY õÎ9—K vXF´ÁJD‰Ê¤„v>HTùÂ{5Ue˶ð]Waj 0C­ÆÔ–M¾.¹­ö¶ÙhØI'ñŠÒ…—Ѧ”Nyq͵Y ë&¤ž@úgÉú]FŒ¢„Ƽj—Ë›fS­)°Ë-e®Yo´d¦eŠÓJ,hs2Á†ÜèÆË!ƒ8¶x„5;s«t$)FѪšúj™YΫD%Ó½ù3…gºR×DIwíÈYê§-D_âÇ’.­Th…*og¯¤Iµ˜à5¸¥C• `Ô‡b¨^» ‡‚¥«ÜÀ µH¸DØÍQ$p2Í-¾ÀÔ ”Q YµõðB"CüTr>¬t¡;‹[üÆi…”VMn\4î2‡è½WË×Vö¾è–r™4 ¹æa```©ZaK-‰Wƒ¬iZµ5ìšs `þæ,~¹ìŽšëˆ26ïU«Ž_9ÞÉ#y;&ÛD,óæÞ­)ÀxʤˆŠÐ¼š?êà\ “ª©ez„«T¹÷TÎñÉYÖzïÜtÓM8묳póÍ7ãÉO~2vÙe—{îà¿D0*˜£™ƒSH%*y«)ÒÊ\®„×w Õåc‚¡Šv*C[—à<·¶µœiKŸ7ÎÁ41! xm6š”[ýL'I·_ž±v’D<7¨.ð‚ Öo–Ç›G}Y0ôF¬?)~üãcÍš5Øc=°Ûn»a—]v70p7‘M·@‹¸¼d ½ZoÜÑœ½Å%Hç¢Æ]$©±Ë‘¯5FzíoýtzóàÝÖK‚<¼%™ÇôA„Ÿm†L³Â:ÙDIc&Ù˜¬ÁWçûÓω•H ¬éeHOözÕàÖ®]‹þð‡øÈG>²™b300p—a3FPf1ŸÜPr]•êè…~qáº&e5ˆoÖùIÆè§Ã0cªK‘¡àúQ#‰´p p¯L]ã¼sÓîe³ê˜8W‘­n˜!šìšP¼t¤ãM„ðp ê ÞÙà(ÅÂnIöè¬2¦™‰½/ûÝüð‡?Ä\€ï}ï{Øÿý±fÍÀ—¾ô%üýßÿ=6n܈W½êU€¿ü˿Ľï}ï»v‚€ª•s7.rÎ5QÌå´×عŒÙJ–·Š•õLÚbüF×^GpEˆâ•¾ ¬*ŠBf‡1#Y)àâ8j©¨¨˜Ì1¹ þ!2ÈéCU¤Ÿ5þ)qK…EÆkëÂ,É-^JçÌD5ù¿USîÆÎ¥ÖÛß1¾ð…/àa{Î:ë,|þóŸÇcûXüÍßüMœß ¥D”8ŸÏ1ŸÏWÿ900pk‡a01=Ô~d‘S ²G³)ÞW#Vs›¡.,© ÒS>„ŒÖ0ÖϺZ–À"Jœ•œ9óªƒ,0#hÊ5ùG«‘Y2±LÅÓ „ås‹¶Š–Y:x¦éžÂ#¬võùÏ>Ž;î8¼ô¥/<ûÙÏÆÁŒ#Ž8yÈCð‡ø‡ø÷ÿwœp «:ÞÀÀÀíÃápÚs«N~+'okʨDÈÍÑ–\m§jô×j°@uþxs=Ë6ãxØÈ'ÚÄe.Yœb6t±¨/&ΔqaŸ Õï,¬#E^v´ XÑKã¸z,RÖø3Þ¡–Y£ß1Ö¯_K/½ÇsL>vàbß}÷ŧ?ýé;?ÀÀÀÀ]„7C›kޏ¨ ²C¡Ñ‚'ͱ*׌lÓ»‚„AÍsñOmÔ“ƒŠöüXMmÆ›ÂÉ•`PÏrlÒ2æËU`ý¿ó#Hµ´µ™h{=;ßØÏ¢™SÍ7xH«’®ºê*l¹å–ØvÛmßm·ÝpÝu×­âwÍÌVý² éT§{8¿½­×U½`Új°ZDkЊ@‘_ñð‘,ÅÂ6©ð}•’ÒY°ªo@õ’)l‘j)ƒ8Mç/ Õ™ábu.˜éH·?Fײð¤}m¥ ]$.{aÏÈÝŠÕl¼J'‘í·ß6l¸™­_¿»îºë]ý»¸38hsFÕÄ|RëDf|Qk¯]]=( •—LnÝ-²¬ê ¥ïný*žK˜Øt_u­J/óÁ³Àj¤™6RÆ­ CJJupžlI1õ_cÏ[©Î¤ÈNwúYï¼óÎøÍßüM¼å-oÉÇÖ­[‡Ïþó8øàƒïÞ_àÀÀÀíƒå&ÍÊ3¨ DÌâLIùM5 ÄJìf `éÆI(؉%6)#ØÇ ªOp›£Z  *4ºÅÕ æÎô0ÓÇ”Y-H©ÚⰻʇÚÓ¬R¨3H‡ètT†’]’nšYµ¶tFõ7Õàrßõí£”‚w¼ãxÚÓž†¯|å+Øe—]pöÙgãMozvÚi§Ÿì/r``à6QSÖ¾²½C‚ë÷µpŒ3­Š ¯¢|¡¦—LImÏ,ò™,\sû¬"`b֙ÞŒÍd—äMë,No8cÔTTÚmf°4ÚðÁQ­‚î{ÎçNÒÕôrî¹èÊ‹·Z~º7αÇÿÆÿKA&“T&€ìL1g7°¢- ½á\Ï ºJ²e3°7áAEIã^Ap)Â#díXX…Çmø..½úÿÞC-÷Ö<ð¹¸ÏV;Áá˜e˜‚CNì[3ÇŠMt ³D쥔•cŸœ00°hB@6æ§Ñc×r¡ÁA ­( Péj¿7/þÛ[…®QGÑßœF½†•¢«Òë+æ®à-£8$‰E}­#%§æ ¨.§öu#l4qÀ6½©jtÅÃ’u:]¼&ƒ8kìVeÇ%@І“6´˳®nZ0…h 3fÌK•ž"ÞŠ)Û-8²©RO :[]­!މŹq8 ,B¹œh/ÞDƪÍU™ñgIÕø#³ªÕ üþG<ÔœÃ+'ù›·¾ 5·\Ð<ãÉH›5µ2À2ŸE“]ÕðëbÝEQ7˜uZŠÔ Š:žT‘üÜé·®¦¿ $3õQƒX:X¡pX^Uÿ¿÷­nŸU÷4ãhQ'²ÖÞ¬ÍfÖØ& -sà+]2ÒdYî-kÍ1+¬ò¸šH(h=,Õ ZaZúàÝ…x| 2%&XÖÚªj’tÎe¥Èž‡X.”ªrSa ½fÇ…¡Ð÷18Ae©ÚÑ—²½˜|ˆH ¥¶{ ¦Zq"ŠçTdhe¡ñ70÷pô“ñßœ +‹/e~­tUƒú¥³1Ñðm[ð ‘œia ¼Ek¼¡œkÕ1²800°LÈž ‘ÿ”›vÏ`³e0Údï&ço[XÊ£f³n ²41¡&ZZ+i_ƒ÷s­q^y±”Ö¨(¦uó^ícX¬§rÒÏÄ÷Có­®×fÑ̹»Ð¢žwëÍ2Q³ËsÝ#÷(L55§ðÈQLGôtt¨@L”苬ÏÛsÆmz)`FΩɅ|Lílæ¨Xêoõd¦8ç;áeÿ’ êÄžBM†‰9™ÐÿÙþ»¡º›œy+fTIÄü*º—f<Âx¯v&Å#GX>hy;0EùŠA•Œ’ÒNÉ8R…‚¬Ù§Yt{€K®¢‡-˜(c1òòwa~+T! • ŽÒ£ÐsnÞ5oè²ÓI$D&ÌTd´V(8¨ƒ™±´'ÕL¥† ÚÅoÕ ŠuÛ–ÎwŽdÌ>8Õâ–ì~¹D°Åâ–W!Ô¬±Ã/ZÃ)Å4W!í‹7Ô.fj–Ë´¸_†&¶0o=+ÞZB:±Bº@šeƒ‡·¾—ʨmÖ|V•=oRà ·š”g …Œ´_Fô60°œ°H;cRúÚªàTilÅ`HB` ¤1wîsQç…„Èt†ãlküX#u˜™ª”¼†øßœ¼BcIŠ „V¼¥ˆ S ð6«[2†cÞŽ7™%>ÊÂÆ¹1¦·™sKÅ%™ö¿«4½øB ©à€Gxã9òÙøB ýÖ7PO­q`ËšÙG2¤·MË}$ç,•©¯ÎÕ‰ÑÕ#œJOg-Mj IÓºŒ°&¨X๠5šïj’$0kW@œ$ó :˜(ÝÙ¡v ,øýïø;EB']:é$€.s´4€T¤WÛ„9¯VÎùVÐgÉÒÄkóLÝm {66"äRb¼ åÒzN=o³%z¡@ý2U¨©3&$Þ0¶ãÈ…5Å ,ÄÄNB'‹ÇÑ˪ÝW­ÿ5ý5`¨œ¼Š_çô£\ Éñ—U"]Çcœ”íf˜«ç¸8b 3Z$E7¦™μKvi£“„jF^hÇΆ¸ðñÉZ›ž£À}‚4YIÏ%ÓÔ…ŠÜÀÀÀÒ€¬ä‘ÁM,µ,ãÊ×B…Ihlå©2·µ(±-cê©;#:°ñ·ZF{E?;0·*XR¨)’Rè¨NaȰÒD»%7æè¦MFw8ÏôT¾sm€?Ce­ç(Ê› 1»‹—MËæå—cšú—EqµöÞHcEˆŠ¾¾vî!,¼)ÄtLü ›òÿDoï}ï{ñ…/|áç}?ShêHßwxÙ<"6T‹¥ñ¤°¬ÂË”ÇPUß½tÑœ|*éXYû…ò2ÅÔ~®ØxﱯVƒ‡è5ÌÛ¦û{·Ï;‰¾¹f‚Ì©‘XcتsÞ‘e©Ím³XsàÁó[ߌ:ñ¤2,7ɽç=ïÁe—]ö󾌟1è )qÑ<=àúÒ“Œt$er I¦^¯‘,oF¹$yU´`Ýï튢ÃC Ä\RSÙ!\ÝÈ{IPÙ¯fœ'#í©kXÞòæ¢ÞºÝÃzÓ ‚"[Pâ–›à~án˜´R>k“\¥.@c]ñBÖãÛʾÈè¸Ö ŽOxÑÞdtijo”C``$Zeeä<£‰¹iÛ´·|¹°Åɲö¢$ûÆÉb= ÚKt)Öy>yºoæÑE„&{Öæîüàññ|á±·½ímøìg?»ð؉'žˆk®¹&_»v-N:é$œ~úé¸á†òñM›6áu¯{6mÚ„|ä#8餓pÓM7n¾ùf|èC›ßüf\|ñÅ·º–o¼üàñ†7¼gŸ}6®»îºUßÇÀÀ/ ¬¢GªÈDdf°j˜1 «L¥›å~¶œ©· Ñ ÛêlŠÈ-™£" Eu:Fwâ‹ZP=ÒäRË]b1³Ã'pË´Þ®E¤&¿¶¤±yU´SDFvÅrÅB|¨üÀ…Ϲ}g¡f'e–ŒîùßÛÅ7¿ùM¼úÕ¯Î߯¼òJüÙŸý^ûÚ׿c_ûÚ×ðÚ×¾÷¿ÿýÏþóñÌg>_ûÚ×ðú׿{ï½7¾õ­o6n܈—½ìe8è ƒðº×½_|1¶Új+üà?À#ñ¼ñoÄ׿þuuÔQøÿø<ǵ×^‹=÷Üï{ßûpÝu×áïxÎ;ï¼;½þ_80©P«†EíLÉ.&”fYqw¯Q¦RÇ챺‡ÐYŒcTæ”8e…n­`%2mu”Ñ'ÎKżˆ9Ù1¸ûRyv¨h IDATn@’¦iÅø¡€Ž ìÉ++îJbzÈ!‡àU¯zn¼ñFl³Í68ÿüóqðÁ㢋.ÂÍ7ߌ{ßûÞ¸ð ñ{¿÷{ØrË-qþùçãœsÎÁºuë°í¶ÛbeeOxÂð²—½ §vZ÷ðÃÇñÇŸ¿Ÿxâ‰Øi§pî¹ç¢”‚o¼}èCóù³Ï>÷¿ÿýqá…Þ…«øÅCæf,†i¹LÔå‚S²ù¬ªà5ƒ¡f–æÖ-tŠ -^ª°#Do1ŽÅW(´n0&ÇÔ Â:šiK"i¥ €ŠÝ*¬DCH±v³U¹¯``t[µ Ï'£•f{RÐ:å¤Í”Îu䎱÷Þ{ã| þíßþ pþùçã…/|!vÛm7\tÑE€ /¼OyÊSçœsŽ8âl»í¶€ù|޽èE·"&½^øøÇ?Ž£>¥Ä•n³Í6xÀÏï¸ãޏâŠ+pÊ)§àûßÿþê.~`àUuzWO+ i$K! fPE}Ê%ï­Ê,oµ-²ÂÌêñ ÔZqÑEáIOzફ®ÂöÛo¿ðþÝvÛ ?øÁ0MÓížã;ßùΡmŽC=oyË[pòÉ'c‡vÀ‘G‰«®ºjU×?0ð ø]é¢CbƒêêHEÓ¼ñ‡g.Û‰’爼â5 ÏäËÉŠ5‡±Ç”‘$PPª9 €Qö›¹²zÔä¨)EÎ.„y´ƒ”Ö;Ç‚¡¹RÓÚþ±•Î]$Îæì‰™0Å 2'GgG¼rÈ!¸è¢‹pñÅãx¶Új+<õ©OÅÇ?þq\vÙeØi§°Ë.»¶ß~{\yå• ï_¿~=vÞygÌf³Û=Çm½os{챸üò˱víZ\}õÕxîsŸ»Ê;ø‚wké4dn¨În ¼({jeyÊ#;Ð9ð²›Î#+T½>"ÀŠssF‚2Vå¾÷¨Tù+§š§›o~ý`l@¿š#JUÕè­rkFbÞ^22;šá꟩ÙçL•ÛcmÄëŽñþÏÿÁ7¾ñ œvÚiøýßÿ}À¾ûî‹Z+N9å<ùÉOÎ×xà8ýôÓÕSO=‡rÈžãq{þîïþ›6mlذ?üáóùZ[´¹fÍuÔQøö·¿½ªëøE‚æØõeVÊYlÖÍ¡RçôBŸ6(+EÉ èþlßõŠÐ*Cd¨­MDe/oœå\313Ì‹# èŠ5ÙUãWN1¡d»HHÀfm´œ7•’êbM ©Ùtã,9®%ߦv“mW³f«Å[lƒ>ïÿûñŠW¼"?ì°ÃpÊ)§àÓŸþt>vä‘GâŒ3ÎÀš5kpØa‡á«_ý*®¿þz\pÁwxŽW¼âxìc‹5kÖà1y .¾øb\ýõùü[ßúVœvÚi8à€àî8óÌ3DŠÿ-® ëq”j³P*(h ©ZÝ­µþRœPs¯‰"”ßžÇs3´¾:ËTÙ«/PÙÕN]±Æáy3ã 0ƒ6ã¨ñCUÉΑÚ[¬ëP@ž.êz•³®Å¬ñ`Öÿ £#?';¯žäþâ/þpvØa‡|ì˜cŽÁvÛm‡G>ò‘í/§œ{î¹8ÿüó±nÝ:|ðÁxÒ“ž„-·Ü@å+^ñ l·Ýv Çße—]pÙe—ácû~ô£á˜cŽÁúõëq¿ûÝpÜqÇa¯½öºuë0M>ô¡aÿý÷_õõ üÂÀ‘žËb†Î W*§eà£úY”Ϫí_–‡œ‘$A^Iž²Íêúµoðån Ööø]ÿÒû‰|vkˆ1+@Ι:q#¸,øi‡©|™èúÛräHmWz…ƒÍ{¼™äe¤Š«Ûºá–«ñ¹kþážùK¸G°æÏÂ}î½#ÕâÈðlÙhlÅT‚4.v®ì‘c}>šÿ À½ ÞùNJœPÐSªÖ+°w¶ªwnR\Åb’ð §ùs64X1o€‘WÍæ.kÍ7äMV£LÌœº"Râô¶ôhŒ]¬NŸ9~0›Õ~þ0FKj„ »´’nQvoEq]‘§pý´"D²k5J\LWÍ$üµ‹ù^dRhe¬ ó %Ï uë£* "9î@%[ÆÉ ÔØj–•0 Jó8Û$‰—Kc­óz*úäà©´4;ôåAù¬‘LΧs‹kH@UuF]Þ^Î#‹)­£²e,ZÓ&‹ß%n‚aUDxÀ¢ra€«ÁØ0ŸH«3õüšÒѲÐî¡™ÒÔpÆ£„Á •;•×4 pKâKÛ%¾Îºˆ±OQ³zÐÛÀÀRÂúó”ãX`ÔF$&o£˜÷od¬ÆA{.Žîç㽞 j¼¶Â¹ÈÊ¥ÖfQÏZ .³Æ ¼E÷pn±ïRÎJ‘@áfóŒCæáÙá›Ñ^vµ ]~½cßÛ 5ã"]¡Û˜bXRDäUõ=U@2,@Zv˜õu}ߥ–"RÖh¨ôË‘yfˆ30ësR£Ž“\çèÉsJ™qI* æH6ÂÈ6‡ÃéQ®=@¼¥q-ª±ˆÔ¶Q¤7òÓ–ê–é¦á@ïéÔú– .¡A±–ç´VÖÁ8*P«¢¬fÖ‚0q¬Ë+˜Á0Éù›–m•ÁWq‡¶¥èÜÆqS¥»•583ω`D,^LiKÝ*kráÞ™˜#BSš\š5•D)mö¿xKU#[mªEúÄ¡eáCeX>¤zi {ê_ÍõMµöø ³#IƒBC·ÇTEwé­É7ÏJ^ó–øñ}.'’JuÃ|óIÖ¾A’I¥98Û”k¿›^%§ßî|,{cø&µ©ä‚š¾HÈÿBŒ@n``ùÞn¦ï5ÒÑ#›Ç ¨tQëX€ñ@,½še·ÅÄ (,㘦UÏ•2{49†#)f®—ÔŽQ‘îtøð6ÎUIx•'TO Ð"®’cšv¨0›²˜´hK•á] õäÕÁpKM,U ÚÊ×MÕ[”ŸµAú¬Ç#"¹ª® Ú+µm•¼ :QS¯S §´YâÆ\'Q´×?³®Dã…j‡Xº‘ÉZ“sîcü+âêÒÁq|Ö{´+bXFÄÀ|+Q•¬‰ñÁ$6–£º}%êƒõúA)^2©F_ä ‰V¿3Qj?³F–±wy‚0׬fºV:ÕŒÊè-®½m¾™Á’-!ÇM©$0ÌÝ0«…;88ÏÔÚىܸ¿±d{ ¢X6è;m¬›G«t{Oè2¦+Y¶38·Ö+ˆ?´¯FúªßU³·¦W*¬Zèèà.sÃK ÷2}Œ›hƒóYÍ4ÕOö:¢w™¬ ¶Å[apÆ™²`f4•qx7p± òýË…–¿© ‰e ÔÕìûÝ©ñ.4ÁÀ;'¢î=ù:¾6SQЫһ£qŸË?.ú{g€596ëfRB¨„.FQ[Äåm®Ì´A+bCLÆZÚÞíñ üÃ?Œõ‚? DIª¨ŽgÇXÔÒã;;Uéc×–Ù ¼Íª˜â¦ŸŸbfžÛø¡¤ºU€f—‘Æê@®¦– J'ÍŠÈ“I©}F,¦R\¥‹Œå}œ¥¯4©ø,T–ØŒÊçòY¼‘ÇóÏ»’œ®]»çwÞ]xÇÀÀÀÝG4÷¹£-kßoÑG³5÷u‘H¼Ë#jkû\Ü*&„o¯FB›¬Ù.G$ÉCEݼŸ-¡”V¢I/÷5à6Nö¶4b$}™¡H&5 ùAi¡4h: Ì^rÐ^ŠU Ü_|ñÅøÌg>ƒÿú¯ÿÂ+_ùJì·ß~xÊSžXYYÁy燯ýëØsÏ=ñÄ'>¥”;9âÀÀÀÁ2Ôá ¦"9h7)Ɇ$¥>9 í8Ö¢¥Æ‡Ù8 }LxIk&rSFÉß#sÌûèÉ€¶³5-‹ •Ìf€Ï»>Fi¤§vøšÊJ¤ªÎ¨°°'ÎÛŠÀˆG¹´†ïf~m…u9¿s‚3®033Ìçó$°n¸O|âafØk¯½ðæ7¿~ðƒqþùçc>Ÿß¿×°šîªÅ@}©…köj,Žç¦ùp,2¦3Æ_â4WúhpYžwî¾Cöyroú@¿ùÏ<²Q>:WüfÈ^áÆž) pƒ– yi\çdr) ]™‚*˜4µ4¯õœ¿ÕÔ‡šTPRmïûï¿?ýèGãŠ+®À 'œ¿îu¯ÃvÛm‡sÏ=¥¬_¿{íµÞûÞ÷â˜c޹+Ÿ=<\x‘4Ät³Úé²@fÁm‹ÔbÀ€ßwÕâ[EŸA³B«Ù—kÕ˜âv>’j6F¼&kp½FN=-qy” ÒÉò:•Bšfü®Ä“3¬$ÄÉ2K°N?p¿è|zM†zwçœsŽ>úèŒè¶ß~{<ëYÏÂ…^x·900€38án§Q°†¶%.Cµ`æ‘™Oè˜Ç Q™GDX¼ÀªE-Ô¤6ŽJò ±A#b:¡N“ޱ ÈÍ{e4t 7Â:ztÙ'q‹õ;sËþ:}j¡…Ï8Åý»Ïqµ*êm᪫®ÂöÛo¿ðØn»í†ë®»îns`` ²:-:P ’ÚèÜ?h£en›‡-ñ@G— göë2Ó¬élÔ½Fïè€Ò‡ƒ€¦¤GÒÅV$ºš I0-Ñ^Zór4[F—¦š_E•¡]ºˆm³Çï&¶ß~{\yå• ­_¿»îºëÝ>æÀÀÀm@ì¢n ³.4Q„³F\¡È«&e%ÉÑ—é­v®¶´¸Ë6Í›E~)a#T]’Ј-M*ÛA+,Vw¼Ø ³ëpqª™G/ŠP Øÿⱆ},€\Fâü3:u6ZíuØÜq‡Øj«­ðï|gá±<§œr 6mڸ馛ðÁ~‡rȪŽ900pÛÈÚ{ü@¡Imõx–šÄ ÕZ½n]v–vi1ÍPi‡¾˜ÁÑòÃÙfÖg¬òLnðZPÚ¬RI~>¶ÂÉ‚P) <»—A ¤ aÅÉÝ'`³”Òû$›¤ÊÊ­ØTcÙÌPö6Xnüãq饗âyÏ{þöoÿðªW½ ëׯÇïüÎïàøãÇ~ûí‡8‡~ø*:00p[è[2Ô6ö®oþE;¬ƒç&?EcVrì„hE¶Èè ¨ìƨQÆ*Xlõʨ&çk_Æ‹‹Ú™Á0KVôÚ|Ú’í(™ÿÖˆp0¥ŠÓxcn@@§ê?”}«nÊØêjpkÖ¬Á%—\‚‹.º¿ñ¿xàˆË.» ŸøÄ'pÍ5×àï|'ûØÇ®êxw€CÔཪNj{tU[\ZÉË•‹vA– ßB[í'ÑåÔÇŸZmŸ\e•s¬ñóÜ2O¦Ôà¡\ÒV)Å×d+$XŒ1´ôši§/^š*»•ç¿=Q è0-!uduxøÃއ?üá m³Í68âˆ#V}Œ;Ge[†qb V;Ÿ6•½ÔuÑ8 o¶ÉªDlÑ›\zÚ”D@X»>¸6R ˆÉd—DÖmÚ…Qp3}¼jåÝ› \ Þ¥˜ ݺ[ìoH²2\\¬y×’?Ó¡s```© ¡z—½il˜r#s.£aPd¤¸h™hÁLÚ+“”àÐõ^0tXE–‘[»ÆyEˆÑ{Vá6Åj@/˜uê…1$4Ѱòh‚ŸÁaVèëFåƒéf]²AášÜ}µD0êäX¡²d%iÞ}u``ৃ¨KïÙQ¡X§÷ƒ y>º©¤Ù,ÉDƒ9rÿ‹3N·ÞÒxdë‰b¾˜ ›Ï¼Ïã‚zßs •ùr#=¬µe½Rd(MD¤äºû°>i‘'Ò_½x'ÃÏ¥B¹õ“¥2¨µˆì"[TZ³w‚â²=È­ƒBÙ\ò†q¬ÓT¡+yÐXÞÅ:¹kîAå’”rÝ<(“Q— çRMÓ¨šm ieý..wBR&£?Ô‚©{·yôÊT…«KCDnRP#ôËÉ(3ÓÞRõͪ["¼âTʪ61 o9æ„s‰G˜tD©mÖõÝZÚuþÅ.Ñ) °PA ÑÏV­Í”¶A|äEjÚWäâ9co\Ì®*khÒ<œ=mpÜÀÀÒ!§Ðgn˜™©Û#[AôÞt ·P²ô’NK<€jyŽ\} –ó2ës­ T­Í"‚°? ›áBñ M&tªI(®q…Ð`­°ôÖFXnÝcË}H¶ªWªð8*pˇÖ(n³$ -ŸÉ"SÏ—;5јßFA^<Ï´LR2yH&SvW8wգܯÌ’xH—^K(˜!—FX”7Q¸Ò`FgÏâR Ý®{iäÆ÷6Ä1ñƒ‹Ÿ–²w¨]¤}w¡ Nå´xã—âi“w‹Â2’#‘¸UÔ"?¹ ‰˜…‰©Ò¦Û“+TR£!Z¥ƒ®úI@™VûpZ¤Å{€äaæÎ"(],*HiTVÛž‡hç+"JŽ™´'vDpˇ¬§e9˸3Ag)­P$ÈHÑ%M°¼vç‹‹k¼6ñ@§ JûäI©?æÝ >ÖˆÌÌ<ã<©“ˆŠµ“(uµôošAéf_½ 1Xá&¸±ÚQùÌ:öF˜Þy»ÅåA­5SÉNª„ªýO´$¦[šl˜Þ«Å3–µ<é‘yV™ã¢ï¿eø¥²Wª¸1';³ ‰,69ïò[­ìŒr°#<›Üä¾9Á9(¯1ŒÅž¶Šf·Ù\‹k½w```© šG’ä2`ÊbzŒÎÇ&û.dÝ?æàKÌ™f3pûÞ¥ŒC›A9 i‰^! Âs¦ÀYÿêu å \»t¯Ìzš&•Q³Z-²RmÑä­& F_ü¹ B– štêo$çä ËI½Š!M¶˜ÌÚ¸9¿ê5¹³µ•ˆÜ€&*IŠàjÖµÙkž„CQ ªËØuaŒ¡L–H¥åÅê“3ÇäZm½ÕŒ)gœyqÑ÷Cöìe¾p6ôµ|v```™Ù‹iQ*Ñ'£ &+pŸCÛ[2Êaq.¾âMI­ÖfPÍJäóÊ~Ù6ÞmœÆâáCdíe> 4A&t¼‰Ij2* ¹]K彉wî¨ÕÑO‘.¶‡04­¥S]©°hY4ÚqÏü} ܃ˆï1ÛÃlB, šÁ,ZÇÒtÒ+úåñ0'*ý&¹Ô(o9%ÇB9IÅ”Oïéãg™*ZFpAnY“kRFåß4&n°ñ §*"¡AïÏZ\JZØzÝ”†ªXhòYqdOvæCdX>„õƒšU†#ˆó«\XG×Ð= ž¸˜Gµž¯Ù+G5T†–šyGsJôlKiãZ†Ð8‹ùbQM Õ2ƒ4Vÿ¥pûÚáh©) Cºos#‰cdšÀüpL#_ÁüưպË7 ÑïªTUÏe“( _­ùSÖìÄ\-*g f@HR 4ÓðœK>“ó~fh9µ‘Œb5Oè€,†Õ†jx7b‘:G›Jð.Ë28-̓X6‘a``a]«‡k”‚BÌzËäT9ýžõ÷x„KGélÚÈG&ñ"ÈÍÍ0cFX3VR¡Ž #˹ќH Û’N0«€& "^cmŒ¼£Y1Eg…7ï\N£¡~Lç9CZi%Ȉڬ)¸uÜÀÀòÁÄÄ÷SnÝi•æ5kè­_Ží!Îh¡|SFV®¸G:]ˆ©I3(-šË ‘Á˜0‡Íîz;;£ zÍh.žÉwÖ†îÕ¿~! U•b*TmŸO:€æu¨06è1À_ß200°$ˆ]¥¬½«Ì•$Óš}ƒ+dF©†Þè+¥´}Z8£T±ÏÀ&>+5² ½È": ÅOwÓÆ*±V³HŠ )˜¬æ^õ¥(qt§ àF·6ŠÑú]´ˆF¡)Õ‘Çã2~«%æÖã ,OA¢A“裂%V@W ‹dæjð-,mµ³d¦´ŽØU#Ô+D”ÞñƒdUÙ‚˜'æ˜}Öɺ%9ArË®/„”cYÝvœœ[‘¦)0­Q׃åpláºÂBoâ–ªÁ£•š¢ f-55`B›VJ¢bäα+J ­ö’œSè fbË×ùB‰,Ú?h¿f±Ué.‘GòB{;#¦Óù*ÕËZ&NuµóqŠ™Ê×wʬΣ›aÁ0 6 ƒÞ–ROÍ(–Q†2w$íÓ²f¦xÈœ\ám‘ Zz›Û³(L´m\}]_û2ÕŒk˜ƒ*EîRlÚ™LØYèæaE¨µð¥ÚyªÁ«ì¬ë ”±ÙæaßdmBöiõ“Ÿü$þçþO}êSÞ—20ðS…¶ë•â±öS"A®:bIµT‰Ÿ¦ŒÖãY·CöW¼Rl îPW‡»£°%Dçó®æfVr²`¤hÝAj†•z‘Ü<âq:ð*@ôîF˜O0DÇ Ç´<ŽZ¹…+Ž+ƒÖ)ò_^BÙ¦®übà‚ .À‡?üáU¿þä“OÆg?ûÙŸâ ütíµ=fÙRæÉ ‘[I¬WJÔÒ¤sÀY¯³’‹Y(la †ê%6Ø“J+ '+‚âôü5çFê¼|ç;Ò# M…ª£ÜÉ`°ªLnPäs”ÒèOÝl–óà³p¦Ó–.Þy×#ø¿gžy&¾ô¥/ý¼/c`àn 3»õPT‹÷bñû]9ãTsÆ=²¾ö»ÈZ¸Â@µŒõ·NÜ Å¶?–iÀbcÖlT4 ¤¨{I,ÝC̵‰>TÓ™Ó,˜±bzÞ¢>sT«-dÚª–â«sñŠ«\ɦÿ•’æ IDAT¿øoĪ>îw¿ûݸá†ðÉO~oyË[pÞyçm&AÖ®]‹“N: §Ÿ~:n¸á†||Ó¦M8ùä“qË-·àŒ3ÎÀI'„Ë.»lá½o~ó›ñ­o}+¿öÚkñÚ×¾öv¯é–[nÁG?úQ¼éMo»ßýn\{íµùÜ?þã?âÛßþ6>ö±á•¯|%¾ò•¯äs?þñqÖYgá­o}+Ö®]»ªûøY™ê©àÔ­À&`–¡`- ³ÈÜZd&BO³åLƒô¹pTu;†FÇÊ÷2šŒšœú7eÂJNïëbÀƒÄo%åWu «UMìL9„¡cDj°SV)4Ï·Ò‘—F9n¢»}‡Îqç8õÔS±÷Þ{ão|#¾úկ⨣ŽÂ3ŸùÌ…×<ÿùÏÇ3ŸùL|ík_Ãë_ÿzì½÷ÞIX7nÄ ^ðì³Ï>8çœsð¹Ï}|ä#ñ®w½+ßÿ¦7½ ßüæ7ó÷k®¹¯yÍkn÷šžþô§ãmo{¾öµ¯á¤“Nƒô \~ùå€RJþ9ŸÏó³¸öÚk±fÍœqÆøö·¿Ã?üÏ10ðóÁbKYß³ÚÊj –dÆÁ%S ŠäF”ÊeøH¤”»`†pW -4ËŒPgŸßì0/á¼VPÔÕ²P‹›’œè¼+gÊîæÜ^*à%]6#…¶ëŠzcí‹]Ï]«ŠÉÓ3šëç;ÃQG…W¾ò•€—¼ä%xÈC‚£>}ìcqþùçãœsÎÁºuë°í¶ÛbeeOxÂð²—½ §vZãío;÷¸ÇÞ÷¾÷á…/|!žñŒgà>÷¹Ïª¯C8û쳓È`Íš5xÏ{Þƒ7¼á xÆ3ž·¿ýíxò“ŸŒcŽ9&_s '`Ÿ}öÁ?øAÀ±Ç‹‡>ô¡8î¸ãpßûÞ÷._ÃÀÀOšIp~Ï#šŠ©[ÂàÕò{­:\³ag†º„Ifnà°=‰O1WÆ—8žÏÂÈε¸žà¯(“¯`Ó´ëFL¾Òùž#™s^ãE=b_ .´æ%’ém¶ú²Ç¯ù<¥Bg;‡&X¯t9´.½Õ`—]vÉŸ÷Øc|ðÁøÌg>8çœspÄG`Ûm·ûšÏñ¢½^xáí㨣ŽB­_üâW} =DnW^y%.¹äì¾ûîøÎw¾s‡ïùä'?‰ûÞ÷¾øÀ>€|à¸ä’K°Å[àŠ+®¸[×00ðÓ@¤¢Yú—…ZGFÑBV³ØDæCöÉyÇw@Z¥EiÌRThˆ€Hݦ|SÅŠWܲr nÚðßšE5Lu#"ȜǸCÑ3bDðâØà!» )(óéºUËWÄ&7Wû^÷_€!-ò¹»ÁmŽwÞßÿþ÷W]uó˜Ç,<¿Ûn»á?ø¦iºÍ÷Ïf3ì¸ãŽyŒ»Š /¼ÇwvÞygì¹çžøîw¿‹wÞùßó£ý7Üp®¼òÊ|ìÅ/~1vÚi§»u ? L¶—Y´{x|·+ƒ¡Èœ±ÈT*ZµPå¯|] Œr<ÒZ*ƒö¸Àt&Çä6®lÂÆ• X©á>anÞLIV|Ž 3›3Bl,=Ð/lÕu›#‰©e⟛씵;’¾º´óŸ› ÿü$]"×]wýèG¶ß~ûÒ€õë×cçwÆl6»w‡r¼~ýzüú¯ÿz\©nºé¦UŸÿ™Ï|&Þö¶·áiO{àå/ùFb»îº+öÞ{o¼øÅ/^õy~æ°XË´ »wõ0’C¤¦ÀÂ2ÄsÆHŽî».¦kTUüC•¯ê›êFl\Ù€Ó&Lur„ëB#¬b² +¶ }#6M›0ù ª­ãUJ7C8h•8…”ÈËiýnî‰{gö*¬À0ks&U段ùž{œ~÷»ßÅ¿þë¿â‰O|"àÀÄé§ŸŽk®¹&_ê©§âCY8Æ9眓?øÃÆ6Ûlƒ½öÚ @D„\pA>ã7.¼×̰²²XYYÁ÷¿ÿ}lµÕVùüu×]·ðú­¶ÚêV)ëSŸúTœrÊ)øïÿþï»pç?c(Rcg„yÏ ‰¼«¯÷‚¢µÎ ½ÎÍ¿1¾(d­M|`Spó¦[ðã 7á–M?ÆJÝ!¼¼yŒFóåv(g8Õ sö±Iõ@ÚoCVÍ~ÞGö»8šK§™£Q9ŸVÍšdu"*€¨_­Y³¿û»¿‹~ô£xá _ˆßþíßyä‘8ãŒ3°fÍvØaøêW¿Šë¯¿~°à•¯|%>õ©OáxÎ>ûl¼ÿýïÇ[lxÁ ^€g?ûٸ馛`føÔ§>µðÞG=êQxÞóž‡W½êUø«¿ú+zè¡xö³ŸÃ; ßúÖ·ðŸÿùŸ8ðÀóõOzÒ“ðêW¿7ß|3ó˜ÇàÐCÅK^ò\tÑEØwß}ñô§?6lÀºuëpÞyç­þƒø)#œ‚¸:0…$Qµ2“ˆÍ`Ý=@5ê2•­¦=ɪ¼SlL®S68aô‚¯lÄ´²æ+p«ádT¬‘ï#w9Úá`ÜÂ+zª3›af÷Â[ ¨ËØ{‚*ÙûbÚÑFJC¨¨pT5Bªû˜0£xÄ#ÿRÜqþùçcݺuØ}÷Ýñ¤'= [n¹%ছnÂÖ[oµk×â‹_ü"Ü|0vß}÷…c|îsŸÃg>óì¸ãŽ8ì°Ãðö·¿=ÓIwÇ¿üË¿àÊ+¯Ä³žõ,Ìçsœy晸æšk°÷Þ{c÷ÝwÇe—]†Ã?ûî»ï]ÿ‹"¶Øb ¼â¯ÀvÛmw·10ðËïn’P?WÎ8®´¸¦ Ù#ZMQ[¥¹nõMذ²·lÚ”ÖI0Ï=Ê=¹æ.L0nâ‹T×aüú1 Ýšë®<Þ"'ærÞ@©Î­õ1gš¡ `Ž9¬Ì0·9¶¨sLV ûQ2ïmª‰(fð*I8ž/6‘ë n®ßp5.½ºRýÿí½[Ì®gU6zûyÛ¢¡þTܶ =€èj µj E$E\¢AÁ\¨ì<û…Äü¬“•¿ÄÍZJi¬ TŠ–‰¨U~T"AÛ9¿ï¹Ç:×5Æxf…ÎR/úÜ3sÎï{ßgso¯±co{ÛÛW¾ýoþ<à>ß83 ɘŠÈñ6[•½Éš 蜌øÁ„ãxN…žíG˜ÎÜ’æ4D†1ÒpL;h¹eyAWìCÀêÁg‡ƒ,›„"“ÍÀÃKÙ”À"÷ÒdbEˆ­Çp;°È g&æTiƒ Æÿ §t‘¿2¸àþï;áîmo{û 6Wiƒt\,j0D1ûQ‡+cxs/c:r˜ãh®8}|gŽOc+V›€+]ž4>z€?B dšrêUÒðÀ¢Tá /S‚6Sn%îY‰>½\˜„.4ekJÚ«;XlÁ‚H„—Þ# ‡qZ—e©å¤UnNI±¿{ÛÛÞNFsúÃc4›„Vº| Ä…Ô䧨ºúÄ1íHQÀW¤ 0=8ò.‰— ß'¼ v©+ŒW5Ê¡¤œôØ=æ‚K…¡ ŸÃI×öRØE±‰uã<[p°ó‚âFG?z>à>‘«å8´¢®»‘ao{;q-·ðŸ0(6µùÖ*hJà7=üÙΟÁ™õÌ ¯Š›Ã>Úý'|Ãæ¨D/{Sl—'Øb¡Œ½–lcÙhùà&P)Žf0¤¡^BN`ÓWÆy8”¥–„¡ÝhÃ2?£”‘{ÛÛÞNL †DÜS¤ËPLièÝʸ9èÆ1á8ö#œYOãô™;#ƒ‘Ïr1ôþŒ"5„_îXe’äÇRd…ÅTÎ(eÌ l:˜2ú(s¯{9è*ªÁ7¯@•3ÉÀôE‘kHZpƒ»;^ÃÒ1–‹-añ €MXZG¦Kæ.'–½ímo'¯žY“À,r´ÍKÓ4MŽÀvæè¬ë=5)•"×ï€ ƒÏ,–@XLaE¡`t+EŒ¦›ÈÚbƃŸ•®Ä(šz¦DQô‚UÌÙ¤´ìQöËù³¥îubbÅ\¦-8o9†%,+^oC j2nœ››ÈÞö¶·/_‹Ê#Ï)ç~ +Ò"œüôñiÜqô¯˜8éÓ"VdÚp>¨00µpƨ4¹ÃnU‡Ðæ0ufJåVÌÌ;±d,Y™lǦC(Ðs/«(o›>±âÃ8ÏXë:Ü%æÞö¶·“Óäí@$™˜££3¸ãèNœ^yüëkd"Ȱ IÓ"#‚‰þ³é[Zù¬”wVüiÚ :Ò$ÊÄ G‰Ð*Õ®!½Ò_2‡Þ:`âýdZЋÅÊÊBš¿òÙNvb™ç†2yðÞö¶·“ØBµ:pzáôÑ8:º‘ÊQÖÑ8'6‹Øf,º'Œ´iÞT\žã*2ݯQ0Âl:ÿ 3Td5AÌ f#EË)™H«¼âQ"K©sMƒ…›r¦—/Ý Od ¼éH*àX±ú _W,6qÀŰ·½ÄЉ3~„;ŽÂ§mâ¨ÔW^@“I.aÀÙ" @º”8õî’|«ªK È¤žOÑì’ð†:”òr|w˜VªBƒcJg˜—NÆ“¶j_™ýC5 z*!\²‹†MZ¨+—¾F›«cÚ‚cüûaö¶·½}åÚ±ãŽ3wàÎygÖ(OPIs+.ò“0VNéÞˆåªËëZ~ФJeîâä˜iÒU†¦ªú)9GêàJêäf 9elˆ6iÕŒº…Š:˜u]¦1‘¾M–ˆ&Cc¡nÆE2B‹;}âG÷|ö÷¶·½}IÛé£;1ç¿aå9Îòž.—îa©’rê×@KE÷òº@ Hð4DÁ,ÉÒ¼ÆYtå\ _Òâ·Ï‚QzhâTK*,§t˜C¡\’£c,ÍBK ÌJdUÍ ƒƒšs¸½íí¤µ3ó lYuOHѳb(CóÓ@à †(ä²Ìó2åS7k õmY´F`IY+ ’OœŒ ‹ÜMf£¡'dM²´ŒKÎ7®Îl2œq|be¡µæ”Œê kÙXYYAtt¿·½íí$µ‰ ³µ8§Ì¦qW« ;p2À°^ÌAò9c™èºÑ=8D£;‡™aÁ}[Ø'$am:Sú°aÍED*:¯¾zÒë!Îê™_Íœ+§?‹ šŠ}G8ʸàΘµ‘z8MŽ)ü¼·½ííKÓº¦lš§kW|\œ”ôbY'+ÐYœª¢”lCkÜU€Æåņ0(¨©*=Ä¿+…Рàà˜ +P>”v€Â(Œ>r²›¢Æ £H 0m¦hë­Ü–%”"0XP ÚôÜV¢+ö¶·½¬@"!pf™}—q¡LLipø4DÔ‚œÐd=Eéì[]…´P6Ø™š‰p"ØlªµÂðlfŠ¥AMÅúéaƒ7¼%Z’¥ÃdQ‘å¤ÑÎ~¤ðŽ¢auÅÝÞþö·ã oxýxÂÞö¶·¯9F(ø7©ÉŪ4V~¦ˆrñ´ º É¥·k ØÞÞÿfÁSÙ*(Au³çP—Ò]v@¥EW'&&…SÖ ´êôb]a˜!j·#äm7¬lî}è ߸s¶Ë[Þ‚ÿù?·åo¸á¼þõ¯?§û÷¶·½{Ëw¹eøÀ¤*j° æxMþŒ` µ¨ß 5ÖÀꎵƒZ2:eœ£ô7¤÷s6)ËgðŽ• <»Hœ‘ ’r‰ÍN#*ï6’dÍÔèM ,DÔ‘aH?BŒµR¹¥¶^C¼»öÇüÇ{õ÷½ííËÕ,hL+qV~)*2lÓY½= Ñð¢f²cdI‰#ƒÏ3“ÉóÆM(8)‰ªŒé!:BGº”‹Ć•]²“dÿÊ ÁTJ5fÔ“€™JÅIÙY¥ÂÌÃ9‹Eƒ HëÖÕsƒ·w¿ûݸùæ›ñÉO~¯xÅ+p饗â)OyJ~Ë-·àæ›oÆýîw?<ëYÏÂ…^¸¹ÿÆoÄ­·ÞЇ=ìa¸æšk0ÆnØØÛÞ¾`óȺí°ÈÄ8ó`ŒF&¿¤ŸnãÈ>,qbH7Ï´iÓŢä8™)¸1@^ŽÌ“Ûqjÿm.é‡7ò!¥x‹ŽŒ°bNiòrB Ô”rP6º‚¶øÜšè‹ö(•”–ÐÒ'% U6×R[~á–\ ‡Ã Þô¦7á/x>úÑâ×ý×qÙe—áŽ;îÌ9qíµ×â¥/})N:…W¾ò•¸êª«* wo{ÛÛçiŒ2pÃÁfBUéå÷æèaœÝ´ÿCU¹\¥QI¶æ» žªô ½Wݪ¸„.¹gØH?avh ÑŒ1²tZ¾$2inUŠ¥Dì Ånq/W“éÀ¢ìÀ©d¨¾ÉZû…ÛcûX|Ï÷|>úÑâ~á6ß]~ùåxë[ß 3ÿü˿ࢋ.ÂüÁà‡ø‡ñº×½ög†Ûn» c œ9sßú­ßŠ·¾õ­¸úê«ïþÅ{ÛÛÕæ¥¸ nŠ,‹âб©Ä~k.a3 8+2 .H£Ó°¡`ºžUz¶øÜ *(¦‚g3R 7`2ãkÖD°2¨ÜW Ê€)OæA#A7 Èl ¸ €1d‹Ñ …rùlá\Ó åtwï9©‹.º(ïw¿ûáòË/Çm·Ý ¬¬xÄ#pÝu×åõ|àñ‘|d¸½íí 4§ôWeA›'†Óç"ë-Ëä óeðb3´UÉŸ¥‘˜bÝShõcÅmïi‘ìÃ!r©Wð{ë:†·Î0F,+t yÉöE¢»²_ÐÞ˧ñe÷ueé´dmSž†ÄT"µŸ«‰áÜÛ…^˜"è§>õ)œ>}:žúԧ⻿û»ÿƒßº·½ýçj6X^Àšó>¹¬ÀЦªBèЊ%Ù¬Ê6|dÙÝëVø#I0ì+mÈg 0`äÀ®—Õ¼ƒªF-ç»x˜ªÞˆ§ùÐt2‡'<¶rNgDò’@áò{ÎG¡9ô}‰Ú%—\‚¿ýÛ¿ÅË^ö²/á[ö¶·ÿ„Ínkf’1M)mÂLÑædŸ,âÙä3+å”Ô\Î{#003QDTM8‘2D8(@£ ¸µcóð­K®%+i¨,¿’uÓ‚’]”•”wû¤¥¥ÞyääM'N-‡–V™râ»»vŸûÜûØÇîÑ=ãÏÀõ×_[n¹åÝ··½ýWo¯rŸžæÉŒ\R²[Ř–Mqî =ÕR@M=ž~Ïä½ùVéû2æ”q°ªÒ'qÐÑŠfuyXƒ5=IJ“FÅ¢ ,ØLÇ`v‘ mìì S^s&A‚¨)¨>txHG½Þ“sÓÃ=éIOÂ{ßû^<ÿùÏÇk^óšsºç Ox~ú§üãñ¢½¿ôK¿„Ç<æ1¸ýöÛÏéþ½íí¿jëú¶®'KˆJéS~­úvn~ °ëª©pþ/F‰©ùP•K(ݬ$GKîÑp ÇJÃ@iÑ”–DöŠ ‚6¶š YÝÆªD„sy¾p¦b°†çæÀŒ÷Ëo`­Ú¥œ»ÛvÙe—á=ïyÞñŽwàâ‹/ ÷¹Ï}nsÝsžó<ô¡Íß_ýêWã¹Ï}.Þóž÷`ΉW½êUøº¯ûºszçÞöö_µ}ĦÍM ½\DŒDÑPX@]¦FsO)09@£Zʲ5X/©ï?&ÅÖAÕV¹/r þž¿ A“ÏJ75Œ3󡆈ÖtõY0殓IÄá“ÅX]`<1ˆÊNŽaImN|&K-bŸ=ýO¸õã{<éÞöv’ÚŸœÿ߀Å)JúZéÏÖôôôo%¹†¸˜ˆá“e5\?„MÀVÅ5á´AÊ*.®…k™á~(Mv†U6NE¤ÀX*PªO˜É¡@ V€'ŽÌëû4"(A§,&@›ž½ímo'±…S„m O‰š„OÚdòËÒË9ÕXÃÈÐCi*礸9¥SŠdf„huÆLn$+ñxvÉ­u!º#YÖè„î ®·¦‰üÍuMÜ‘¸gí~˜ iÈ>Ä%ÊÅ¿{ÛÛÞNT3æxóÉÃmÝ€@Èrƒa)k$*Ö)½>ª¨Ÿ $†Æ…  K‘Je •8†ã°áÂÔÇü¤^˜ dåóVºDËÂX™ô$»ZfŒ¼r?1S֒ʬ;qÎvÔ½ímo_¶fo¸yêÐBé_QMÆ6ŒâÖÀ#”YEiŒ¸BýšEÊÆ|™‡´{¸eꩇØÌÀD Ö1ÐãÊ& áÒ!LÖ™iOÈN(±™Eqiݯ]™–;—··½ííÄ4å\«xÆ‘&€Õ•n+qG>·,Cñ³$ɪ‘w½€|^ïªB‰ÕW¸-ÉÛ(¢Ê.ànðáY$F!ï‘€sR¾´l(˜6:#é³ðsÒén)ÑÕz"^5ÃÒ2ÈÉMêáŒJ¹ŠeÝÛÞöv’šÀgÚVìÔß‚¨™ -…á¡'ùˆ60MwÖS+*¤³Ôdƒ>uéµc\¢¦Òû7Rl-nNÆ4“‰@v‚ 0£nÔǹbP—(h¬€ÚÂ:Â{Ù,Íueo{ÛÛÉjŠP’¤Ö<1fÞšœ”d΢p´QÜ…ÑÊJÿü€µ¿2êŸÆ G¿6/?¸šž½ímo'¥eí”n­~²§®¿@/ Ž©ÂcÓZLîA±We ”¡a#VçppVepê½ä*bódÞʪéÈä´kšE €°ŽRNŒu¦Yq”ØË'o?)õvNno{;‘Íf¨°¬Î®¹cbApX2F0³¡Pª¬š›ò¡\ÓÄH©°@•²£è>Cÿ–X׆G WŠ¡nPú’,1¼…O*¯6[z¹ð[‘B&(Jál  –@l£î[ÙMv?¸½ííÄ5[eF€a…MævtàW`-^=8=0²@Õ èYz9 -šëÖ4†k40G8+`˜8XÊÉ´@¨ïpzè=šÒÄ¥¬,Ù9]M¤ö³Œ{ÈïÀ}´ÎSÿGq¸ÃœR!×Dìmo{;QàRçÙ¨_›uº›ÇEp/#uí]2³,D%§å†³z¡oÞfc`;ñ IDATõ|lÓ£ƒ"ðA3Ò'ESO\ÉrtÌE{…Ò,…Sp³d ë=ô[Ô`nºu¬0,û²·½íí$6cé>@¶ÈJ§Vê¥ø²ŠÕËPP¹"{Ìifj¡Ë–*¿xw3ÝEŠ{“{I(ˆh "ð¨&¡4Na$èéMÄvML› 8N%aˆ¢‘ñ×dV5Ýi˜4áv/ç%Ñ3þ‹z†î3Aoø6XCNÅw1Hœc[ׯxÅ+ð©O}ꋺÿÞ´›nº oxÃ^ loÿ™[3<Bm¼œ÷Òω©ÙrfzZ}Ukn"#Ÿ%¿·ÔÛ7]}ü¥™† Ã00ÖK,˜Õ+=Žrozw”Ix dh3 Ê…ItíaWäݳëõÊæ¿âØ ÿ+£ãå/9>ùÉO~Q÷ß›vã7âõ¯ý—ý½{ÛÛ—«¹ªÜ(;À|Laz@Š•ý¯š¤µ¦ p«è*Çl¤Q¡tu²ÊÆg‡aÙ pÁ8Š¿Œâ̘…ÓS)¨®èMÞö°€T¹AUÙV"®¥AbFˆ×HkEB¦ž¾«àö¶·“׺·Äô ÃÂp-I@¬tÆXü9ó—;,õõħ±Áß%#¨˜)©ÂÌ,ŠÍ2nbÃA<ã·&ÆT}A9Þøœ°&Ø7ÃR¿äºâCr…S±d-ÎÕºÏÒ!8ãÑL2ud ¾§¸S§Námo{>ûÙÏâ OxÂæ»·¿ýí¸ï}ï‹>ð¸þúëñ¨G= W\qàŸÿùŸqà 7àŸþéŸðØÇ>—]vÙæ¾=èA€w¾ó¸è¢‹ð´§= ÷½ï}7Ͽ馛ðçþç¸ä’Kp|||—¾}¾w¼ë]ïÂ_üÅ_à…/|a^û¦7½ wÜqžýìgçg¿õ[¿…‹/¾—]v^ûÚ×âùÏ>ÞøÆ7âÔ©SxÜã‡Ç<æ1÷`¦ö¶·{׺ÿ½5?sxcX¨$àP¶ÜÔ÷[2P:™R©EAìÆ\73ô˽UNv9·òŒ qMƒÞÇnŽ9&æ˜LJ9©\ üMY’¦YPÓ%$¼<‚«›ácÃ7^sÇÁúŒ©°R9§§ò9Nø{Þó<êQÂßøF¼ï}ïÕW^¹ùþ†nÀ‹_üb\y啸馛ðÿð€÷¿ÿýxô£ßû½ßÃûÞ÷>\qÅxÙË^¶¹ïiO{~äG~ùÈGðÊW¾yÌcðéO:¯yîsŸ‹ÿñÇ_ýÕ_áW~åWðêW¿zóî/ôŽ9'~ögŸýìgóú½èEø‰Ÿø åg/yÉK0çÄ™3gðâ¿~ô£qýõ×ãÖ[oÅW\ßüÍß<Ç™ÚÛÞî}sÏ4Î Íš)¾†Ø)Œ–!®¬TÒã Ç:~2MÖá Ø9'M.h´„Aa¨òÑn8@8ëMYç]ò’ƒòbÕž ‹3›˜©_-$º]ƒß B_7š…7J@ØYWß]{á _ˆ—¼ä%øùŸÿyÀ>ð<êQÚ\ó™Ï|ïÿûqÑEåg?õS?…Ÿù™ŸÉû~ôGO|âñìg?ßþíßxøÃŽ·¿ýíX–ÿöoÿ†K/½¯yÍkð²—½ ozÓ›ðŽw¼þð‡qÿûßîŽg=ëY›÷~¡w<îqÃýîw?¼ë]ïÂüÀà/ÿò/ñU_õUX×ï~÷»ñøÇ?þð‡qçwâòË/ÇwÞ øßù\z饀oø†oÀ«^õ*<ÿùÏ¿3¶·½}ñ­LˆŒ2u%Æ`ñ‰|÷×ý×ß«w\sÍ5€{ÚÓž†g<ã p7Þx#®¾úêÏûŽ /¼Î×{ÛÛ—§e*$Tê"O¹KìN|¯ÂñC€GñÓnTá  þ€•5d²èŒ¹añ‘"p)<Õt0èHüe{6àc–?š B–ï‹4H©…S DÜL—ÁjP¡¦wÎd3JB­ée¿P{Ѓ„Ó§OãöÛo¿G‹¤ûγÛo¿—\rÉç½ïãÿ8¾ù›¿9Ÿñ…¸§syÇ“Ÿüd|èC©S§ð|—_~9®¸â œ:u ó7ƒ?ú£?ÂUW]uƶ·½})[èÚtä¶6¬Š·KðŠ’¡kãœ`f0Y¨ÊÜáÓgmTáŽmÜy™Š­Ä]C`‡Œ ‹E :^î#des2&Çp_1=ào¨$Ø9ˆ¨yÈCðð‡?¯zÕ«ò³üÇ<§û¾å[¾¿ök¿–Ÿ}øÃÆûÞ÷><ñ‰OÌÏÞýîw§?ÝÑÑ®»î:<å)O\y啸íßþíÍûúÏçòŽ /¼ßû½ß‹_þå_Æ•W^‰eYp8ðÔ§>¯|å+ñÈG>r#Zïmo_éNùñÇ$ÑåÉN‡5@ÆGódvdU5æ“`ˆQ~lò 0ŒFªÃácbÚŠia ¢Y ä).rFÑw *$VïŽ-Œ4FèsfjJqv¦Å ÔLf EžêMt#IËK½3 w7Ùcà7~ã7ðÌg>üàqñÅãæ›oÆ\p·÷½öµ¯Åµ×^‹}èCxèCŠßÿýßǯþê¯âÁ~p^wûí·ã;¾ã;põÕWãOÿôOñ€<?öc? ,¨¯{ÝëpÙe—áéO:þú¯ÿ·Þz+¾ïû¾ï½ãšk®Á‹_üb¼îu¯ËÏžþô§ã‡~è‡ðò—¿ünç`o{ûr7¹¥NÝÌÞ+Œ“5Ò /ý`^¹@ú#BÜÔ};Ã≉ù³W”Dæ§·ç†Ã E±fÓ3ÍøàCJ J»GK©}Ž, “<0}HèêFÞ#Q8Tx¼ÔçÅ̹2œœc»êª«pë­·âmo{Î?ÿ|¼üå/Ç›ßüf|í×~-àIOz>÷¹ÏÝå¾ïÿþïÇ?øAÜpà 8::‹^ô"|Û·}Ûæšk¯½Ï{ÞópË-·àꫯÆÕW_ ÿeYðÖ·¾o~ó›ñÑ~×^{-.¾øbÜzë­÷èÏ|æ3ñ‰O|b#Š>ùÉOÆK_úR<ç9ÏÉÏ46 ¾ñ¿¿ø‹¿x·½ý´&¡™"‡¶eà¨c"$qcé©QõùÄymj=$¾X½Ó…™y Ë`!W5`À¾÷Áÿ»†c³Ð·M©ù3ÃÍÌçtIÜ´LMîÔ§axdî…a™|y¢nY=ÚRp£ã0]ÿåô?á/nÿÊÅuþÜÏý>þñãºë®ûŠõao{;iíâÿvîsÞ×¥¹PYx=uörð—Îmï›"šò·j¬æò‘WZËØ[÷ŸÕŽ*`¬lŸØégDÀ‘Y6‰Ac2¥EPòáÃëœY@ iFVÜQ^vaÿ€ûÊ‚9å Ã:k"ö¶·½”&se0,Ê©êôñiüëÖÄSO|PÆßî?ëYØŠâ¨Ì:">2j3Ãep’­ëç×Y¥ÁË=Äèçâ™ëâèHù5ÔŽ&]\/Ö:肳”PN%%ÍÆÊ½>¼…mímo{;Q­¸.e󭤹!f#˜X•i8UWá™…¦ÖÔåU‚lÍTk!ů…8¬Ìáa7ÉL9Åœe§æ Ç ®”Ó©»•$+ dF÷ðõt0 p¡¯C!cg[Lí.Ÿ|ùÛçÓÝímoÿ•›ÉÍÎ:ï^ùØJ¯ø¡Ë] Ê4Žp1‰òqÇLÑTqíL§¦ðQÕ}±B+i¬<¤UƒfØ(C~…|”;ô™ëA¯rbU>¢”r"†:ãUãúè$'ƒ™K¸_ÉÖÝEö¶·½±éXZ±>æRGí*¢¬¾:ÿq½Î}øÂ)©%=/$éeiøŒÊÐÙOއċ@ÈCVÁ2ÂÊàJQÑ„†–ÖO9XÊÍl‘ŸÜD"F-= øU‚¥Àd_ r Ž ýáp–½·½ííD´A•/ª’ôÜ +k™*¨~ s»$X¹‡I¿/ç_qZ%’]RÚ6y2/R³¹0_ ºñIas[iâ]0ܳàªâU‘IJÂutiòZ0B!ÜLcTdÌÂÀàe_M…a¼ýK²6{ÛÛÞî]K·^›Í ãÌ ¤óëfX½)]Ül«„R©Q µƒaYk` åàˆ9Õ“J{‚$PЍLo‚¶Grl|kÏÅ`Á¤B/*X›­É}™#½™+HŸþnnX\üè$°ϨlÀ““'np¯ªµ·½Ì&£`Ši<´`zà¡’äÒLÙâRœTXC÷«Ãö¬¸'0”¯3þº„Öˆª¨¬&‡pгvÊ5Cr²ƒNw4æ €''éáâ~uAr·-%ä Ó°9°R›8ÝÒòš)—djÎ\S{ÛÛÞNN34›%µ £éÜZé–’ÉLFOÂ’c¢]ç©Â’š YÒ 3cé'×zxˆ²h  š‰×|„5£E0ˆL9ÚhÙšfG=Q}6–RVƒBíe!÷—ÿïú·½ííd¶Ý²ÔNÊ/yVP€ e eÁ)8à "²½Ca½GOùëlÜ!U¹²,©{ÔEE ½Ý<8«ú5)õºŒn`áÕ™0ÃÙÎ¥tÊÙ£àe 6É1NuVV‘YȽ·½ííDµÜ òUÑx3¬dz,¡‹Ì‡¨* ¾¶Ð$* Êö5&ÉåKÛô~™Eõd)+c7ç‹¶èé®2]ñÝDÇíxÌ„Ám£ö_"ÄNB@VXwfÿ†…žÏ‘ÌÎm`(‘_õÙÏüëвìmo{»·í3Ÿþ…3iФÞ7¨ˆLdüÏSA37œ”¼R©ÒâvK—±ÔZIDyu,6°˜a±ÈûÊ'*A¶˜Ž ÆWc±¯ýï×áÿ{ÛŸ| –lo{ÛÛ¹´·¿õ=xõÌ–q~09@ê¬Äy9}eÝÑÀœmåÀÏ•Ð6bD£¹c:##LIÑ—’Ba›Lâ¦Ün¦BñkIŸ,ùšïx¹¡JVI?¤ ³lʃŸfð½0 ÊP–Žˆf0êßzƾcH$î!ì‹ë­À²œ;Î|7½ù½X }é·bŒÝxo{ûr´ããÿãÕÿ7~ñÿø ¯gpÁy÷§¡¢I:8·ç¾å NÈêrè‡:ó‰<¼È pÒÏ¡YG…1&Çb+v’Ù öÝù‰ÆCmì„”Ã$U@älrW¡ˆÒÕÉ(z8¡¶žím>˜¾Ø•”™~I–\gºE;L¯gð¯GŸÂ°¹äëñÔºßóÄKñÐK¾÷½ßWßË%ÜÛÞöÖÛgÿå_qÛßü#nºáOð†ß½Û)L[qÁáXÆyh|TªÓ¤žrêÒÊ*Ú2e"[‰šñŒ¬Ý@&ªj/3äËFYJ}bÈ+ƒ´xXuצ÷·ï}ðOºj£Š? ¨š™žÜZg`3ÝBŒ¿P7NÍ1©éÈ‚ÊB27˜¡.òÄ`™aMYÍà ŽéÇø×3ŸÆô6ôÄeK-Ì`¾&j:GŽìÿ€´°êoR ÖuÔRºäU\Ç–H_º}®ô#Ÿ¿m–,ü@-jºôäSÚÞ¾1ã3KÅÛ¥E̤ÅPFü¾aõt©„³òÑYßkHžº…*óh>3Ã6®ÃqìÀêkfœ ßG‡Ùˆ¬Òép0²¯½ç9cažKÎ_‡IR‚Ôë¶¶&ëP U •±Û¥j™°YÙ+ B®7˜…¿ÓÐ~EìëT¦×{ä¹P’ÌÄÊ__ú¢f_ÜÛ*Ó YMÞý¨×Ý©¾K¼»aïÝIC@å+l,8ï¼ûcØa3ŽÔ}!8*c*E@Mó¬®WÏv-If$Š@˜Ï‘€µ§{KQëÒµ9œÆNFìP‘cê’+Ìë6½9á!8:Ó¤2ŰAE©íú~AJ¼˜^ J”7¹™†âbÅ"€ ž7;÷½àA8ž§q´~gæiL?Ó Áö¬úiµY{K,5D ÌÌw•d³ÝfÑIØsV.¶Æ{6 Ô–`:@¬ kŽ­|J¥œŠ7VÂýg(ýFrÅ¢’º;/ça&Õá"U\ó¬.k?ùhÆ%ö"JSíÙ=îT¾_tù6U§ à4nƒ1ÙÃØ³”y ÃK mó7O*”½¥Û•3Š&¯kNç€5¬ñœ×íôéú så-3ÀkEEìysxkîãl%íò"Jî©­ùü ‰a…wî\‡*˜±.}Îy®]}F󵩚ƒ”‘wŒãœ?¾ ¶×&ÉJT÷ÊÈ G%εº‰ x™D‰8ÜÏ_­ ¹³¡·›Ä&YR 0Š~0¡ˆåœ’+³ÀÄ:Öȇc(’AèßdbwŒ¡<êBhC½ šú¾ ?Ç5ùe-’8éuÊ2mbà0.ÀWÕv« ¬ždcëèíºÏ‡eºXùîÒÉÙ¼qñýÀV,1±9 T¢z|6ZŽ  ÝlâM+8“?+ñŸÜƒTQ”#ÒW!Ã匰œƒÑ¯ˆì=7PXÁ cd:*lFçuapM€(>u´>a¾Ä:"Ÿ:Û›—~•AÙÇÑ ÍnGÜŒt'wã§Sç€ûÌÀŠ‚ £¯xª˜ Uj•5KtlÇC€¥œ¦ùÎZâ‡àhæf—Ä¥:DA˜œÉar#8dÍ ˆ"_ƒãˆ©•sû(ÔÜg„ï[Z‘Ey'÷Ä}33y-A$ƒ§ZŸ«×5ǰƩœM Û¹ °uÀF ì’N dÂm Ü J²%ÆI;Þ‘bîlï 4cÒeÄ .„U7žtXmV®6÷Ä¢VLw"„Üà)ÒKÍ….έ¦Ç…¾F®Ï1™à2¾(QÊÕˆ¡çó‘ÎÑý3& ¥ÅÚüaÀ4*\²`¶t.›Éýäè=#;± 6¼Óÿ/D®‘€¬¤T!pú,z8˜|ÀÓYZºÆ}·&jÁ8ñ5—JÓ%KQP è$N×#(s.cåKÕà¼N\#XÆñÍÜ0@l4ãi0„÷¹,â Wk¢’DŽ©Ír€Nk—ÕÕ"&‘˜å8IT-@x,=‰  æYg7=C©‚ô7œ1+n!Þ¬4±ŒÆšˆZ%d4.¸åqœ—âÊtXy àXÆb*V °² ‹5pªÃAâ4*Q-A@E¥ÒÑ{ÕC)ä £V:q¸aI®œášA‰á3¸5yE¤ÿ™  ¥>Šs­>9Ý0¦8hÉ¡+¼鯙|‚¾!ö-Á.cSSµ¥¹Ð‹¯Åùô±¦u˜£ÄƒBvð°*“6 ý+nG¯CÊI•ÎΕ-›ŽêmýÍ–z>u}ù ɳou%Ê|"6°©­`œ(ßj–´Ú$É= mÉèólf™¤\›£Ý—НlAÄZ…¼†ÊS%èk2°´Mß=â*ÖOs‡„z;£nµs•ÜcÆ…ÓÇÈ7Dß4©ãÁJYÇ´¹œ`%nY!-ŸGîBEA¤5nì?©½×Øg±rí«ÐJ¦‚âd^¯A§rŠ{¸ßÛˆ°:lý¡n›wj2"D‰;Ê pðÂÚ›¹Ÿšñmð¬LŸ€Shª±ÿ›ÑjîEÈmÀ©Á‹«y$€ÖÒs”˜€³VªþãÃfê‚¥£“Ú£¥Ÿ@ç¿ý-+añ¼xžË¶Æ&ñ¼Kg½ÄaI"]Rd‘MÃaUuNZ¯c%ñ*;—$E§×ëhWˆ–UÊ$wŠ ´Øb¤;Ó’bM.ÊÈ‹ŠÃF޵Q0Öš5×±Äpç¦Ð&oá¤FNnAóY€|×ÖÅ÷,‘rK.Þ¶¤0êá¨,Ÿ}!qØö¼x&8Ñ.ª:9È™ë5†®º×jå{ÈI¥êŠß¨7“%8Ç&YG‡š;s<{ŒµÄp­‰9éÊ2ƒ˜ÏT®‡¶$”à}Ss3¹8å-©)bã–ªFÆùÍÍÈ~ÆŠûK¥´À¹­~ŒÄÕLN’X¬¯mú¦=Z´[$M†4íý¾§QgŒç¦øêºFb¬öe:Õv½˜ˆœ@<¥-Ënäô¶×‹Ý,P6'·G"à†I¢î‰Ê%î¨Ôç[ñõèöç]Dã,cÆaLZ9êh¨<ê¡ã(±°Tº†T¶X=° vÃ2ãZªMóõSd߃šó@ç&Ðã´íô,-8Å/Þ×FÑ82êS¨œ,š¨)iQ&*`1`©ªYÉ)ˆW³S2up´$ªîm l+7†,Ø–:Œ‰ÙÍL{®3:D£•ž9@yÁ`] ؀ϙoÑî˜ÓAm"xÈ IDATDnvܹ QßèØY$gÁˆÔô1h& I@,#ˆ¸õ æšÃªžä7(Íð0û1ûqd5w>;õTÌH•˜¸"¶äˆ§¡öÐþP˜x|7rMCõBÎÓF‚¬f g‘–R©SÒ“ï-ß„œw¤n7:÷t çSŒ0L…)–=n¢¡Æe°ªïTR Òÿ‹>QtÔ¹0î$µp1rœæÀÒŸ•=*uaVª(õHƒ& Y;A¹7”~)>¢O©q@(£Ù8#L:¥TŠ}|pBúH Œi©cĈ—ìJR¶¦˜I39m¤Ž­x lþ6vZ³å‘¤+,1Ö}´'RlX' ÍÔ- €ÄeÎ<ïÍz"õc£.ýŒv €3)Êäädœ›.*~6*ð0K_0É…äNü…à]\:Ÿm:€b³\\qú£²X™Ó‹wíà#®cM –òYÄ­ìm!’B`๠}¤£”}»ô&muYÄX³"f–Ø3_0¦az‰ÝàZ‚Âm.’£Îý]Vcq 9w<ìæDñÉ+õdœkq[¹–O-¦ Ö̘³ú7º6µ–T9´Þ ²h ‰}οÜc¬Ÿ)˹LͲ•å[ó"Q|Slô˜Q¸ôvIjˆ‰÷ŒKWéüz&†æµ0­¸áèCÅ‹NJÍ;(‘¹OÑ<6bŒ™D—g:~/òsH?%u.®§(PÓÆ`ɇZENaQ)•›ÚPê¬<„¾©÷+îй1`ŠÃ£r†°´‰CSöä7`cBÖ3ãnVDˆ(´­âð\1\ípr”QX¸”€Àä}Ü«9Fã¦8X×GÍEé*¼ýs¤·˜WÄÈàœ .´reº—}z´¼ôSï َ˪ýpžÒÒ)–.µzÄ ‹ë .%â“£Dˆæ™1Ë•'‰EìcžÀ©A•Ô\j-0¹×Ìác,*°8ãSÛf³.3 ]'©5R@úY‹ƒ{=†‡#¶Ö„X)Ó-÷IÌûl¢{®mû=æiÒºž[âðRšAjõy&š`yÖŠf§2 ”ppBS£rA÷Ê=—útQ„C•^Iq£:1>wŕ֩”h¬¹ŒÍ[) ÚI¬RÞɹHCóHŠHÀEð9‘´DÝMD@rjœ$÷¢.^»„÷E§b¹Q9!uvkêãÅÕ!ÍÑÞ6dŠ•h`í}š¼fÂ?GFaH.Fܪ¾HO&oi±ö"$#§X*5Cmkz«xô6}ÓòObµ% KAêm1\ÏÊ· êŠ(%9á<û›BºÚÜ3ðþ,½#9^öIû@ÀÇ~§Ê…¡ïÇÀª¬¦¼ÔcuÊïÉr â€¨ÓÊtV¹ÌW¸OøX¸G—Lí…0ll{‚t¹n4¢ˆ"Pr\ÎúmåsÏç|Özkã+ Ö“@Ãf“$èoèKW·c+.£sí qµ°ú¬aïÈñIb74ÓÆO ižqò›3¤¾5Kq7èAD«$º¾GŠxÎq?çIMuöß ©üßÙËZ“\i>ûV'² §ozpN* ‘§>·‰IPåz…3SH±¯’«FúS йšÒ%åšµ«ì‰¢›`_Œ}—CU5Y`k¨=3Íõ.†nÖW´% 1jZ×QÂaßx€Q”‡ƒ¾hÚ¹f&œ%ï¥É^S~DÚ ùpצyà¬m¯Šå³³zÌ~{›‘‡xMò3pmLœëÍê]Cš9a¥Aɰ¼èh¬Õµ¤©œ(JÜ]<É/ÓœpÃÆ –Átàøöš"¼Á‘5©W÷=—‹çi|‰g6—ÔáÑ)šÖˆPêÔêÙ1oÕZ(ç(ñQÒ¸èâáÍbša7NŸºÒ;öÊTF½´¬®©&€ÄÚ†ÍZ$£~Ö J4„Õ\sH܆ÚLÜ=¾U_ÕÙ&zÍjÅÅ÷•‹[†W `áHú%=´ÓÛtX¯Ü”ƒnŽÈâ Å+•Èú(8Øê‚ä‘Þ‰MÆ çU«©% 6<Ü$Z²¿ÃÙõQš’íÄ99ž9§¶CÁcmmq&*»hp[åkÌ›FŽ® àƒ‚µ·ùTqlm2´Ú4=˜ªŠpKD\yPHa/ˆ6a.7™Tàiþ§²-£:¦6~ 6ˆm?Â9“óWz:Oâq&¥'ÀNo'7ô·ž¸K®FŽ¿BS¦-½?C4t _;†Û€óHЖfÈñ³²%÷žÔÎùªÝ"Xr÷µÐùNí¯ ù-†Ž-ú\)‹Cddß4¹ç Ù$^~kHuZÓâLÒ‘;;¸¢:ÉáógTsT *x¨)$zûÔ yú,t¢ù­¶$ŠñÉse’š\ˆ}*#“úœž+ ²šVÆ›°)&ãlݼµµÄ]ÚAžÚ¹ýŒéLŠ=m>wõnEŸR²C|ÕÈìl°kj¸y…àžïîiлz'MúÔ+Å ó¡ÑÙ“h2;›¸6QD…”PIç¦ÿñ㔩£)~kÍ, â«^Eõ»ÇAÖ˜5|^™›?¦ÎrŸ@å<\=5s>ÃD%ŸJ´°ØPÞÒbåí#-æ#@µ,hZ{Ï%OÝ,9pi`ÓZŸÌÐÖßòþUÀÜŸŸº½ÞãSä@Ä'NŸP $jŸ™>a~¨á’ž¤åc6Ó @3é\£\C~^”"o­](É=¹¯!ÎÙ§Á²¯›L=(ð cAçÒíI÷ZòIpI"<ÜŽö½Î]vO8•D!Ïú†£"ˆ¥åÍC;(Ÿ!uOòZ‰ "=}M¾ÓÈÇj¿KŸ&Ò¥½!8M%IŠÙFÝgÛ^¹nI#|`u呌>tŠŒÝ ÑŽ¯ÕºÖrÆUV´!´ƒþ-³~W*R=9 —¥ÃsNMÀCŠµÈšÂC«˜¥ë„»%'ÙÅÖè'‹ 2Põ±Ò»èDnSýKÓH=ÔTÒyâX´\&0­oèâøZ"¸(*E9ù(eßÔe×ór•9>Å‚t5“F[×8N“R¸Äx}ë`Å=âDðò½-©©ˆb*ÈΜš0:4¯ ¯e³nqî…Ã!î%~ZZ­^÷ã6^À'#N¦E(KÕ}u!1„:B$€ JpòÜk{-BÃEÖãYšÛÚ5‹58–ƽewÚÚD•(ƒ¸K¯…ÜSÝÍ]Ûĸ\C‚²‹z#ÎPî«'µ §üRR‰åóÚÙçG‘Œ_`Ÿ5á†,°×z6ËnŠÚ†BgE€ÔúëE•瀞¡þãtؘÖEMˆ¶™e$­„d›…Äœ·x@Dg㛈7}sóàm&©&+©‚Ùïu×û¡Ä~k~SO…|w¦DcicÊ ¹Õ=èú®!Ø< R¬žõ1Äçât`q­œ¡æ¹µ·tB–à¡kó*‡zc±à¤} Ž$"ŸJ3oÙ¹„f -÷#¯Ó8ºŽÇÙ‰L¨]¶¿Ž@fßØÌ¡Ÿõ× C†4F^ëŠú(ªÜ)ÝœìÀY..'€j‚Ù¬•|Zœ›ônÍêiÕÉžã]•´·ö³|¶4ÚnŒ1i.䦽áe8ÒtzÜT Í`ãò=’=îúÐ+g/vFÀÓ¸¡Ùh2f‹ ñ„:Cùè6Ï:@Y:`Z›A`b‡*8O< °—šÜÙ_u¬(ÒJä ÷‹–½­vƒÆE%:*n ~7+ ÔccïDöL×Ô&©­=÷1β¥¿>ôñòQê¶*d€çØ ü¥¤7‹å_Rg¥ÞÐ%ê%h—8-.¶í Êå…ªŒœ=%tÃ07n5ëÚŠ:D9#¹ÿ¶+gÜ(2Vtް¶…v_ÍÄIôûÝK<4­W9 -àÞž‹f€i„@€xZ_a¶Æ¼ ‡Ù@[uAF)à;hÆEÓË*kT%Ìvà9'^û¢Zß9€2PP¿ç^CêP»Hù_bü€ 0ê® tapTj³Æñ¨mOænÏ}Ù9½¾ÐíQÔ¼Pϼµ>7ü°þi›©}òÛ"ìÎ=œÖ@Ìú1çtCò躃DÀœ`R£ÇÁ s-1FÔV0½yÈ ÅI››ù\Œçtmè* ò€â@ AÁÿ±+G…Ø^NáÉž;²,až}½»QOMOÉôœ(´¥6fl’žÎÌqÓè|‚âŠ)ëY­½QA\Ö˘:ñŸµqÊ3yP À"*Q}cé3Ç1ªÖ…î’p–Ü„9Ü×vÅ”tm@r i¾ñ°Û ©OÂP åÉ»¬œ@h/Æ€„5ñÌ[c½8¶\—Ö×Ô¡©*”¿¡š‘~¼ OuÖdjõY8Ç'àžH$£!ýrvÁ„¯i02m<2çO`)¿{ê“йm»Ui[´¨À+4'Å;Q‰Ïr4”¼?0³>*d™3榖Ñgj’úqUÚL+ <0¹¤ñìLo€¬in-@)¿›d™Ó*|J¬Üyì5Òãº0¼}—‹gºg-Jê15¯’‚‚:7‡Hmˆ&r,†H 5 •$Ip†vQiK®Ç ÷m@¯P/‰htyÑÞ‘œ4}›¹%ˆeÍ@rkV–dLCq™È£Ÿ©ðF S¢™«W`â(ˆ¥ `0e”f:E„à>A"“ó9ß"6MÕâÞú¬HžBãg"ˆ˜ KM›¥ ׊Þ𘣰ÉÎ".ð" yz ¼/çxÙVè4ÈíÆ†@iI=š;m÷äÜ”ÿÐyVtvÌf†jÿ•›“¸hêâI)ÀR3ÃùÔëw, •0Â]©ÕÄÃÜYlÚG„j-t‰00Üì-4 É4%ž Ë·\[ÓÆ4ª,Lò‹ÏÈ™8žÂõ®>-P˜›'s¸›ÏãŽt*v NP±Ö›D}úžÏìGŒ§Nv¿¨-î@%Bºs§rpÞ3žbÍe¥ ÔüíÌ”Ÿ©·¨ÍA@iÔÖÜäºW_ú¨Ãm†°Œ/]+C1N+âÎtg_è¯LB7€IK<Rpe~%êŠx½ö•&O‘(н—ÖÝ©S$Ö+²&C7×JÜEL½8ý³%õtÑ߯1¥>è€Âò{œÚÃoêÆrïWyÒ}bðYÇ(½+¹!ŽSÏHâ:ïÎEdrÞŠ›g“ÒJ-1x˜ç÷qÎ'” ÝX@„è:½èºùÄòi´¦Þ"÷•QR] ’²]îw…ufœu÷j`Ù™*œ ˜•´šö¦aŽà¦©ßâ…’÷§•æ+•ÍgO Eh †ªy¢³ÄIQ7qRZ¶Ldè ´Üî1 Qgv!zQº£žŒ/92–ÏÔá+¥çÌT·û?‰CEqÃ|ºaE¯›‹ë}ÆŒ‡CÏ/î2»Ý¿*`\›afÇ»:8•Õü „Q¹Œp-Š…þØÆôO©7kÔÈ9©CXó8ëÅ9áZß|‹æNÏóØÊZlI µb5Ïj$ÇÆ7s>+ù$w› )ËtÍCkûF÷¬À œN%ÏÚª’›ã—99Bž«ò’i&Œ‡£2¥”H©,8D`d.£jÇMÛyÏU‚u’Í]JÞ—Vý•]*ñ‹¨ŠðÇ~e?R»¯o-ƒæ7ç|‹uíEõ±"`DÍ×UÏÌVMqê|uŽâlZëφj»T3¸Ñ_¨6h¼@‹UÀf ˆrÖH½œµA6…tŽ:޹0Ð×:Æ@Ë‘Jpô:€‘j§m[ýUé¥ú< ‚GÅè¨ËHzMzUrÙû|iÝE‚t@•ÉD³S’„ˆÁÚ]rËâРT÷¥çSb9çáé\,¡„¶ ±Œç ¤««?"ŒVºl/ïÇÐq^h2ò¾F Ȥ)•0Ô +¤ŠÉÉaNqjù­ÕòpeñÚU†3j§˜i¸yG°®ˆë6%Aî¡-, Élý©òèŠò™Ï¡HåI#+j¾K™Ü,R¥Ï+~QBÒàb÷ƒd ’Š™,B€˜XqbH 4ô‘f–Óì÷¥;õw:Ÿ“ÜñÈþ®ŠÆßiÔ{pcrJˆ˜–® RÕ®Vܳçå‘{°¨pmœ@æÒÇÌ}clœkfžûd£¯YòÞñ$YI””Ê'ÔT£­^%&5rõoåÌGÖ§–{*Âsc˜6pXmEÀCd¼j)¹€Ù§Ì ú éN¢Ä%•Ö«Ã1Ql¼”Ì9G¼•¬¤4ËX ꪪXÈ} põ ÐfÜäðkõœ íJ(qÄfÿÞúì9gµ?O†¥ObéÜDÁ @ÚêËWuŽAŠC×-°¼&3d²ƒ—$ÊbŸ4Š}šùêL‚Q¥6@õ¼f²ÂÏš>ÓR‘z›¬“úqnáÚ‘ÊçX¬p¡*_:Ý·ϽÕ3Ë ˜K.ñÀQ›6·H€FK ´¦zn8=§T 2É÷Õ#—ÐY¦Ö®á„Ò_¹ÇÖ֖쑜W€€R" {—† #·¨ž«÷ÜZÉ܆ܨ 2r…!w–O¡&ïËÝÖ!Ä)ø`kìaXì°™GM\?¦@ù1B;Ò=Z~”Ù›ëeòm}s„$_5Ú^²<Ùµ<‡^*2)ÚWp= ˆõû9ÍŒöjí|éÖXLªIÓ6ó#ÒV„ÕPë y(p`TÇÚ¬(ai‰´q¶§!ôÝ0|Éý~X‘„ mæPÜÙ ~­+ö„¢Õri²0©Ì­¬òY©7‰b!'?(x=4GR°é˜¯L¬]FýÌЙ¥%ÛñÁÒПM˜sä#OÍäXbLèrœ @H¢žÀ:¼ U±Úè!²“õöÞûüï4?.j2‚q¶ÒT›—[ ÕÂ}MÀgöUBJ5N‡ÆÎEi+hs×Ni? ó-upKŸú¦ôoꇖº38’{ªM×[Ï<¼ ÈMtKC×*Ï’E_“é-‘Ï™=wŒÔ£JÀÓ‰é0œÔºÍN\ O÷½Ñ8§Üv.b¤9özVrx®qG×ÃÄõÑ9NCAÄJ £9HÐaW‹³ãˆ¬1&I­ 'ü"æ‘n¿,¹©]ᛪïü=¿·Ô÷Ý…àˆ`ÅŠó]µ¥&¿3Û‹BKT¸D0ËMQ΢åi pCrO1X@”kë(¿yß 4Qˆ…˜í^‰ŠºÂ½^¬vŒdu@–Q§÷{ùQßQLÇš‚i‘¯l–‚Šï[x¿†á#@®®Ê±i^b]䯣ù3zÅ'=2ŽhtüŸiù­ÇìÌè\fÒr¡Ý$“¾rótc‰#@ÛL^çV.]Æ‘ò•ŸÚ˜T W’‚›ÈÒḑ–…˜ €? å_ÏÎ_ÑRž:^§MîäpP@ÞäQFn˜hG¤ÈŽŠìHòJy O€“Z3|ç:Š|= ±n©8ì™cÔ¬T&÷ £²µ5@$˜§! €ÔçMF®‰jx€\_24µ‚É!ðYŒƒV,Uiåœ!£½ráâ|Ya,•ñÿÒŒiëÆbâk¦TŸ3Œ2‚0£ñÊ]w蓤}cd(ÊYâºsŒî Êå™ÀŽsrB#º'Åð`§>Ë$Ne,Z®Jqï¤*1ŽÑ ØpÀŸŒ“$'^q 2ˆ8äŸ6žÜÀ€Ó¨è¦õkŒœüÜG˜©K eì¨ÃÏÏáq@Œ<)Ÿ;l ¥–xÐ9oñÝÐÁ–¨I¿½˜f[ŠÚÃ5¦DÙ׉1 Ã Ÿ /×”8_â°ÆËÂñhÃóó V³ÆÉ#!< „,€£$”î|dpÒ¼hMS8Jn¤®k© kâÚëR+g€b½K]|žyV‰wðp6.ÆuîKŠÜwì³Ö)Sïc§ëøÈ÷p…ù1̸-ð1[ ¬-Æu®yãií“ ¯äÒÄ£¾ÇL„QôSWêùÆó†ÕIéÄÏ”Š¿éU —Ü—këAôa`„ÁJó8‹ËŽýê¹çY\% tS(cÉ‚¤¼áá(?%Y˜˜ŒØ¹3ûl”È&2¢E@ìçì5´Þ:ăŸ7Ö)IÑGw&Eö´¶¢¶Z"n bÚ2Pdy݋ҷӧ ”WK,ñÓ6€¬™ê &ÎW%Ôqí&x’e† ‰R™YÎEÞ!.•siúÓTfÃ~kŽI‹—Ókì%Â:çKjô.Òi|å·†6FöÖJŸ¨è„0`8"OùÒ•¡^2ãáɸ®rOÄ;'ùìº*æF:ŠÛý“iú³šZ@Ô¼Í ’7Î0¹5E³ÕÄr¯kŒÚ_äcH$Yh®p[ÈÅ3ÇHÿ·x× H1|¡T0kA²_ŽtÞkÿÖd¨ØqógDöÕ»[Søù çônö|“,ÿƒæÓÛ¬rʵɽ ˜rjwpª(¾ŠDþÜœ>¸aÓBÏ=›yÑŸyrȇâØDQ]­ÄËp›œ| AŠPCŠ4 õ²Í#´!Ñ6,Øá~½;ÄJvÅ#e·;(Ö*{HÖòt÷™ËBq+½õéOeY3¢or²å™%¢X΂¦)XjY K¬Bö=ô <ôܼÁºëЧfÕݸ6(ðä .KOïFŽò´iœIûIS–ßt#b  —E¨ŠØ„t†Åk€3KåHI+Pp¬ÒݨGºŒ ®I :±^Ôµq¨ÅÞè"Wi …➆šRi”³u,•Þ³2[váàŒƒ›ð4i]#eº¯ÈÄs,ôÛŒ^ÅZs¼Ò!ƒQÆ2U6d¿ã˜Ë¢]zÐ^${5o Gísíé‘$êY>/‹í˜íFCr’IDATö¤£ôÇ(#„åé5ö,ÔìCÊ©˜ùTÙè³ÐíÎ\[ ˜‡ÅŠÀ‚óµeß…%£:Ʊ{;ßq¶Ú•¿¬øŽØ=Q'3&ʈ*Ûr. <„¾Ã”µ`°ðŽÐÝM¦"©¤`rñ™åp1Sø?ÉM¬<‰Oý€ôt¢ˆò³r•ý£W´VR‰ª –™ÓÇhï0¤§#¦è 1‘b–“­©[´Ô$š×ÓßÐ{ÂÂS‡ÐuÅÍ8\Õ+ç«Q¼áM»™)ê3à >•I„žÿ®º+TßTz­´DºÊ×ɱ¹Æ‡(mwP! mÕÈ­ÓùÒßÅÁ]C_ªtùRÆNdÿ Êô ;‘zr.ÉÅ>,]H' s¨ÕÙIä´nVëâÑ€EÖ±xÞ<¦øx øØy›žÊ*ì4õuò7½Rl¥Ì˧¬‚ÖÌ«£> x43†€‹»G‰¥‚#É!u8Ëo6rbq€¥î,ݹ¥ÅTnX¼ûªËcD:ƒ.@¦ž3°U°휲³£}fé»êý ›¨ìÉòQ,Ëö*çâ)` rfñÔaÔĸô-J7âŒ&¶te7Èép§ƒ-ŠÓÀP+PêRMFÑfËéÕ¹ÊÃŒõ!µ¡4ùEÕ‹:rkz­ëÏÈ»Þ^<çô™X}Ùø´¤¶ ª00m¾¦x×™ç¦è:²ø‚]V“'Њškûˆ³™F W”…Ž÷ ¸½6°)äǨžÓ ³é5RS:qQ`Qv‚@p2  kYçÊ‚ E¥;5Fý¤fÑøÜéL~™¯hpåÏVÑæâœy'L{%×иòs’0û©…R4Kô®<ÈŠ+Š ÑþXsPoÓ{ ÖsBePרevÎS# ÅÏw)ÃêÞö…msj=[ù¥¦FÒ 'W§1pc滺$ç$Þƒû0Ÿkâwë„9€¬ÛAfa³&d%>±f%›:.Evç(‘DÖ%* 5wˆÝ0Ĥ°¦b­ Óˆ€bB®“%çF û"/ÿdñ-9Ë6}ÈR‚qz·éÕ5Źé€â«AAÒ*ñ•›¼&S‰Öœ’ ÇøÊ[géþ¯\s„A[^ÜF)u½Æ+0☆ÄïÉú¾ÆjñùåÓÀ,À˜9 ÿ·•ÄÈfŸi½Ièà…rŽ”éÜG7Iòšá6sÙ· nªÚ”/Aêhøùp)Í56ê_e ¹ö‘ö°F˜Eì.{H…¦k̳%ˆë‡M¸ŸÖÁ3²`=³L\béË0!Τ8Gó &f¤ÏUS­¸Ã©c3˜ÚÑùì"öF+8‘jG¬oºÔ$PQž¤C ÄXéÓ$zè=?ãzè˜åfi‰o½öƒDÔ8“€(œ*]tĸ[qÛ°22"þPŽ­A@HaØ—áIâó[;ÉDajwC2xMRmÛžŠÈ!]´Õ¤¦KÇVˆ+ ¨Iƒ– `7r.)E< H¹TÊfnö)¾µÑ¡)Ü ì’›‹+µD©Ó(òÁ®Õ&µLB¨(¸žš¢a^Rž”/¹X®SV/'ç˜ÜD× ñz-‚2^l ÔkVjnØ©)bú*aA?~é]Ÿœ* KªfÎV@djÓC>S}4“ŽÖ å›W‡É9Ÿâ¶Ï¹WDÀ•Ý¢ö‘) TÕØd†`[aÃ1Ò*»Y2X_ï<›Ô¥?äØÛa¶»ô¸qb¯¥nKãÉ=¤+N’ܸ«)G°Cì­æ-ãÆ¢oî©!:—§;89îC™€|*9;Ï{]Ì¥®è7÷(dmþmKGÖ9õ…IEND®B`‚././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gtk4/controls/images/entries.png0000664000000000000000000003376515074674453023502 0ustar00rootroot‰PNG  IHDRpþ#Ô^#sBIT|dˆtEXtSoftwaregnome-screenshotï¿>&tEXtCreation Timejue 08 dic 2022 22:23:47R=šƒ IDATxœíÝy|TÕýÿñ×Éd™d²ïd!È’ û*‘E,ˆ´¥¢BÝÚª­mµ¶Ôºa…jÛoõWq¡n´ ¸"D}“%„„ˆ¬$!+Y&³üþH2d’I2„ÄÉÏ“Çyܹ÷Ü37“wΜ{îB!„B!„B!„Bˆ^Dq’:…âj`îÎʺ#lÛ«C‚\!µÜWè] ÙÖÛ)v>&„}Ië€6Ûù˜].7\mµÒÁ×]ÝB8;[amîàk[Ûuèr‚µu0+-ŠªÕ÷í¹Bô%­Ãºe1µú¾õú²7\m…vspÛ*âBˆ¾ÎVx›Ú)­Ã½åöír±£íõ¸Õ-þWþ@ à ¸5Õ-.„è«Z±¨*b  06S‹ÿ[n«ÐIˆwà­Ã»¹‡ÝÚ.€0ð£ÿ­ýÉèQ#¢à‡Y[!¬(˜Í&sÙÁC©üdáÂuÀwÀEÃ]áRˆ7y§!ÞYж2iÜÀôèÑc>\ûþÿ) >]~bBч˜¡|îÍ î;vìØaàÐ@c7÷Êm ©´ÑQ€·ì}7÷¼]šŠ+à=jÔ¨‰ëÿ÷Á›fû†b„B4QÀ0gÞ-KŽ?¾¨ô4†¸ë±qh'Ä; p[=oWǸ¿?¹¤ç-„]£”õw+pœÆ1òæ·ÕoCÕ^­­¾nñæ¡“ ÷ß[³ o!„¸f¿w×¼5ŸÆ 3Võ,>h§³ÝÙeð-‡N44ö¼=€øìÓ™ÿUÀïŠÛ/„}˜Ùdº—ð3àPKcO¼yL¼õIM+]ÛšyÒä~Š‚o÷Þ–Å9T*/0P\i¤Á(DˆÎhÔ A:ÃÂ] ó6u¾ÁUNQ©ühì k°>™©¢“™(öÎoàZ™*Góáx^Þ¾~„z (}þÑ)³ÙLm][¿+#1LEbxŸÿ½Q-ÖC(ÍDvÈžxëo:‘Ù·{›•*Žç5ÆØZâ‚5h]ûü QˆNÕèÍd¹óÍ7¾Í+ HçJ˜Îèèf9š+—òµe€7—.õÀÛFQ÷ñüæxo_?ÆÄzáêèæá4´® Ã#ÝØYçlj¼rÂâÛ›OÑg\ÊÖ¶·$i—­£fëv°­C\eëÎ,}©Wqs÷`P°¦£ã+„hÇ WÜÜ=(®6:ü÷ÙÑëÛ“´Þm¼³?{íݸJÝÉvW½£EQкõùžƒ]¢uUP½Áìè¦ô-ÃÛÖ mêh¸­¹à-+BÑ=Zç«­üm£«w#TúúIL!DwêóyÒ¥ÏR¸œ»Z/ëóÇ[Ñm$O ýO>ýìs6µ³î\|ÇeÕ]VVÆéÓ§©ªªÂËË‹ØØXzè™´Ïh4²uëV&OžŒ‡‡G§ëçææròäI›Ýpà ÝÝãw¿ûááá–åf³ÙiîÇâííͼyóº¼}yy9û÷ïgæÌ™ÝØ*!.¹ùÖ%\“0ˆ?ÿþ7x{{PY]Í‹û'NfðñkÜÂ+ ð®ÿÑè3ÒOe0iü„×›8~<­ß@zF†]õ V« µZÞ:¼+**ÈÌ̤¡¡øøx«á•óçÏ“Mmm-ááá 4ÈòXff&nnnxzz’‘‘AXXšþÕÖÖ’™™IUUÑÑÑôë×ϲ^¯'55•ÊÊJú÷ïOtt´]ϧ5£ÑȾ}û3f iiimꫨ¨àðáÃèõzRRRðôôdâĉ”””pîÜ9âããIKKC¥Ra6›ñöö¶z~yyyäåå1f̘.µOô€^˜'‘ýHÏÈä‰gVð—Çþ„¢(,îE²sÎÞ+Ú,=ðTUU €¿Ç·MoÖʪ*»ê Á`0’’ÂôéÓqqiûc<}ú4ï¿ÿ>C† Á`0ðå—_²xñbâââÈÉÉá½÷Þ#&&†ºº:RRR1b?þñÆ?}ú4•••DDDàéé @QQ«W¯&,, NÇž={¸óÎ;ñõõàõ×_'..EQظq# ,èRHF>þøcvíÚEÿþýmÖ×üÇJ¥R¡R5޳qãFRRRðóó#22öïßoà»wïF§Ó]v»Dßòä£àñgž'ç\.O<»EQøþì9‚YöèÃŽn Þ£t:/ÊÊÊ)½pààv×+--µ¬o~ò“ŸðÅ_°{÷n†ÎäÉ“ ‡R>üðCn¸áÆŽ @tt47nä·¿ý-QQQ,]ºÔR_zz:o¾ù&sçÎÅÕµñÆ\uuuüþ÷¿ÇËëR›6lØÀ¸qã˜6mšU{ôz=K–,±ô’u:;vìh7À+++ùüóÏ­–EEE‘˜˜hùþöÛo'22²M}>>>Œ1‚ŒŒ ¦OŸnUGUU÷ß?QQQ@ã;””ª««ñòòÂl6“žžÎ½÷ÞkÏ¡}X€¿?Ï<þgKˆðôã"80ÐÁ­kÔ哘æ>þÏ×Ä'°gß¾×Û³·ññ„Añvÿ1cÆðøã3kÖ,rrrx饗x÷Ýw1\¸p’’8t臢ªªŠóçÏ—z¯z½žüü|ËPCEE…¥þ¨¨(«ð®©©!++‹ñãÇ·Û¦–ë'$$páÂ…v×UWWW«¢ÑXßL«ÕÚ]_3OOOKxJFÓðTNNnnnVC?ÂñýûÜÞ?µÚWÍ¥»j\4h4‡ä‰-ÒïA7̘ÎÞýûùô³Ï6d(qÛžÈü.+‹O¿øEQ˜9cºZÚ§Ñh˜4i“&M"##ƒ·ß~›C‡YNlVWW[Í iî­ Ö­[GNNÑÑÑ–!’Ž”––¢R©¬Bµ#nnn˜Íí¿0u:ÝeM쬾Ž$%%qòäIFEZZIII]ªGô-eå,{v¹yùcÞ@n~>ËŸ}‘§ÿ~¾ŽÿH` ðÇÌÓÙüÕž}á~tÓ&M˜@€¿?%¥¥ìÙ»O¿ø½^N§#´i¤+ˆ¥¨¨ˆaÆ0dÈËDK¤  €‡~µZÉdbûöíÖïááÉd² E8“¤¤$¶mÛ†ÑhäĉÜ~ûíŽn’pyq•%¼Ÿ~üO,{f¹ùùüeÅJV=ÿ´ƒ[x%óÀ=mÒÑÅNw,ZÄ Ó§S¯×óÑú üîpÇ]wóûGþÈG6ÐÐЀ··7UUUüåù¬†1ÚS__OuuµÕ²šš éׯZ­–˜˜¾þúk›½ÖÊÊJE±\ùYeÇÉS???t:°ó™÷,FCmm-õõõ®D@@ûöíÃd2ÉðIoäèßg%ûûb¢£{Û>>øùøðôã"&:Šìœ³½a¸ôÀ{šZ­æÎÅw0qü86oÙBÆ©L***ðöÖqM|7̘NXHϼ°‚s¹¹üåùxâÏâãÓþÛ³ÌÌLÞ{ï=""" Äh4’™™ÉÀ1b·Ür o¼ñÿú׿ˆ‹‹£¼¼OOOæÌ™ÃСCÙºu+¯¾ú*AAAdeeÙœÉÒúyÌ›7µk×RPP€YYY,Z´?¿ŽgÙØbë$&ÀM7Ýd×öaaahµZÞzë-"##™5kV‡ë'%%±iÓ¦Çð…hiÃ{o·Yæçãêçßónfëæí}¦pk*¿ýÍý}ú ŠcùftÞ>ŒŒv³ký€€ÆŽÍœY³¸åæy̹ñFÆŽM`@nnnŒ3†o#7/#G2fÔ(<<ÜmÖ¸qãÐét¸¸¸Èõ×_ÏäÉ“-'(u:£GÆÓÓ½^OXX£FÂÕÕoooQ…ÀÀ@fÏžMpp0ýúõ³œH $¸ÕÌ™ÐÐP1›Í¸ºº2zôh"""P•JÅÀ­NDº¹¹Û¦ýŠ¢àîîŽZ­nSšç›wVŸ‹‹ ÇÇl6ãããCHHjµOOO›óϽ¼¼Ø±c7ß|³å¢ áx‡sê©®¬ ©°ñßÿù¯Í@. o*ÍŸNoj*6ûé¶ŽZËðnnw?5Y×TÆ>•¶ª{Ÿ‚sy牰ˆ(~q]÷…Aee¥¥'Ó¿?Ï=ýT·ÕÝ×¥§§³~ýz{ì1G7E´ðï•äžåŽQ}û“­ÄyØT5• ë o3àrÓûvé ÞÞÞ<þèŸCP/™gzµ8zô¨åä®è}ýûìèÒU2ÞËx{{óÌ“O:ºWƒÁ@ZZwß}·£›"D·’{¡ˆ«ž‹‹ Ï<󌣛!:"yÒ%WЗ#.„è.’']Ñ·Ï!„“ï"ZÁl6S£—žƒ]q±Þ„ÙlÂUÝ·§^‰.¡ôõØ òR¨­«#³Èá‘öÍB\òÝyõuuéT˜19º9NINbvÑ0¶.ã›3á=(Ä­«ô$„èLÞLf‘žoÎÔPY^ƨ80ëÝ,§$'1»(X«gX¨†cùì¬óãÀ§ù83!Él6S_WKeyÃú¹¬íü~6Â6™~5èåÊÉ‚rΖÒ`ìÛÔ„°‡F­¬S1*N-á}…$À¯P°‡žà¶·ûB´Ë ›Š¸2 E!œ”¸B8©®O#ìâÇ[ !„èÒB'%.„NªËC(yg³»³B!.S—|ìäiÝÙ!„—I†P„ÂII€ !„“’B'%.„NJ\!œ”¸B8) p!„pRàBá¤$À…ÂII€ !„“’B'%.„NJ\!œ”¸B8) p!„pRàBá¤$À…ÂII€ !„“’B'%.„NJ\!œ”¸B8) p!„pR.Žn@gjª+)-9OMõEL&££›#„¸Ê©Tj´žž… õÒ9º9êÕ^r¾Š ¥DôEçã‡Z­vt“„W9£ÑHUE9ùç²ñöõ' (ÄÑMjW¯ ðšêJ*.”’8—^ÛL!ÄUF­Vãë€ÎÛ‡ôcGððÐöÚžx¯/-9ODÿX o!„C¨]\èKiñyG7¥]½6Àk.^Dçãçèf!ú0o_?jkªÝŒvõÚ72æ-„p(µZÑØ{'OôÚBÑ1 p!„pRàBá¤$À…ÂII€ !„“rú_·n›7o¶ùØSO=E^^ž]õ|õÕWlذÁòýwß}Çßþö·.µé­·Þ²ª«Ù¾}ûxíµ×Ú,¯©©á©§ž¢¼¼¼Kûƒ¶í·å7Þ 55µËûBô.Nà}ô›6m²ùØ“O>Inn®]õ¤¤¤°~ýzË÷™™™¬ZµªKm:qâË—/o³|ùòåÜwß}?~Üjùž={øç?ÿ‰O—ömÛoËêÕ«9räH—÷!„è]œ>À{£Y³fqâÄ JKK-ËjjjسgIII|þùçVëýõ×̘1EQ~è¦ !œXŸ ð-[¶°jÕ*>þøcL&Óeo¿oß>^~ùeÖ®]KEE…Íu&OžŒ»»;»wï¶,Û¶mÇgÉ’%6|æÌ™ví§¡¡çŸž††6lØÀË/¿ÌÅ‹m¶£¶¶–uëÖ±råJöìÙsÙÏUÑ»õ™7™LÜrË-,[¶Œ‚‚ž~úifÍš…Ùl¶»Žûî»Ûo¿S§N±bÅ †Nvvv›õÜÝÝ™2e ;vì°,Û´i³gÏfîܹìß¿Ÿââb*++9rä3f̰k?z½ž¥K—2}útžþyöìÙƒ»»{›6”””0nÜ8þú׿òÝwß±xñb:d÷sBô~WÅ¢vîÜÉ#<Òá:ï¾û.‡âûï¿G¥R¡×ë‰çË/¿döìÙîcÓ¦M|òÉ'œø`»í}î¹çˆˆˆà³Ï>C¥RQUUEbbb§ÏSá<®Š¸««+^^^mJK_}õqqq¼óÎ;¬Y³†>ø€ÀÀ@ÒÓÓíÚÇ'Ÿ|ÂÂ… ñõõÀÅÅ…‡zˆ­[·Ú\Ö¬Y=z”ŠŠ ²²²¸xñ"Ç`Þ¼y–a”mÛ¶Y ŸØ»Ÿ9sætØÞ/¾ø‚_üâ¨T?bNGhh¨]ÏUᮊø¸qãlÎúxòÉ'-_—••Q__Ï÷ßoYvÓM71iÒ$»ö‘““Ãu×]gµ,66–’’Œ6n¼•@DD»wï&;;›Ù³g[NRÎ;—™3gÒÐÐÀ×_Í‹/¾h÷~ìuîÜ9 l!®rWE€Û#&&†ììl›Ao«ð(**"22²Ý»&Μ9“;v––ÆÝwßmY>fÌ<<<ذa™™™Lž<ùŠöÓQ{ÇŽk÷6BçrU ¡ØcþüùlÚ´©ÝyЊ¢`0Úý~êÔ©¬]»–üü|˲ÿûßÌ;·Ý}Κ5‹””öìÙcu’R¥RqÓM7±téRËŒ•+Ù­ö^ýõüãÿ ¡¡€úúz«iBç×g|êÔ©üú׿&99™|'žx‚qãÆQTTÀ¤I“زe O?ý4&“‰±cÇRZZÊ#>\Ad¨û?Cã¢&2ÄWØ||ÛŽ]¬~{M›òŦÍíÖyðÈvìÚeù~Ë×ÛÈÎɱÿ‰´ràÐa«úZ3 ¬~{ UUÕ]Þ‡=ºûø~üégì;pÀæv{÷`Ç®Ýèõz6|ò©]ÏíxZš¥>{ŽIgǵ»”œ/$~H’Ý!àî¡%aèpJÎÚ|¼åëòíwßcë¶ÔÔÔÙ]ÿõšéHO—ßì®&^œ&ÀÏW.+\Â|Ôx©qÕ¨9ßÎÀ×;¶³s÷^ª««­Jmmû¿,aÛŽÝ–ï_\õ2Ÿ~þÐø¶ñåþeeö’Ð7ß´ª¯µ††V¿µ†ŠÊJ»ëìŠî>¾9¹¹¼úú›6·ý׿_§êb5gÏå²bÕË=v¬Óý½ûÁÿ,õÙsL:;®ÝE¯¯ÇÝC{ÙÛ¹{hÑ·3´ÐòuYPPÄk«Wó³ÅKÈþþ{»êþ¡^3é©ã²ï›o®´iW§B0™í[/!TòùQQcâ–v¸îˆá‰üî×t¹M¾ÿžÚK/Ôµ®cþ¼¹øùùv¹NGéÎã;=9™þû!……E„††X–çæåó}ÎY¦Lœ„NçÅ>"Àß¿Ó}>ýÄR }èÓ™Z¾.øÃ£Kyaå*þß?þîà–‰ÞÄɼó„¹.Î?ÌôÅU­àë¡â·Ó}ØwüÜí÷à‘#|÷]áaam>âmûÎ\Ï ¸8Þ~ç]>Z¿n[øS<<<øþìYŽ;Neu5q0vô(ë˜ÍN=Ê©ÌLú…‡3iÂøN?H5ëôR~‹ÖSKòäIxzz^Ñs„î=¾C_Chh;wïá§?¾Å²|ÇîÝŒ= Î ƒÁÀ†O?cá‚ètŸ;XXTÄþßP[[Ç€± <Ž?A]m S&O¶ÔUQQÁáÔ# FFITdD‡m¯««cïþo(:ž¡C®aØ!ö‡Òh4,ZøSzt)z½žÚº:>\¿»—,FQOOK#¯ €YÓ§Û¬Ãd2±ÿÀ7œÉÉ!0ÀŸ„øxúGEYï‰×Ó¡ººšqáBC‡&>.Îrô\n>‡S (0fÔ(ÂBC-Û}òùçLKNæxZg¾Ï!"<œë&M´Ogá4C(&ScñvW±ê'ćh,ËL&˜—äÉŸoôÃUÝøC¨¨5±îðÅ+Úçò¿<Ës+^âlnï®ý/k?ZgõøÇŸ~AFæw@ã'y¨T*KŸH;ÉCü3©ßãØñ<úÄr^xi•UÛvîäÿ­~ƒ³¹yüíÿÇ}þŽz½¾Ý6}ðßùÓãËÈ/*dÛŽ]ܺä.J/\¸¢ç Ý|§''³c·õ0Æö»˜~}2Ðö­þ7‡³èçwrðH*ù…¼þÆÛž?ßø˜!‘?>¾Œ'N²÷À7Ü~×=lݶ£Ý¶”––rç/îc˶¯):_Ä£O<É›ÿy粑£x{ë,¯«òŠ V¿µs‹?¸ÇO¤±ió›ÛšL&~ûðùÇ«ÿóÅÅìØµ›Öo°<ÞS¯§ž–s–Ûï¾—)_ñÝ™3,ÿ˳œÍÍ`ãæî}àפLgûÎ=,úùÝìÝ·ß²íÇŸ~ÁÂ;~κ?#/?ŸV®âéç^pÔSé2'냇ŠÐ?Ð…ço àÑuÈ(Ôó›©>ü(éÒPF^™¥—‘WÖñÛîÔoñ½fµlÖ Ó‰8]{ör(õ(ÿýÏ[xyya6›YºüÉvëZ¼èV^{ý n¹yÑ‘‘@cOtýÚ÷,ëìÝ·Ÿ‡ÿü¿}à><šNð$ÊßWýEQ¨¨¬äŽ»îe݆Y´ð§mö‘›—Ï¿^_Íûo¿IdD? ñÌÿý_ß÷ËŽ`'ºûøNŸz=ïÿïC**+ññö¦´´”Ìï¾cʤ‰6×ÿä³/˜sã<üàoìjï³Ë—1§þtª7šÀÛC…¯¶ñƒÖUá…þdo 1ÂÕ²^êY=Ë>)£ºÞÔi­õ™òæðž}û™15/¯Æ·÷Š¢ÉùóÅv·¹ù-Ymm-¹ùù¨ÕjÌf3çKJ,!`YÏÇÛ›¹sfsèHªÍ?rô(>>Þ;q‚c'N4íCEöÙ³v·©=Ý}|âÊž}û™=óvìÚØѣÚ}{À®=û9|8ãÇŽ±Ä-X¾^¸à^ómÎdgsMBB›u:Ì䉬fi4—†?”'ÓYýöŒ#YgÎðÝéÓücåK]ªËÏǵZÍ›ï¼Ë‚ èÙ×SOª¬x†ËIIDATªâБTž}jy›Ç§¦n o€Ûn]È[ÿy‡syyÄDG kú½yíµh4 $À{ŠÉlæLq¿ù „—@€§­«b.›NÔðRJ FûÎÈ | ÷ü|‰ÍÇŠÎsíðÄ+j³^¯çÅ•/sâäI†Œ¯¯O§ÛôëÎÎ={m>VU]‚BAᥩVáVã™]ÕÇwZr2;víaöÌؾs³gÏlwÝ{ï¾ WW7ž{ñ%ŒF#?ž3wý|1n®®ínÓÌÕÕ• À@JJm¿õ¯ª®æbõE«ã¶háB»žƒ#èõ TWWãæêÆÔä)üeÙ㸻»w©.___V½øß¸‰‰ãÆZê0šŒŒ1EQøpýÇ]bíè‰ã7`ÁA¬üûß=rT‡Ó| 4 'ŒgÔˆk)ì`¸*//Ïòõæ-[ñöñ±ô®EÁhº4>Ÿ|Ýd>\¿‹55öŠ^-(°qÈíÀ7‡,Ëjjj-_·~͘ÍfË Ï°ÐP-ü 55uTVUõèë©'……†àïçÇÇM×`´4ó´ÓM쌭³8J‹¢jZÇÐnM%â±Ç–¶?˜Ùþ{ “Úf3–R^c¢ Ühµ¬e1Œxªë¹{J@›:Tèt^Mã_—Н¯/ƒDQfΘNdD`æú)×qëO~‚Žþ–ž\?ˆ€€Æú§\7 /OOÜ4® ˆ¡tS“§ VTôëοüQQ‘ÄÇÅáîæŠÂOo¹™b1™ÍÌš1»¾Øêíìu'P¯o 4$˜à  ÄÆpÃô©¨T* F#cGbÜØ1¸ta†BOßfáa¡èt^Ì™u#Í¥>ƒ¢(¨Ô*F^{-nn®Œ3/O/ „‡…ñàý÷1(n`óÊDö £t4Š¢àëãÃ÷ÿŠÚÚ:"#Âùͯ~EBü KÝQ‘Ä ŒÅh00 6wwæÌšITd5uuúû³àæyøø´C½Å…ù…†ãÒôË^uµ5œ/È#,¢íX³‚ŠØþÑDôë×îöÇ#:*£ÑÈÄñc¹÷Ο£õÒ206°~Í ¾&¤Äa`2£¨¦%Oáwßi ³žx=ýÇ%6&†ë“¯Ãl2ãîæÎœgqMü E!)qÆŽÅ`0; †ïûQQ—NÞ¶þ½m^8<)Ñîa©îôìsÏmr}Si €©©Ø|¯këÏQËðnnw@ èšÊ¸š‹Õ«llÛcV|^È;jðõõA­²ï…Õ8FVÁâqZþxÓÕõÖ©»Éñ횜әÔÕÕ’0t¸Ý—Ž7ß´ÉÝ]Kô€¸n¡cÈq¹K½@þeÜîôöq^<0Õ¯ó•û89¾]Ò/ŠÂ¼ŽìßÕî=Àbcc™7oÐxƒ7ÞxƒuëÖñÀ8¸e?¼±cÇ2dÈ.mk6›Ùµk&LN¥¡¡/­$-=€ßvÆ E__OZz:kÿ÷!Å%%”——Áú½ƒ[}宊oI­V3eÊÞxã ...œ?žììljkk gРAVÛœ;wŽœœT*ýúõ#** EQ0›ÍdddPTT„N§#22’àà`¶lÙÂСC-=ü‹/rèÐ!’’’ðõõ ²²’ƒ2mÚ4 ±÷œ‘‘Aqq1ÁÁÁ$$$ ( %%%œ;wŽøøxÒÒÒP©TŒ9ÒRÏ©S§¨¯¯gàÀWtl233ÑétF²³³qss#))É2Ü´uëVvïÞ§§'ÉÉɨÕjvìØÁ”)SHOO§¬¬ŒAƒñí·ß2mÚ4«‹­vîÜÉu×]wEm¢+Þyÿ«ð~áÙgðòôÀÃÝ¡ƒ[^ç‘<þèŸðöövX{»ËUàZ­EQP©TäääðÞ{ïC]])))Œ1‚ÿøÇ¤¤¤°oß>ŒÉd"55•û￳ÙÌ¿ÿýo*++‰‹‹ãìÙ³œ={–ùóç“••E}}=sæÌàäÉ“|öÙg˜Íf’““HKK#++‹iÓ¦QWWÇ믿@XX;vì $$„{uJEqq17n$%%???"##ÈÉÉáÍ7ß$&&www¶lÙrEÇ%33“C‡áïïOdd$§OŸfÛ¶m<ôÐCh4TªÆsÚ*•ÊòµÑhdãÆdddÐÐЀŸŸcÆŒaûöíÄÄÄ@YY7n”?¸s¹¹lùúkË÷‹o» /OOR~Ëê·ÞÂŒ777 ‹¬Âûè±c„‡Ú{ï6Ø™«2ÀOž²³³­^žžž¨T*¶lÙBqq±ÕþLnn.uuu˜ÍfNŸ>Í-·ÜBNNŽeYVVƒÃmܸq–¶èt:FEVV–ÕþZ†wee%yyy–€,¡ÚFƒ«««UiÞ/`uòÓÝÝþýûsáÂ…Në½æšk¬¾OJJâäÉ“–ïÓÒÒHLLì´!ºŸõ K}óL,³Ùvxû-«^~…ƒ£“HÌUÑ7 ÔÖÖ¢ÑhHLLäöÛoG£ÑX[·n999DGGãÙ4.Ölñ⍤¤ðÚk¯áããÃôéÓ3f ^^^ÜsÏ=lÙ²…+VÃìÙ³‰‰‰! €àà`²³³Ñjµ„††Ddd$™™™àîîn ܲ²²6½xrrrÚ}Nåå常¸àîî~YÇâÚk¯½¬“˜]n™ÀÚµk),,Ä××—³gϲdÉ’.Õ%Ä•˜šœÌ毶`2™H;™ÎÐ!ƒqus¬Ã;ýÔ)V½òw T*S›Þ1;««"À[ÎBiíàÁƒððãV«1™Llß¾Ýòx`` ‹-bþüù¤¦¦²nÝ:‚‚‚,ã»qqq\¸píÛ·³zõjž|òI4 ƒ&++ 777KO{èС¤§§bÕcÕét”••mYV]]Ýfº_K:ƒÁ@UU:]ï»™|ó18yò$þþþ 0à²ÿØÑ"úõã†éÓØ”òk?ü÷ÏÜÛŒyW_¼È¿ßxƒ†¦iµ7LŸF¿ðpG6ýŠ]C(©¬¬DQËl‰ªª*«Ç›‡M<<<?~<ÞÞÞ”••a6›-ùûû3eÊêëë©©©ÇÁ³²²ÈÈȰ„õ°aÃÈÈÈ 33Ó2þ 0pà@vïÞm¹-¥^¯çðáÖà·Å××—€€vìØaõ\zRóq*//·ký¤¤$ÒÒÒHKK#))©GÛ&DGnûÙÏHÚ8ö]\R¹ÜÜ6=ï'žzŠÂÂ"‡å¶ŸýÌ‘MîWE¼#C‡eëÖ­¼úê«‘••eù”“ÉÄsÏ=Gÿþýñ÷÷'//“ÉÄ AƒÈËËcÍš5 4­VKFFƒ ÂÇÇh<XUU…‡‡@cÐ{yy‘““c5åoæÌ™¼ú꫼òÊ+ÄÆÆ’™™ILLL‡cÆŠ¢0þ|Ö¬YCaa!þþþœ9s¦ÓO(²usРAm¦N¶·ÏøøxÖ¯_ϰaÃ9r$~~í¨Fó0Jqq±åœƒŽàââÂ/ï¹›‡þø'êõú¶cÞMÃ&Š¢0ë†,Z¸ðªø´/[Ÿ˜ ´(ª¦u\ àÖT"{léÌžlXIQaѯ„††ZB´5oooQ…ÀÀ@fÏžMpp0ýúõÃÕÕ•¡C‡¢R©0™LDGG3þ|´Z-ÞÞÞÄÄÄ`6›Q©T$&&2sæLË AEQðññ!!!àà`Ëþüüüˆ‰‰±L„Æ“…£GF§Ó¡R©;v¬Õt;EQðôô´bÆák¯½•J…³gÏ&00ˆˆËKŠ¢ ÕjQ«ÕV% K-Û S›ç¯6 www\\\ÇÝÝ•JÅÀÛìS¥R‘ŸŸN§côèÑþœ„èIϼ°‚’ÒR«ðþöØqþïµ× bâøqüòž{˜&tEXtCreation Timevie 09 dic 2022 08:53:46cZKIIDATxœíw|TUÚÇ¿w23™”™É¤÷BKÐ{sQYÀ@ŶȺËGÝ XTTØ×²+«ïê⺀ðU׆¤÷Ž$„Jz/“)ïS23™I£ÅÍùæs?3÷ÜsO¹¹Ïï>Ï9÷Þ@ @ @ èÒ/¤L@àó¥,ìR¯§2„0—OBpQÑU£uÝOêà6@pq¸¼¹ƒÛ:DgÕáKm|ïj= 5îŒßÜÆwwûµIg ÕÕÐ%‡Eæ²îIÁÅájüŽ‹ÉeÝ5»tÔX݉€MÜ-B‚K;10yX\ÅÂqÈ;ÐO—çÀÛZ¶àÒáhØ  ¨J€ Àh]LŸŽûJ´# í ‚«Ø<›È Ï'm˜3bø°¹Hè0 .;f³É\±ÿÀáõsæÎÝduXÄB¢ElÂЮ(´g¸®!‚£(€À#FŒüxú¿JÚ.wL \f¨¼)möŽ;v(š±ƒÍkpB´¢-ApôlžÜº(ÍðáÃÇmúhÝ»fs‡B@p‘ 3ÒfÝ}üøñÝ@  Ç" œÇÀƒ(´'î<%–1‚Aç²ÎláÝ©"¾wßÛ€ãXÆl¢àÎSh…ÌS©.ßm¢` BÖý{íl„Ý ³îƒµïÍÄ2À¯Àb³^8Ïúg ½ÛŽCÏÀHÌÎ:󡺋n¿@ ¸¤˜M¦ò„¾Ió€Ó@OÁ6¦à:ÈèD[±¿»™›0è$Épi«—I&Óa¹X+p\”ÑÎLCGïCp_LbjQ 螘%ÀçÁvÃ`›tÄCp9 Î@ЭQÒb¯Ž‚`[:5¨hÃSØàuIš,.޶êúHGÜyî_vÙ%~/ƒ@ ¸´8>^àI Zy ¹uÙ݃L^B‚n£¸{àÐ-žÁÝœ¥£(ô˜Åo¾ÿ‘ŠÊJfÝ8¥Ré´­ªªš·þñO†̵“'v¨¼Ÿví¡ °éS¯Cãïßjûá£Ç9™i_Wû«‰‰Šdà€d$é—qØó Ù¾k}]å­"2"œ^ñ±]Å–õ(\íÕ=wjÚÑqgÇB$@ê)ÂW[~ ;'‡iS¯Cá"é™YìÞ€Òò ¦tP¶íÜÅCG?v4j7‚pèè1>ûê›VéÉIýxî‰ÇZ‰’'ÒÏd°kÏ>FÆ€¤${úº7a4¸sÞ­*§+äæ²þ“Í­Ò½¼¼¸iÚTn›3«Ãýt™.½›¤3O;º¤õIp÷2 CSS¸ÿ¾{éÓ+¡Õ¶Ž•ënKÚŸZİÁ©ü|ú ùÛÛüœ~†CG1zİ•ž“›Ëg_}CHh0’íé[~ø}s3wΛÓÉövK¦LœÀœY7RS[KzFnÜÌæ/¾Äh4°à®ù—±þ_i·ÝMrR?žxø4 Õµµ¼ü—78q*Oׯ½˜â=½áÌ#]}(é—á»^fjjk)-/ÇÇGE|\ ••|óýV¦Lš@uu 'OŸA«ñgܨ‘ÈåîuæÙl>JHpS&M°§ËårT*o†¤düè|ùí÷ró Ø¹gýû1(¥?` mª˜}Ó Îçæ³ÿÐ9N]]=×NžÈÎÝ{ihlÄd4±aã§„‡†2yÂX{§3²ÈÌ:‹JåMÊ€dÂBBìÛ6þß$%ö%48˜CGc6=rZÇããççCxXáaaôíÝ›ÁSxè±§øâ›ï˜výµD„‡ÐØØÄácÇ)..!::’¡©ƒìáÑö]{0ŒŒ9œ½RSSKêÀb¢"),ºÀÑ'‘{É;j8¾¾¾öºM&‡ž /?Ÿàà@ˆŸŸ¯Ûv^Mb¢£ø9ý KW¬äù§#IϬx™ìœóDGF^LÑ]²ÑÎ BK%=ÅA°áæ‚^^VɆO63vÔÆi_ß¾sù……ö|[~ØÆò%O´*¯®¶ž•yƒ²ò ^xúÉÖoÁ3CS“žÓ™h4õïfÈË+`Ã'›™uó `„¯·ü@vÎynúõõ‘± ¡£Ç8tôƒSúóé¾¢±± € Ÿl&5e“ÇÅl6óÚš·Ùº}—½z¥BÁ¢û0iœE0>þô3ÔþþT×ÔÐÔ¤`ýÆOyý¥h]EÁÃÛüb"#3r;÷ìåLfaaäðüÊÕ\()A’$Ìf3ÃRSYòØÃH’Ķ»9~ò|ø eåå( ®<‘-?nÃ`°ˆäÆÏ>çµ—V T*©¨¬bù««É:{Î^wNÇÒÅãá|uxöñ?±dù‹äœÏcéò•H’Ĺó¹„óôã^ ;ë”0´w‚  477³ô±GYò§‡ ÔpâT:YYNyÌf3kÞý'%¥eÜ1wIýú:mùµ7¹õî…ܾð÷deçƒBѱ¸{ê”køÃ½÷pï]óùtÝZ’úõ㽿½Ž.@‹ŸŸ/Ÿ®[ËsO>ÀÛ¶³uû.† į¼È¿[ˆÁhäïïý‹šº:{¹•U,¼ë^|æ)ú'õ£ªªšïÚÑ©c@~akÞ]Ë…’–þùÞû¯Œ1œƒGràðû>MMzÆū˟aʤ 477³}÷núýoyþ©ÅÄÆDSXTÌîýX»~YgÏqëÌ›ù몗¸iÚõ”UTð÷÷ÞïT[¯A,_òá¡ääæqî|.!ÁA,[²˜Ðàà+Þž. ‚¹‡üµ×c×m}zÇ3tð@† Mëá]p*oëölß½—!©I»á×­J3r8³nšÁ̦‘ÇÑ'yö¥WZµ«½u×–»KÛ±w îºè¨~5i>>\{ÍD’ûrﯠÈÚ/÷u´>j^^–{ÚüýühÒ7q*ý j2Ξå?_‹——å‚–“—çTÖ”IãéÝ+¹³ÒÐ0~ì(R$ó«‰ã(,º€Élb÷¾êtÌ»%Ȉpîž?]@ég2®ÚyÔÖŸ——¥ƒØ+ä  ÅE•ÙU„‡p™ÑXž7NéÛwí :2Âítâ„1£™;;ùsoaÅÒÇQ(œÎȤ²ªú’·ñÂ…B¦##"(¯¬r».À&\úÕÖP*&*’††&L&£‘¼‚Bò ‘$ãÇŒ">ƽk`­×ñœÀh2QYUES“žà@ûq•Éd„‡…`6w¿8·¢²Ê2äæItd$EE<³âe*<ûËI×ßtÔýŽí奭O¹nóôl‡<¿¹ã6V½ùÿùæ;ÆŽNR¿~Îù¾û¨|ˆŽ'û|.5Õ5ö °¦ºÆýOs8Ôe6›[•ivi‹V«¦ ¨ˆ‚ ÄÅD™• @Dh¨ç_pMsÅ¥žòŠ vìÙ‡V«¦_ï^øúú¢RyÓÜÜÌþ•ªõþúå©^µŸ?2™Œ¢âbLF2™ £Ñȹœ\‹wÒÍÎÛç_^M^~Ñ‘‘,[²€§—¯´Ž­¬bõ Ë®h{„‡ÐAòò ÉÍË·/555U^tTsÒnÂd2ñúš ×ë¶›LFL& ìÜ»Ÿs¹yhµj¢"#±Æ–!=#ƒý‡SZZæ´¿Zm¹ÇáØÉS45é1™LÖt5õõõœJ?c÷ZL൛_ÈþC‡9ùs:!ÁAôéßå>Ö74PRZFn^>[wìbñ3ÏÓÔ¤gÁüÛí3cGŽÄ`0°æÝµ465ÑÐØÈÁ#Ǻ\§\.§R"UU5üó߸P\̦Ͽ¤¡±‘QÆt¹ÜËEö¹âbY¶d1:­V˲%‹Iˆ‹%;çüoÏE¼ ±›IíeæÉe+œÖïœ7‡T딟O—/Ϯì§±{ï>²ÏçòÁ‡Ÿ°àÎÛì9WþÏ›Nõ©Õj]ôd2‰^ñ±¤$'qâçtžxv2™Œ  ë ¥ŽÔ”d‚ƒ9pè·/ü=\ø¦LÏ”Éxïƒõ<õü „ó÷×^áæé¿æð±œü9{Â^߃¿[ˆR©ðÐ/OýnÉóý¶í|¿m»=U£ÑðÈ¢ß3aì({ž;çÝBNn.?íÜÍŽÝ–0Êd2ñÆ+/ár]]/÷Çø¾»çóÜÊU|þõ·|þõ·ÄÇF³àÎÛÝ´õê²ùßï9¬YÚ¦ÓjXýÂsNiWŠ. B÷:¬—©S®¡¢ªu,—œØ.€¹³Óˆ‰ŠÄ ­Öú'%2wvqñ±˜ cÆÐ;!µZÌË‹‡ÝÇî}‘$‰Æ&=CRâë0_®T* aHê@|T*K¹’ÄÒŰsÏ>êêê”Ò£ÉÌÞ‘+˜__V½¸ŒÝ{öÓÔ¬§w¯xÌÀÓ®'!.–̳Ùê´M&”ÞJ–/}œÃÇNŸ_€N§#5%FcïÇ-7߈L&³¯1wv q±­Î…ÈÈpæÎN³¯«ýüˆ‰¦w¯ø–>XÑj5¬\¶”#ÇOŸ_ˆF£&!>–ˆð0§ã¥Ñ¨12//æÎNC£VÛˉ‹‰aîì4$%b¢££xmår;NiYQá ”‚\.ï1çmWq7GéøÜ‚í…(*,/\P[—Ñ™§O®¾R£Oâ€G€=XÞ¾\Ô8¿J­•{'1† ìˆY@`G * ;b A ØcÀŽCv„ ;bPQ عˆAE! Á"dvºì!äŸÏ¾”íÝ€. ¨ S.e;A7@„ ÀŽ@`G‚@ °#A Ø‚ ìAv„ ;B!ÀŽ@`ç"Þ˜ôËgÞ "LLòoµm[z-zƒ™IIþlÜ_ÉŒÁZ4>mëçáœzjLnËkâj'óÉ*nBí-£_„7ƒc}‘$ø×Ž * ÷½k\ yåÍœÈk`Þh]«>ªU^̬qJ?‘×è6?À¦UÄ+ïÓé~~Ùôh!»TϪ¯KÜn{åËbªd—èyzSûÏÖµ[Þ;[+œÊ{G‡Î5´¹Þ`æµoJ˜öjïýTFv±žm§ëxà_¼úU15MFjLÔ4˜Øu¦Ž÷VÙ×kLMp"¯u»+Ê^óC)o~WƸֆí.¿Mû+9˜]ßnÿ}ôhaú ïn+'¿¢™(ž~¾¬™¬b=× Ð ñ‘±û龫Û?T«oÀàðëè_«B)‡¡m\i—v¬â&¾|´aZ…Ó¶ÆfË´þqJ°=ííËø)½–§n k³-Ÿ®æíËØ°(žH¢Í¼-©±>Dé|²–»Æ·¸Îßž¨f|??4>2 F3ëöTpÏø {ÈPPÑÌO§k©o2“éÍ8|•2œk ¡ÉÈu)>;\EA¥NÕR\c`ú }¼ê?v¾ÏUñõŸ[‹€JÑ5nïÙzžÞXÈš1ô ÷n‡PYodûé:Êk ÷a`L‹ÈíȨ#Ä_ŽÞ`âโÕr®IV㣔ؕQÇé¢&z‡(™œìJ5èMlK¯£°²™Áq*†Äµü¦åG{+˜žªåHng šè¦dB¢?’õÇ›šMì8SGv©JÆ5ÉjB4Χó™¢&öfÖã«’¸n€†M*¹gB`‡êï©ôhA‹—°åDµ³ ¯å¶1èfÞø¶”´¡h|dį̀cÑÚ\&%© ò÷âëã5¬˜Nß0ovž®£¤ÆÀu)$ëÏfÊdr™äö•s;2ê–àëV ºJæ…&­Íã…9‘ŒêuiNðSùÜ÷^©±*|2^ýª„ßNâÁë-žËÎÓul^öïaZ}¼ñòj)gB¢F“™ U±Ùq¦µŒMªØt Š#9 (½à\©Þ¾Ox@Ëõ*!Dɸ¾~ì³vÚš˜W®çHNqÁ ­eïɪ'>Xi€„P¥Sß=ÕßÓéñÀôT-[NÔ2s˜–oW3k„ÖcÞ‡¦†à-—xò“BLF3óÇrÿµAxw!ÞïªäÓCUNi¶Á UÍ|´Ïý,€'$ V̉`þšx?ÿ]ƒÜñ2êBˆZ΃ׅ´Jß—ÙbèåÍ(åjŒ RPZãy*ÔÏ[æô^_¥e³5”ªn°ÌœäU´À‚IAN"àJD€‚ò:K»2ëx~s B•U6`ñ¶ +›ÛöTOG0c°š[ßÌ¡¸ÚÀ‘óõ¼qw´Ç¼þÞ2þ4=”‡®aGFK7á­¸ÿÚλšýXõU1[®m5àÖU”r‰·îŽfÖëçXþxvfÛ¡M{©åè fJk NFVZk`B¢_—Ë TåÍÂNaiáÖq‘G×ðÜÌp®h þçërÊ,Ƭ–SP®÷XNWëï ôø )BE¸VβO‹Û×u1»ÉzÕSÈ%®IögLo_ *šÝæõ–Ë(¬ô|MŽTqËHO~RÈA—ûjõ]Í}°ZΚ{¢Ùt ŠvVt¹°\•ゼ»­Üž–q¡‰“y Œï×uA˜š¢æƒÔ4ym~„‰‰þŽE9õÛFJ”ÊéÞÉá8*å3‡iéâMÞD¨ZÎü±:t~–Sòý•üîš`ÆôñCá%±`b iÃ[Æv¦¦¨‰Ô)QÈaê ¿„ÖWnŒ‘½|ÓǃúG«˜Ò_Í¡ìzîg™vl¯þ_:+^xá Ð[—fÀ˜¬‹[Ô݈“£Ø„@øjë2º¾®võ¥í•'·¬í8SpõøÃ?ó¹q¨†éƒÚŸ>ퟮfgf/͉h3Ÿ$At ²Í<¿|ýüö5Ö¥hÄY̸Cþ¾µ¼ýL‚«Bq­méµä–»Ÿi³ÙŒäàýpª†¸`e»ÿs•BbI;·…ÿ7Ó£aùì‹\>Næ5’6LË­#º´ÿ³›‹È)Õ“¡âhn=ý¼ygA ¹çiXAA÷eóCñµÿÅN·öTÄ´£@ °#A Ø‚ ìtV̸™ªÝŽ.Ùj{‚`vùtMÝO6Û¦ívÄCp,¨Í»œA·Á½¶k·  7Z@Ð}±Ùi§.âžîC0»YœÁ×ÏÿaÀPb¹½YŽE`l"#î.6·Ù¥ËmÉz ÷‚ິ¢#7&9Š­ÒCXžmðÁòœƒÒZ–B‚+£ ±Ø¦Ëó Xž]èÐMޏ3-ÆìèØ*mšh1|“5Í˺H1®6û´y6Ûl´~ÚÁæ)¸z­¢-Á]¨`3|›ÁÛÒ´xB‚+ƒëÛ2Ø<ÛcÏîB·t&d0`1x½CºÍc°y6AWGA°‰‚£0p~ܹMÚG—D²VΊä8˜èør@pyq7èo€f‡O›X´{£R{!ÖJ eªÑ1f±yB ‚«ƒ§™@ÛØ§Ù·t4d°‰€kÌ"Ä@ ¸ú¸GqhWl´eÀ’›OGãw'B‚+㈎ÂàúÝ5o+Ú3`É廫ñ»zB‚+ëT¢£7àîF$žBG Ø5'o@ˆ@põèèÃLm† 1bOy…ÝOß¡gºjÌB‚îx*Y @ ÁeáÿVâv\hïIEND®B`‚././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gtk4/controls/images/spinbutton.png0000664000000000000000000001665715074674453024237 0ustar00rootroot‰PNG  IHDR5d级âsBIT|dˆtEXtSoftwaregnome-screenshotï¿>&tEXtCreation Timevie 09 dic 2022 09:12:29NôgMIDATxœíy\”ÕþÇß3à ˆlŠˆ¢€šænaV^Bͼ޼™eú³›–z»Öµ¬4MëfÛ­_×[?ÛÜ×(Ê}Ã}7\@öMT@Ù™ùý1Ì03ÌÀ3¢tÞ¼ž×Ìsžs¾ç|Ïú€@ @ @ ‚?,’Ħ@ h¾¨­iÌdΆ7@PæÄ¬Q"×Pá1N'±ðš@ ‹–ÚÂkQ_Á1%^’ZÞ74@Ð<1%`êZÞ›JW+õc±’èR£ssâ&Ʀ¨ŒÎã׉¥‚cJÈ´bfêÂ&LaJÐTfcÁÓOo; aÎ3“é½Ê€Ö€;à ØWÙ¢&ôѧ  (r[@eÕ¡Ò{ÕO+¡a«KÔŒMë‰i…Ìh øoÚ°nBPÿ~‘àŠZˆ˜@ ° jµJ}ë䩨µ&NÜ \î¢< Õ¦·:…­.ñ1nnê‹™h¼qÝš/%\|càn‡GŒŸw¸ ”£7­÷fª9ZƒÚDMßKÓzhvU‡pîß¿ÿ-ÖüŸZmQ3V jE‚¤bTĸ)ñññGB  °U`Ø×f„­.Q3å¡)Ðô™õ¼~íò:š@ °&’[;LâÑô¹i…Í”ÇV©9«FïµÂ¦mvz¬Yýýx„  «£výéûUcÑ <ÊÑèŽ Ã`Æ)«k‰“~³SŽÆCS]’®]^/×F—_ ŒP«T7ýºþHŠÑxlÚ>6ãjë 35â©7W‰DÝʺËP@ƒD*uEã4É10RǨ¥óÔŒEÍ•˜¶!l…Z8bØüÔNì¯K<5cQ³ÂI6FAµæè‹šö¨×@sMP™UŠ,æÑ×ã%˜f1å©™Ú:ÈXؤVÞ×M ŒÑ_ŽiNÐjxl–,“2µx]&4M Ø}A3µQ†Ỉš©ù úÂ& ¬Ä;Eœ=Ovî •J:øøÐ%Щ´®ž +WýR Ó§üÕ¢øé™™D9¦;w°wÀË˃~½z¢P(t÷šòòr6Gþª;—Je´õòÄ×LJ¾>MX2•1ÖSšT¯)ú‰õH‰pÔÏ‘ã'ù÷Êo)**2aò$ÂGý©ÎôwïÞå÷Ý{˜í¸xé2o/YÎâó‘H$¼³äC’’SðñönŒééL}E­:á¨5Š–Ž-8{†ßvîaè A´léh'!á «V¯cïÁC$§¦ ‘H˜úì$ÂG> ÀÆm‘Èå ÆŽ©;wjÙ’‚ÂBJKËX»yŸ/[‚‹‹³É]ßÏÆŸG*•2$8ÔPRZƺM[éЙá¡ZQ‹#ò÷øùúâÓ¢´¢–‘ÁºM[‘I¥¤¤¦‘RUÎí»÷"•Jyf¬FÔ~ßµ‡o\CEE….ûQO ç¥ç5}%þüÖlÜLî<d2 çÏ£Wgfçz…\AĨ|½ê®\exèPÊÊËYüáÇÄŸ¿ˆD"A­VãááÆG‹Þ¥•‹3 WX³a û!#+KgkØÐbââ¸u;€×mdÙ{oãçë‹Z­æ³¯W²?úˆ^Þrþ6ý2ØÔÇݬy÷¿óÖûœ’ÆÛï/G"‘p=%Oww¾1ÏZQ/qþyÑ5ПÞ={PZZÆÊU?0eæ+|ôù—¤¦gÔˆëîîÆ.åõÙ/#·³ã§õu?6Sܺϴç&óÁ; x¨k ùùì9xÈ Î¯;vóÌ”iL˜2{öáÚª•ÅýPíÚ¶åË—0°_¶­ùž áÌ›õ2!ƒ4žæ'˳å§U€fpâ›VãÞº5Ëß[Èûo½‰›«+Q;wwþ‚Îniiƒ‚ûó¯÷ßáÉaaTVVµÃ¢2iéàÛ^—'À–È(âÏ_dBD8k¾ýšç&N 77-¿D¤óôpcù{ yñ9Mó{ÏÁhF=ù8.z‡Aý)--Óy§{D³?úýz÷ä‹>`ÖŒiTTVòŸU?Rx÷n½ÊÛpkÝš÷ßz“¶mžîî÷¼< 5µøkÔŸD*aáüy¼1wþ¨¬¬äð±¼:ÑGéâ „7ƒ3x`0eåå\¾zMw]ÿóP*• J×.ŒñYYÙñ:û1.|cÇŒ¤ßÞäݼÉܾMÁB0a×Ð9ªQ×ø.P#üØÉÓTVV26|$èþPÆGŒàLü9ëÃC‡Ò¹“Ï>3€Œì,“õgî{(•iæ…·lÙ5jbãâÍàÂÏQ¿Wݤ¤¥Ø êß—À€NŒñ¸î‡øxØPüýxú©ÑUeÑÔá¡ã'xṿàÓ®-=úƒ‚ûQTTÄ•ªÏåö'“Ù¡WžËíäÈåòFÙl(ÂSkB$ ú÷cù¢…|µb9C¡R©Øe6MOM¿ÍíBóžš>®­4}iÚþ2-þ™8>‚IOeÁß_£K€?Å%%Ä»`ÊL£ÈÎÉÀCÏlçÝ€›·n›Lãää„T*¥²¢ÒäusdTyhí½ÛèF–³²³IËÈäÆÍ[<2h@Í&­®U*µÑyUfg×¼ï¶U÷S‹Ý\¹u;_ÓüLMÃÇÛoo2²²xgɇµ¶(lEÃw¬}jV¥­—“Ÿ™Àác'É/(4û$ÄkIÉxºyXöXsqŒ¶Ø èäG•«š¼«º0 ÍÛ©:W«Õ¦¿ ªêp—ªAŠÌÌlúô|€«×’ðöò¬µ\µÞ›Ñ{•JÅ/Ûw"‘HêÛÔàååEjz&#†=Fïž=jÚ1õ´IãëFù¹¸8‘‘•EFf6ÚûÜO[OOÓõÑŒYüá ÒÒ3ðñöfÑ[óXøþrÒ22X¼ücV,]tOË#<µ&"3+‡%ÊÎ}û9wñ§cϲjõZºÄý}÷^’RR‰‹'þüœœœèÐÙ”Y‹Q¡F¥RQQQÁ¥Ë—9~:©TJ·.8µhÒÁ̬>Ê嫉\H¸lÞÙÉ €+×’ÈÏ/¤²Ê‹q© ?{–òòrzv€Í¿DqáÒe’®'³g4R©” ~}|åäÞÈ#3+‡Ó±gy{É2“’y<ôQºø08¨?߯]Oîùê?€Æ“Ô·ãÔ²Á}{s"æ /¼ò*C‡ âÕÿ™ÆÐ!ƒØ¾gk6nfÝæ­|µb=ºuä'øeûN,^ €T*eʤgèX•_Ý.SÍó´ô ¦¿:O*“ɘ06œ OÖÅ LÜù ì?t„é¯ÎC.—S^^ÎÿL}Ž'‡‡Õ«Î´aOAlÜ9Î_¼Äì¼ hšË³gLC¡›°Ó¼Ùºz•Þ™æÞ]]œY±ô=ƒ°{EƒEíõ±YŸ!éÝ«ç/&{#©D‚·7÷è†T*5¨ß©Ïþ{{•ôìÑï6mtן~jŒA|ãs777&ŽÀ¯ƒ/jÀÛ» ÇGèlˤRÜÝZÓ½[W<ÜÝté&==–.IKË cG_:ùùûN¼½«óþÇœY=q’Ü7éXe?À¿Ÿ,[Ll\<ö { {ÔÀÔ¿N"dÈ@._¹†B!§[×@Úµm«³2hýüpvvÒ…M÷JGeïš\npö >ÞÞtöë€kÕ*]‰„Ù3_âOO ãZÒu@M§éàÛ5Ð%П‰ã#èì§K3Œƒƒ¦ìJ%ÇGà…½‚÷ß~ƒØ¸s¤§gàêêJ¯Ýpvv¿‹ûSó?ô×yj7…t@³a›SÕ1ðjÂù÷ªT"£¶óÝšõÌš1°¡Cšº8Á=Å¿K÷¹À14O•*Š€ ·õ®áÚ‹‚QßEˆ>µûšÚú™)ÄCˆïcÂGŽ |䈦.†@ð@! A³Bô© ‚f…èSÍ ±¢@ 4+„¨ ‚f…(ÍŠF Y÷¢ù)š öÔÒS’¬Y@ ° µ!ÃHHÍçTR!9ù”WŠ&éýˆ\&ÁÃIF°¿ >Îu'`µLjo\±É%8·rÅ­‰äþzr^iI1öʦ.дeQ«Õ—”ðëÙ[ô¹YBXOËX,<ˆ4XÔRó‰M.Á³M[tv$ÀSŽ£âþµü[¸¸ÞžIS–¥¨LÍålN$Ú“œ‰[!휚¤,­ið@Á©¤Bœ[¹ÜII/Å}'h‚jz··'¸“çV®œ¸úÇ{8ˆàCƒE-'¿{%žrk–G`C½Ø;(É-¬¨;²@ð€Ò`Q+¯T#‘Hp´³B$ eb@GÐ|Š$šBÔA³Â&¢6{îßmaV êDlç-¨•JEzr"¹9Y”—•Z”F¡°Çݳ í:tB*Kõl=„¨=@ ÿÓ(vÿuÏòLON¤¸¸ˆ~‡â ´lòpIq—Î!=9‘ö~þ6.aó@Ô³õ°©¼ÅçŸNLLŒ-³؈9YtéÞË ґ®=zs#'Ëäõ}¢Y»a“Ék1gβï@tƒÊjK²srˆüÕvÿLlUÏÇOœ4ËÊÎfã–mìÚ³»EEºðã'N²e[¤I;IÉɬ۸¹Îò¤¦¥|®–ÔYdÔo\¾r¥NÛõÁf¢–››Ë#<¢E‹8~ü8¡¡¡,]ºÔVÙ lDYY)JÇz§sP:Rf¦µ÷À~>ûò+víÙWãZÌ™3ì=°¿ÞùÙš±ìãO¸sçŽMìÛªžž8¡;Oº~)Ófp-1‘˜³gÉϯž„]^Qο>ûœü‚‚v¶Fþ•«Wë,Kjj*k7lÔ[Rg‘Q¿qé²uEÍfÍÏ×_???6mÚ„D"!::š°°0ÂÃÃéÑ£‡­²< ôìÑOÿý%ƒÓ¢E‹¦.N<=.‚áÃÂhÙ²eS¥ÁìÚ³~}{óÆßçÖ¸6 (¥RÉá£Çùä×<Äüysê_SÕ™M<µòòrÖ¯_Ï‚ t‹ÜCBB eåÊ•¶ÈRð€1hàz>ܯ¿ù¶ÖxkÖo #3Swž——ǪÒ?uš«×¹xéë6nfמ}• R©8~â$kÖoàÈÑc5ì–””°wÿAÖnØDüùó×~þõWòòò8w޵ë7’–žAzF&;ví1ˆwçÎöìÛÏÆÍ[¹˜€J¥jHUÜ9©˜RÓ2øæ»ïk45år9¡!p ú°AøÅ„îÔ¯/·oßfûîÝü¸v;w若¬Ìlž¦ê¬´´”}¢Y³~qñç¬tw†ØDÔ ‘ÉdôíÛ× ü±ÇãÜ9Û܈àÁcîìYü¾s7—.›³zÝÒõD-÷FßýP-j'Nœäosæññçÿ&-=oV}ÇÌW_e櫯±iÛϤ¦gðÎ’¥¬øâߺ4yyyL>“Ýûö’“Ío¿Ëÿýð£îú¶È(Þzo1‹>XÆ™øs”••ÖhZ%%§0ùÅ—ømç.®$&òÎâ%¤¤¥Y«j¬ŽT"‰fE‰L&C*«ùÓÊñ“')-­nÎî?MXÈ#ÈårÊËËy~úLŒ&11‰Ï¾üŠf̤̌°×Y~~>/Îü?­[GJZ:ï-]ÆÅK V¿W›4?KJJðòòªÞ¦MRSSm‘e£¹}ûvƒÒµjÕÊÊ%©å¬ïõ{9*j <ÜÝ™>õy–ü ß~ýeƒ§%ôèþ°€Ü7z"óç¾FDøúôìÉ»K–òÊŒé( ¾þï·t àÝ·ÿ Àا™Äk³^4ÞÜ–u«uuRPXÈèq8Ëàê,Ãw?­ÆÓÃ}°©TÊÝâb&?ÿ¢•î°›xj*•ŠÊÊÊár¹;;1‹DPÍÓã"P£fËÏ¿4؆S‹ê>wwü:vD¦÷=Ü•JEÉÚ¢e ¢¶ï jûο€\.#5-]—f`p°Y‘-(,äTL,c«D³¹`ggGhH£oôæ­[ô×kqI¥RT*IÉ)$&^Ç»Mrrr,²øè1"ÆŒÖÕk ¥7·ÖÖ¿«[”J%ÙÙÙ¨Õjƒ#³³³ñññ±E–ÆWC1çq5Å<5[#•JycÞ\fÏ{°GC¬bÓÑQ‰ZïÁ@J úYA…wîp÷Î]2³ª§BüeâD<==,²Ÿž‘L&ÃÅùþثϚ ,Œ…‹—ð¦JÅþƒ }t¨#²výF¶DþL€¿?^^^—”Xl;;'·ÖÖ1cl"j-[¶¤¼¼œ£G2xð`]øáÇéÕ«—-²<ÀtíȈ'ç³/¿Â·}{Ë %Å–ÿp,¡m›6úóìÄg”¾e‹–TVVrûöíû꟡5èß·gãÏq ú3§¿¤»–œšÊÿ~ó-[Ö®ÆÝÝ € /Zl»µ«+™YYt¨›u m„MšŸööö„‡‡³dÉ݈P\\Û·ogÆŒ¶ÈRð€3cÚ‹Äž‰ãäéÓá^žž?Y=´¨¸¸Ñy… aã–­“OëCÛ6^´vue› 'ã62™Œ°¡!lؼ™Ì¬lú÷é­»vãF { ™åPP 7M"1Ùí¤¥ŸÞlز•Š Í~~eees嬅Í:¸>ùä†΀èÙ³'‘‘‘,_¾œ€€[e)x€i¡T2wö,Þ\ø Ó…O|z‹?XNIq) œŒmt^ÏNšÈ騦L›Î°ÐPÊ*ÊIJJæÓ–Y”ÞÎÎŽ¹³_aÑ˹–˜ˆ‡»§ccy÷­âסC£Ë×Ô ,ŒWæÌ#bÌhd2™.ü¡®]híêÊô—gѯoÎÆÇsóæMÝõîu#¿ €/¾úšñcŸªa÷Å©S˜9{S§Ï¤wïžÄÅŸ£ðÎ]«—ßf¢Ö¡CN:Å®]»ÈÎÎfΜ9bÒíˆBaOIqQ½g»—¡PØ›¼öØ£¡¸šh¶…=¼ٳpww×…=9|íÛy»›ó^›Í柫çXQRlèq…I×ÀêžvvvL›:E×ÖB©ä?û”ã'O’x=GÆŽ©îôe }ûöLzf‚î|øcaøûwætL,eeå¼ú·—éèëkIÕ˜ÄVõì¨tÐQjAXßÞ½˜þÂó„5ìãT*•|ÿ߯ٽo?••Œçv~ŽUK»\œùnå×ÄÄžA*•Ö¨³6^^üðÍJ=JaA!ãÂÇwóÎNÖœkêÁ’ªCŠFôä€à8Uß]¿¢­/Ó‡Öì,=÷ï|¾â_V-hCÈ¿uWÛwLZ‚5Êb‚• ÈLKá~ÅO¾v™’’bºöèmñN»ÐÚÁÁ‘…gn ¢žkâØ¢å\àPXu%@9P¨uÕ¡C̯x€hŠQO¯v¾d¥'s,ÚìCc {\Ý=ðj×¾îÈ@Ô³5¢&¨¼ÛûáÑÆµ…6H4s …m ׌õl=l"j÷CÓS`= …øáÜD=[±]¦@ hVQÍŠ‹š\&A­VST&ž!ù p·T…Z­B!35è-4ê+jÚáSµ‡“ŒÒ’.g›ßOIpq%§‚Ò’<œeuGš5&¦lÔE]¢¦6zÕ…û»PXp‹‰ÅœI-Û}LQ™š3©¥œH¼KÁí[û7¯õŠ‚fK Ý1n€%£Ÿú†TU‡:ÐÇ™>7KˆIÎä`‰+Ç•;rÜ”–”cïPsÏõ¦ )Ë¢V«)-)¦àö-úvt$ S“”C ¨'š£V+–NéÐ7^YuÖÓ·BN\Í''+òJá­ÝÈe&tEXtCreation Timevie 09 dic 2022 09:22:14\È2ãôIDATxœíytÕ¨¿ªêM½iG ’e[Æ6xlj!dx™³:^Ø^€†7ä?’ylð`ÂdÂ#¶@H!C!aŒ±Ûò¾ÈX–µï­Þ»«êýÑj¹ÕjI-©ÛS²îÇ)zqõ½·Uõõïnu @ @ “ i‚¤)LôL&– ‘†JCH*˜, %å¸d«@ÉŸ“Òü7àT"Y>=ÍK‹ÑŠ“JBi˜çcÍG 0:©DÔ‡yžêsÃ2i’¥“69éõP’ §É"&nZÒëäýG$]qR —2Õ&œê¤SbK7ñóCbJ£CEJ%áQ €"À XûÒr NU%‹!À´]€Ú·i ‰Ÿ•AБäL3ãBš'0ãÍ_½vÍÒ%‹× ‘.dL2$t]Ó»>ߺýÕkÖ¬ù5pðWâ„ qIGt$‰’«±‰Rš‚¥K—.{ãµWž“$rÇüÅ‚Sº/[}Õ555Û€N BLÒx4MUÍÄpr&FÍxÄ4õmÀ½dÉ’óÞúÕ+?×õ´ªÇÁ¤ABŠ~cõ•7íÚµk3Ð „‰ e`[†t$9SEL ±6åü£µ_1‚ÔH]S«Ïø°‹X›4.hª:y¨T“žÇWg‹_yù¥«b NTU% ðyñy=ôzzèõôàóöðy …‚hš:ÊTõü_¾ôâÄ:JÍÄüQ8’CÉ‘¦Þ%VgÍÄ"f0ëËÚƒ¯K?ÊÒ †"‰ÑôôÄ“e«Õ†ÉlIk]Ó:§1û›À @,‚ÆÛ ÉD®­˜ª‡6.i¾$éy™æ+œ<4M% Ž.jšF àG…ȱۑå¡*Ÿ1$YÎ'ÄÌ ì’¡Ç6ÝqÎd9íhb¸D01‰FUBA?š®¼óhšŠßë%Çžƒ¢˜‡ÙS—;«µñ‰:Ã’NäL–ÓXDÐLDT5J àËHZ::~¿Ÿœ'ŠInW 'ÜI”3¾ªC(ÎPUÛaK"]ÓüO7ð¡kÃFáDo’§¸IªÈ™ê’¯dAå _W*d`Цgþ¼ÕÑ ýäØCí’8Ýu(1EÐt¦ï¥šä®7‰h4‚:ÊΟѠFU¢‘(&SJ¥ÅLuaHJ†’3Õ8L¢ “ª3Èëõ³s÷.ZÚÚ±çäPUQÁ¬™3Fì©KÅŸ>ü+ÛvÔp×m߯år©m*óæœ Àî}ûÙ½w?+W,ãøñFÚ::ñù|´µwòù;ؾc>ŸŸ‹¿rE…@ìĨٵ‡ŽŽN¦L©dfõ4ìv{ùÚÚ;غ}²,sÎ’Åäæº‡ü.G¥%%”–”pFu5 çÍåÞ\Çïÿø—^r1e¥%ƒ!¶×좵µŠŠrÎ^0IŠîŸl!UY±l ŸnÛFo¯—óæRyz9MÍ-ìܽ“bâÜåK”SÓ4¶ïÜÍñ†ŠŠ X8o‡=e9³¦¦×Ö¬(/ãÀáZ[ÿ,ëÖÞ ’Ä?ÿË©«?Nyiišy¥ŒÐcòe´ržÈäÔœ8ûzß¶nßÁÞÿ3¬XÓyâ¤ÊɱñÚ›¿¡¬´„•çÄä|÷½÷ùð¿>æ¬Ù3™wÖ:~ÿŸâÓ­Ûøúª¯òѦÍlýbç-[Êá#_²µOÎ/vÖðÅÎÎ=‹¢‚ö<ÈþåYº{<ýùÝwçí\¸ò<<½^îºÿ»„Ãa^yã-žùÁcƒbõšÊòrV,[ʦ-Ÿrðp-e%%olä‘'ÖÓÒÖ†$IèºÎâ ø?ÿx’$ñѦÍìÚ³—_¾þ&˜Íf.þÊüé/FøõÛï°áa±XèêîáÑ'×S{ähÞ…ùù<ôàýLR9Æ#3:4-½“õÁ{ïâ±§6PßÐÈcëŸE’àØñFŠ xðÞ;ÓJC×µáÜ•¤£ïјDÌž9ƒ…óç …yáÅ_pÓÿÀžyŽú†FJŠ‹©ª¬ ©¹…ž>‰vîÞ‹$Iì?x˜@0ÀÞ©ž6ü¼× |ý¢¯rÇ-ÿ€[n¼žß¾ò³gÎ$²áùŸáéõr÷ÿº•]ÿC¾»ö-\ÐÿYI’¸åÆëyü{ë˜uF5==>Üøñ¨¾_Uåé445ðüÏ_¢¥­‡þ÷Z~ñÂsœ³t ÛvîdëöýŸ …¬\±œ'ý>]x>‘H„›7sïwnã‘u2¥²‚¦æV6¾€—^}Ú#G¹öŠËyî©pÙ¥—ÐÑÕÅO_üŨÊ:.Òœ TŸÇºûï¥ô´bêcb°îþ{úk3#f5ŽYGÉŒYN}ü'Éß{ð~¾»önfÎ˜ŽªªlÚò÷>¸Ž›· £³lÉÙì;tˆãMttv²ê‚óÐ4šÝ{9ÖЈÇãaéÙ Ð~Rãy¤ú›©«£©¹…s–žÍª WRZzË—œËéèÿŒËéà’Uræì3¸ô’‹hjiôN¤=ø˜)J¬ãÂép ‡Ø»ÿ .§“CGŽðî{ï£(±úºãǤuÑ…+©ž>5W® /7•ç.gîœ3YuA,²75· é›?ÛJA~>ß¼z5åe¥Ütý7ÉÏËcÿÁC'ñH¦I1a6Ÿ˜Žg2›0›†›ž7i¹DDÎ$‰åKóÄÃßã'ëŸà¼s–¢io½ý.Ë–,`ÿƒÔìÞ‹Ýnçºk¯F–evìÚ;ýX²haÚy6·´pZQQZûÇ#²žfõ-NcS•§—„Ð4¨ªr¼±‰ãMH’ÌÊË™Z™ºú™—×W…ÖßË@Õ4º{z…Âô·[eY¦´¤= “†"ž÷Ht{<<úÔÓÔ74R^ZJyi)Í-­<¾þYº=ž‘E^é0ö &A›3™²’n¸ö6mùœO/èP]5•‚ü|öT¾.‡Y–inmES5dYFUUŽÖÕÇ¢öI:‡$IFgäN¡=ó¯445S^Zʺîà±'Ÿ¡±¹™nø ?ôÝ´òÊÔ÷‘sšš[yì©§yÿ/e÷¾ýlÛ¾“_~€3gžÄ~)—-^Dí—GÙ½og/˜ÀòÅ‹hniåómÛYºhῨ.—€š={ …ÂhšFõ´*l6+[·ïä£O6Ùè^ߨç…úÚÚ;¨?ÞÀ_?þ„¿ÿ¡P˜›¯¿®¿gõÜeˈF£<ÿó—†B‚A¶í¨sž&“‰³fÏ¢§§—ÿ÷òk´´¶òÖ;  ²|ñ¢1§;Z”ÁãŽ)9z¬žªÊ Ö=pyn7yn7븇ªÊ êê§——’9¥Æ±öÏ©:ÕÖòÅŽšþÕ8S**¸å¦ëˆÿ –-^Ä{|H4eÑü¹€ÎÒÅ xéÕ× ƒ,>{ƒÃ\,ô,˜{&E…lýb×Ýúî¼õÛ\táJn½ñzžÿù/xú¹Ÿöç{×mßæâ¯\P’tBgìõŸ?ÚÈŸ?ÚØÿ®Ûífí]ßéŠíó÷ß¼šºúzþkÓf>Þü)yöGSQ^6¨ìé,n~ûM×óŸxŠwÞ{ŸwÞ{€©S*¸ùï¯ãdC&“B$2r^/¿ðl«Øþyn?ôà€÷†CV”´öK‡1Ëyê« çŸw ÌeϾ´µw KååÌ›{&²,÷ÿ æž5›5W­Æn³QP”—•qã·®%3Ιýûž¿bÕÓ¦áv»Ð»§þùa6oùœP$Lõô©èÀª ÏçÌY³Ø³o½>奥œ½`:põå‡I91½¹ä´bÖ\µšê©UƒŽKyy)k®ZÝÿÚåp0¥²‚êéSɱÙìŸ›ëæ‰‡bÇ®Ý444áv»˜6u e¥%è)Ê.+ k®ZÛåêO§ª²’5W­fÎìYè@EÅélxâQ¶×좽£‹ÓËJY8.&“éäC²Œ$Ë#]9’l”çÅxIU×JœG¿¸ÚFì‚QWßvÎá{Ög¨ AÖQÕ(ᾡ­la±ÙP”ÁñnƬ9k-ÄVáëü@Ë• ZèKt &ŠlB’ôQ/Ò•²¬ È¦Œz!Úœ‚IƒÕj% daGÂlµi'Do­`Ò If‹mäG‰ÕfC–2¯’èL*dEÆb³ …ǵÀ€„„Åju6e¨|‰ˆ6§`Ò!K ‹H$ˆ:Æ\YV°X¬±ñë,¹ Úœ‚I‰$ƒÅjCUU¢‘HÚQT–dÌfsßx&dÓq"Á¤FQEAï›W¬ièzÿÕ%’$ƒ$¡(r_ïÉ»”YÈ)’,cÚPÙDt eBBO ›+Ž ‚~Æ9Ž}™Ér‚$Æ,çòó/Êd9A¢Z+!§@`P„œAr EÈ)!§@`P„œAr EÈ)!§@`P„œAr EÈ)!§@`P„œAr EÈ)!§@`P„œAr EÈ)!§@`P„œA™°72êé½PЮëY¸•ø`$IŽÝ•ʤ`w¸pç`·;²žïDeÓ!ÿ±±…íµÝxaBápì.^YF’$ÌŠBU‰“Û¾VÉÕË ³žg6˜prz:;èìlGFpåPZ^ÅjÃl1 G‡‚x<Ýôvub²Xq¸\‘W×u4UCU£~<]˜ÌfN+«Àév;ýS…w¶wñÈ›Gèò†°ÛÝØÅäåZP3RîäUî ãïj¤Óä’…§qѼ"*‹í”æYhîQßæçƒ]í<ý»C¼ü—:®XQÉ;ï“Iª› J}›LL^3`쀫o;Çïó®?Y…PU•æãuý~JÊ+É+,ŠÝUxt]§»£æÆãØN,6[F#¬®ë„ƒ|^/v‡“Ó«¦!ì6r'“@DcÍ3ûÙW×Mna vWÁˆÇh4(’D…¥™Ú†.š«W”£Œp¿LUÓyã“Fžzû0³Nw³áæÙ¸mʰŸÉ4v‡s-°èíÛü@ˆQ@#vã¾'ç„3ÑxìKÌ+•UÕ wNUU©?Z‹âp:3~ûB]×éíéFªªg¢˜&\…dÜ4tF¸âÉ|…ÂÒJ$9³8,:&oåù6Ü<‡mtco0ʽÿ¾›¦îOÝtg”Ú2Z¾á«œ†ÿ™WU•Æc_âp¸©š>sÔbBìîÅS«gb·Ûñy{3úk±6Ž;/Y‘©«=xRÚUF"ѸâÉBØ(*¯Ê¸˜Š$aòÖ±|†›î˜?j1œ6ÿvç–UçòÀK{é ¨-c60¼œMõu˜-VÊ*«ÆVYåT“™P(˜’ ÆáÊEgòÝmÍ3ûñEòŠËI]æfÊó-BnaIÆ«²qü]¬½l:›B¦Î§M᾿­æOŒ}Œ +gOw'Ñh„Ü‚BtŒnyE„CaT5š•²[m9DÂ_VÒ7 xcÃ%®‚¬¤ éð¹êœ²ŒŸל[FkOˆ·>ëÈJÙ3aåìloÅ›ŸñÎèëÀÉÍ' e<íxú«žÎά¤o~¹©»Ã•cà÷yøúÂâ‡KÆ‚"K\² ˜ûиÑÓ°r†ƒA\î\2U•IÞ\¹n"áìÈ `±Yø²×¶5;j»±9r³–~ÈßËWç’­s`Õ¼BŽ6·oÀ°rjšŽÅjÍZú‹ UËNµ@‘ÍD£‘¬¥o¼&“%ké«‘0UÅ9YK¿ªØN8jÜa/–ë(Š™lM™5™ÌhjöŒ¬È¨šñÇÒÆC(Íê„‹¨¥ÐeÉÚ9Pì¶d|BJ&1läÌN+æ'å ùÈOâSÕ²…®ÇÿgL +§D£a²ÕÞˆFBcšm”.šª¢(®˜d‹Å„Í^Ó@6™hí ‘­s µ'˜µÎ¬L`X9%Y" g-ýp8Œ,eONUËn•ϸíÖ¾Ðì`2™9ÖžÙ\ÇÚƒ˜M'wüh0¬œK½žîŒoÅ7oO7Š%{òD‚!ìNgÖÒ7 §çðe¯·Ójsðá®ö¬®igZ‰q¯Ç5¬œyùEôötgå"j]×ñxz°˜³Ó¬¡Pˆ¼¼‰y‘oºÜt~ oOÖ.tÏqäòþÎvT-óéGUvµsóªòŒ§) +gnA>ŠÉLOg;™nktwµc6›1™ÍY){(àÇl1c³Û³’¾QXq†ƒ—_ov&[˜,VŠÜVÞÜÜD¦Ï767Rì¶rÕ2ã^€mX9EÁ™›KkKj‡ÜÝÁ5»-¬^RÄšÅØÿzÐOéÕ÷QU €·§_oj$‚Fߨrº®£ª*áp$ ›Õš‘ª¦$K(² ÅdÂîp’—_xÊ—Œ‡Í‡}üÇÇ­l?Ü…Ç&Žd¦Ê«kèѾi}&+2ħáI’&Efêivn\YÄå‹‹Èɱý·µ1Ç*ç„«ƒ)Š‚ËéÄa·.,"UÑt ½¯-*É2²$c2)X,–I×þ3+f8X1c2MӇçì90áäŒ#Ë26ÛÉ[{T`CEI!¦@#݉îÃVmG#ÔPû )‚Ô %_ZskÇ*–R âJ.@ @ †ÿ›7Q;cçMIEND®B`‚././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gtk4/controls/images/togglebutton.png0000664000000000000000000001631115074674453024532 0ustar00rootroot‰PNG  IHDRd¬tsBIT|dˆtEXtSoftwaregnome-screenshotï¿>&tEXtCreation Timevie 09 dic 2022 08:49:27ÚI)IDATxœíy|TÕÙÇ¿w&“d’™$“•„ì I‚(ˆl"»(¾jëRikµ¾µ¥VEܨҾµ¾õ­­…ZA‘U"–€aËdOÈ>3ï³d&™I&$p¾|îgrϽ÷œsŸáþæ9ÏY.@ @  O õ‘<AÏ£ïÎ̺Cìå!DF èØ•.‰Mg åu’ƒÇAï¡¥xè<æ}ðm‰ˆÔÆß-G ô,¶„D߯߶®k“Ž<ô-EC²Ød-ö퉌@ è=´ËM×b¿åùíâèƒoKPL¢bk#ônl ‹ÎÎÖRx,¯·‹“•°ç©È->å€7à x.Ƽ…¸½K‘hêJà*Ph›ÎâÓòZ‰v¦=qi),&ÏÄ$(N€ ˆþ|횆§ { z!&AŸBB¯×éËÒýô\ä×0D³À˜D¦]iOZ6ƒ,EEx>|ĺ5«?$<;}c × ‡ò³æü*33óP 4b“7c«™ÔжÄÅÒk1y,NÆÍðHIIýÅÚÕëõ5¯AABjš:ë¾Ç²²²U@iÂ:v¦=q±å±8cˆ©$;›³„Ç"ÜœHeáQ1Yb2&±åÁ´Bf/×›ÆÔò[½jå„°71zÍVþk6†Ž†ç_ŽuO0ØqRÚºoÙR`ðX”@lÞÙœÏ$Ðt¹þ ×¢×éJ#bâþ 8 Ôbð`L1˜–^+ÚŠ•Øê!2‰ŒF’ô^Ý;ÍI ô6$™LƒÁ‰P`Ø•ÑN‘£ã\ZŠ‹:ÑÝ,Üüè%À ëf‘i l›8â¹´'ÀY8-Á-ƒ3ÍϾ¥¸˜¶tMØkÉ»¥Ê /`ùÜ·œâc[ž‹­%Z Œ¬›×•½Ëé>ö„¥•ãÈð[“åB[‚[Ka±51Ù&öÄÅV?¶¥ÀÜÁÜ/·n§¶¶Öîñ±œ˜p]ê²ï@*……Ü;y"*U»ç766²~Óf󾓓C'áåéÑ“UíVvìþ†²òr$IÂÇÛ›þýˆ‰F&k¯U/è&Z>û¶´¡C]Ñ–[f"Ò­à¸|¹e;%¥¥vß7s:I×I\¾ýþ‡Ó3¸ãö‘¨—†ÆF>ý|C«t¹\ÎoŸ{†‘ÃS*·¢¢’õ_~EXhãïcNÏÎÉå@ê!n1Œ„¸8Ço¤ƒlÛ¹‡¼óç[¥‡†óô“; ÇʘéÔ:M™Ý"íæ——% ‡Nk#´jí¤¦æÙ_Íc@d$jµšëo‡6犵8ÂÃBøãë‹))+cãWÛØ¾kkÖo`äða•V]Sͦm;9<™ñwÝiN?ñ"›¶íÀÏß—„¸ØN܇£îcù[Kpqq¦°ð2_ïÙË¡#Gyõí?ò×w߯×Ç»Ëï;Ìzè1Æ à¥ùÏâáaðN+««Yö§÷9~2›Ÿ®ìJööV¡´Kg'ÞÍ¢þæ¿Õjwüü îßêÜ¢+œÌΦ®®ž1‘ÄDEY¯ºvôŒcTTV3$1žüÂ"jjk?¶ùÍÎÉ%çÌh¼¼HŒeÇ3š??»uÌ;S§sQ891$)?_«ã …‚~þþ<2÷>¶ïÚƒ¶Ik>¾}çnÊ+«˜;{2™ŒüÂBöøØè(¢¢"غc—ò‹X³~#I ñ¸8;“–žÀÑŒ,®]«aÂ]cÌy[¶Ø •¦&-£F¤pèH:å• NL ,4¸Í¿nnnô $%yï½ÿ7öHå“5Ÿ3ÿ™_´kìÜ3d?Áý3§sôØqò ˆcPÂ@*««É8–EeU)CÓ/  Cßmo!$¸?§²sxåwxýåH’Äâ7–‘wþÁAA]ɺSÏ{GÅ¥¹›ßq±ÆÖÊ¢F¶íÜÍ??YMSS“9mê¤ üüñŸp1¿€Wß\FIY2™ ggÂÃB?Æ .ÿçS6mÝn¾^íîNÕµkÄÇ À×B\,ÊÿdÍZ¾øj«!Y¯ÇÕÅ…—_ü ƒâm®zš‘u€;F4§mݹ‡ /1gúTd —.²æó ̘2 ?_¶˜Ä¥ €5Ÿo@.“á¡VsØ(.éÇ2I?–ÉÄx|½½ÛµÅ·ß$ëÄIV¯[ÏÕâÀÐT[´à…¶ãW-ì>wöLöH%çL®Cö8}:—Õk¿`ï¾™ó?æNÒ33)+¯0汎·_{…ˆÐP ýï¶7ñêï_dáÒ·8á¯,}I’8wá"þ¾¾,úý ÝñÌvHdDD¬‹äò¯Â×Û›w^[ÄÒ…/á£Ñ°åë]dž0<Ì+V}JIYÌšÁ_ß}‹éS&S[WgÎ#÷ìY6mÝN€ŸË–,fé—pUº¶Yîñ“٬ߴ…¡IƒXù·¿°táK446²bõ«óÎ]¸ÈÜÇæ1÷±y,ÿëßÉdDG„;toýùཷ™’ÌÆÕ+y`Ö &ǯž|€'}„«W7`€C¶¨¯o`ÔˆÞ]º˜ÉãÇ¡ÕjÙ´e‡Cuj®[?œœœ¸|¥­Vë°=üý|xçµE<ùè#ìÞ·Ÿ©“'²lÉbFO¡¾¾Áì­9z?½oo–.|‰À~þœ¿x‰s.âçëÃ’… ð÷õ½îõé´¸èo±öî;5íZ­–Ù3îe@L$ ñ±Ì™5 €Œ¬ãhuZ2²Nà¬Ppÿìéô dÎÌ©V¹¥Ëàî±wAB|,#’‡Z•ײüô,Ã5..Îlݹ›ã§N¡R©81ßê/Oî›1•ûfLeÂ]cÉd,}÷O¤Ë´™oó¾ušå¾åy–×¶g Ëë&Ü5†¨È™{—‹:dw$ƒèêêŠL.sØÃS’É´{&š¸‰ãÆÁý3§ërÙáûémÿär'œÎf»)œ(Š.åÙYÄ"O]äò•«øù4Ç:úb5¥eå”WT Õj‰ ÅY¡°™Gq‰¡G**2Âárkjj(+¯@.7 ˜NJhõ ÀËÓ“çÌ2ï{¨Õ¬ß´™CéG:xÃå9B{¶°…Z­F&“YÅ¡¸¤”††" ÍGía‰FãÉ•âbtúæ}VÛéû¹‘”•W°èw¸”_`ޱ\*(`ñËX²p¯ë»BJçÅåV‹¹˜hÑö÷4Ž),¼ÌÐ$ÃÃzælAþx¨ OqI :­Î06£E<Ä4îäò•«¶_EÕ2~¢‡~Æ oB\,?yðþö¯1eè骬¨ÄèPUU·Fc}E>z½Þfž–éíÙÂÖ}´ª·=Zœÿ¥1>5"yHÇìa¯\6ëÐýô^_¶Ü,,K.`ÑÒw¸TPÀëï¼Çò7—\×úˆ˜KIJˆ`ýW[8™CÞ¹óìÞ»™LÆðaÉ8991 :šòŠJ>ùl—¯\açž½Vy$ 4ŒÙðÕ²ss9›wŽc-Úôr〱rcàqDJ2r¹œ­_ïâdv/åsñR¾uõzt::Ž‹ù…|m,;ÞX¦ŸŸ¡iðå–휻p‘ÔÃG¬.÷P«È=›GEEZ㯺Zmk“yâ$õõ ètºvmÑ®–”r¥¸˜ã§²ùÛ?V°eûN‚û1sꔎ٣ôäýôyçÎjðR<=Ñxz²dá"ÂBÉ;áº×§ Í¢^&Û× ëŸ¸Ä±L¿g_mÿš—_0Ä{h.á¡Á€ž'y×Þy›·±qó6”J¥U~ƒã¹cÔm|wð^zõ ‹s åÅÇÅòÃát½¹Œ'}„{'ÞÍ“>ÄÇŸ¬áå×ßD¡PÐØØÈè‘·ñâ³O™ë˜wá"s~ú3«;}Ûp¦Lè™:qé™lÚ¶ƒMÛvhÕ «G­rgDò¥gð³_?ǘѣxî©y Nˆ¯7‡Ó3xxÞS<=ï Æ½£][´ïBØæ7¿_hµûˆæ=þärò"þíØ£­rl».Ž|·½‰ «þe±g¨›ÆÓƒåo¾f•v½°Õµd9Ôß´~‹+†5ÔÆmä™Ó'–_¯Jö§gpöÜyîsG«±$g~Ì#'÷,ÎÎ Æ °#†AzF&H1Ñ‘¼ðÒ"'%°xÁ‹€¡y‘~,‹üüÂÃCùþà!v~ó-o½ú2±1ÑèõzRÓÒ)..&1>Žˆð0ÀД:™Cuu5!!ÁDE„¡V©hll4wË‚aè¼—§'QaDE„[ÕíÜù d?‰¯¯7#†%³c×7ô dHR":Žƒ‡Ò¸Z\JxX(CºŒ«®]ã`jõ $%ÄÜ®-öø‚¢"¦LgèµnÃ&”nJ¦MžØÊ®_ïÞKY…Á[“Ëdöó',$”àþ­Îm˧sÏ‘u‚aC’ˆ6ƶvïÝGqi³¦Þƒ‹‹ µuulÚº_ƽÃáïöf':6áy ÃBÝU@ P‡õŠt­~-„¸Ü²Nœbñ›Ë˜2ñn»ã%¾þ'³sXùá_Œ#‚CgÅEt¯µµµìO=Äð!ƒ©­¯ã?Ÿ}`h·íxèÈQ4žžôëçOjÚNfç7 µJ-l-蓈˜Ëu çìY>üç >4îK’Äô)“’ÉŽ·l#;'×|Ÿ¯Oýì§; ú*oeÍ"à :.ñú6‹Äï©@ h s=‚ˆ¹‚AŒÐ=‚@Ð#ˆ€®@ èºÐò"ì#šE Gè´ç’!¯;ë!n2:-.·Ý9€êÊrJНPWS‹N×±ÕÄÍÈdr”J%Þ~¨<[1LؾûèŒýmÓ¥e.¯PYVJ`h8*µ§yyAAÇÑjµTWUR”žºÚ|ÚžÖ1ï 5ÕÕ¸(•¸©THÒ-ñ¶—C¯×£mj"ÿbî*‚Ã"ot•ú<—êÊr*ËJ‰ŽOÂÉI,ÅÛUär9ž^T*5¹'3qUºÙý­®,§¦º7µZˆJ7!IN r''®UVR]Y!<˜.Òé€nIñCÃ…°t3r''ú…„SzõŠÝsJНà¢T aé$IÂY©lÓþÇè´2ÔÕÖà®ò0,Ð,èVTjòϱ{¼®¶7w±€TOáääDmuÕ®FŸ§Óž‹N«1–B.—£Õéì×iuÂkéA$IjÓþÇã\A ÄE ôB\AÐŮ̶钸ˆŽ"@`>HeÏÞo9û〡 ÐßߟѣFâåÙw0ÕÔÔòåæÍÜ3i"/¯]‡IMKçÂ¥K€Áö> Ƀ™_ÕÚÛ)+«àTnÅ%¥2tð ы֋¸á1—Ý{÷²ïûï©©­åjq1k?_Ïô9p,+ËáeeåV韭ûœcÇww•­ÊÝøÕff?ø_ÆòËz¬¬žà`Z‡fPWWOiY[wîæ©ù¿ã´Å+NÚC§Ó±bÕ**­Ç…lýzÙ¹öÇêt•ßìãÅW^eïwÉ;?øKßý3:Ñ…Ük¸áž ÀÐÁƒyî™§ÍûÏ/x‰¬XÉûï½ëpŸ®]ÇœY3Ñhš=‡]ß|ƒÂÙ™Á‰‰ÝZ_€ú†žøÅ/Q(œyuáøÍot{׃øØ<úÐæý·ÿô>ë6mfá‹óÌAbóŽ]Lºû.<=šö8t…BA\Lt÷VØH`€?ï-]Œ—ÑSÌ/(ä……¯‘‘u‚äÁƒz¤LAÇèÝÖ/>,™í;wšÓöì݇§‡šaÉCÍç¬ødS§LÆÏ×—­ü7k×—§'?yèAöîÿŽ¢ËWØà%%%Œ7–ÈÃ;‚Ë++ùá‡4ÊÊËHJL$~`œ9ßÒã­ÑÐÔ¤åXV&nnnŒwînnVµvqVð‡ßý–ÄøFwÜÖËÕû‰ñÙàó~jZ:*w7ã›m´á«­Œ½ãv¼5^|±i3ÛvíA­R1óÞÉü~”’’2gdRV^Á¨)„ô ªºšcY'©¨ª".&’(ãwpìøI¼<cæÔ{P*•ÝZoAçéÝAññüü‰ÇÍûO>þ÷?ü_nÞÂÃÎí¶r ‹ŠpvvF­²îj 2»ù¶psw»igˆŠdîìf±}`æ4þûw/³{ï~¦M™Ômå— P(ZÅ®üü(¯¨´{«Òµ]ÛðÑ <=<˜5uJ·ÔUÐ=tÑsÑwÃÖ:/µÊ¡IIääz$I2þ’¶¼®­ýÖyûh4444PRZbu^iY™Ñ¥·]ŸÎÞG÷ØåúâîæÆÀØŠ®âY’$ÙŒ7uO)«¨°J¯¨¬ÄßÏ·Óù®Ý°‰Ü³g™ÿôÏ‘ÉÄ—ÞD¯kaìÄ…K‰Ž2tcøû“š–f>^__VÛ<žA’$ —¯X/ðãâìb•æïïGHpV¯YkNË;wŽìœÓÜ6<¥§n§O¡Óé)(ºLXH¾ÞÞdd0ohh´K"I†xÅ¥¥Vù8+œ).iNóñÖàÏæm_›Ó.pöÜ9w2N²yÇ.vìþ†E ^0wI z½¢Yt,3‹þï#jëjÉÈÈÄÇÇ—é÷ÞÀÌéSù|ãFž}á·„…sè°uÏ‘$IŒ1œeËÿ‡qcÇpïä‰D„‡sûÈüsÅ¿©«¯gèàÁŒ½s4 ^˜Ï‚—ñã¹<øvßw<÷ôÓøûù]÷ûî œÊ9êu_PWWϩӹh¼¼¸{ÌhÆß5†í»¿áõ?þ‰ ~dž8eu½$I ”ÀG+W1rø0ÆŽIpPÉI‰¬ûr3õÄÇ`Dò~þøOøãÿü/ó ðõñ!íÈQ{h.>šŽ÷ð|wð+WFRb<;÷|kNW©Ü¹oú½]°ˆ »°µÚ“d±ÉŒç8 ÀŸÿrÞ“ý‚º\I’P©TÈårär9þþþL›r?{ô§ÈdÇÊÃÃ{&LD¯×ãëëÇSóžd@t4QQ‘¸ÛðcÇ܉ÊÝggg¢"#Q¹«”@DD8MDEFàëëKÿ  &Oœ€““/O/æ=þ8£nauû!ÁA„…†Y¤HDGFà`ÿ>€ä!Cpµ1&£3\½\€ŸEº‹/âÒ åHÈpwS"—ÉËdøz{3nÌíÜ?cšÙöj•;wŽ èÑxixèþÙ„‡†ŒRi¨Ãˆ”dÜÝ”8+œ ÆÝÍ1Q„ôBÛØDXH¼5üý¸óöÛPÈðP«y`ö †&Y p”$üèhQG‰ðþøúøXÕ½¤¬”~þøz{ãäädÞ”J%¢º¾¸vC}]ûßj¼ñæ›;€K@ƒqkšq³ÙŽ·ÕHµ“¨¸n€Ú¸:­¶#å ÚA«mâra>j·Ýs¼ý¨¯¯½i'SÞHôzõµuxûûßèªô&l,vb3Ý G<ËŒÌ#òÔžž¸«=ù1ç•ååâõ—]D«ÓQY^Æ9ÙxxjP{Ø_ \åቻʃšª*…Ètz½žÆÆ®UU£R{ R÷â¯VϾEZ›8s±Ì\ h dNΔ_¡ðÒ9±8rÉd¸ººáåã‡JíB¡hóüà°Hª++(½z…škUè´Âö]A&—¡tu'8-…Ä–¨qú6¶ÞÓ£³ñwËs[ÑžH-þn)$-½!.A߯ÞK¸lí·<ß GÄ å9ö¼!,ÁÍ£ÛluDì+DE ¸9±'Í-ê¬0An-ÄÔ{@ @ ‚^Àÿh­n!®_IEND®B`‚././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gtk4/controls/scale.rst0000664000000000000000000000016615074674453021664 0ustar00rootroot.. currentmodule:: gi.repository Scale ===== A :class:`Gtk.Scale` is a slider control used to select a numeric value.././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gtk4/controls/spinbutton.rst0000664000000000000000000000313615074674453023002 0ustar00rootroot.. currentmodule:: gi.repository SpinButton ========== A :class:`Gtk.SpinButton` is an ideal way to allow the user to set the value of some attribute. Rather than having to directly type a number into a :class:`Gtk.Entry`, :class:`Gtk.SpinButton` allows the user to click on one of two arrows to increment or decrement the displayed value. A value can still be typed in, with the bonus that it can be checked to ensure it is in a given range. The main properties of a :class:`Gtk.SpinButton` are set through :class:`Gtk.Adjustment`. To change the value that :class:`Gtk.SpinButton` is showing, use :attr:`Gtk.SpinButton.props.value`. The value entered can either be an integer or float, depending on your requirements, use :meth:`Gtk.SpinButton.get_value_as_int` or :meth:`Gtk.SpinButton.get_value`, respectively. When you allow the displaying of float values in the spin button, you may wish to adjust the number of decimal spaces displayed by calling :attr:`Gtk.SpinButton.props.digits`. By default, :class:`Gtk.SpinButton` accepts textual data. If you wish to limit this to numerical values only, set :attr:`Gtk.SpinButton.props.numeric` to ``True``. We can also adjust the update policy of :class:`Gtk.SpinButton`. There are two options here; by default the spin button updates the value even if the data entered is invalid. Alternatively, we can set the policy to only update when the value entered is valid by changing :attr:`Gtk.SpinButton.props.update_policy` to :attr:`Gtk.SpinButtonUpdatePolicy.IF_VALID`. Example ^^^^^^^ .. image:: images/spinbutton.png .. literalinclude:: examples/spinbutton.py :linenos: ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gtk4/controls/switch.rst0000664000000000000000000000107215074674453022073 0ustar00rootroot.. currentmodule:: gi.repository Switch ====== A :class:`Gtk.Switch` is a widget that has two states: on or off. The user can control which state should be active by clicking the empty area, or by dragging the handle. You shouldn't use the ``activate`` signal on the Gtk.Switch which is an action signal and emitting it causes the switch to animate. Applications should never connect to this signal, but use the ``notify::active`` signal, see the example here below. Example ^^^^^^^ .. image:: images/switch.png .. literalinclude:: examples/switch.py :linenos: ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gtk4/controls.rst0000664000000000000000000000051215074674453020570 0ustar00rootrootControls ======== Learn how to use the most basic interactive UI elements from GTK, such as entries, buttons and switches. .. toctree:: :maxdepth: 1 :caption: Contents controls/entries controls/buttons controls/check-radio-buttons controls/spinbutton controls/switch controls/dropdown controls/scale ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gtk4/display-widgets/examples/label.py0000664000000000000000000000643615074674453024566 0ustar00rootrootimport gi gi.require_version('Gtk', '4.0') from gi.repository import Gtk class LabelWindow(Gtk.ApplicationWindow): def __init__(self, **kargs): super().__init__(**kargs, title='Label Demo') box = Gtk.Box(spacing=10) self.set_child(box) box_left = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=10) box_left.props.hexpand = True box_left.props.homogeneous = True box_right = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=10) box.append(box_left) box.append(box_right) label = Gtk.Label(label='This is a normal label') box_left.append(label) label = Gtk.Label(label='This is a normal label with xalign set to 0') label.props.xalign = 0 box_left.append(label) label = Gtk.Label() label.props.label = ( 'This is a left-justified label.\nWith multiple lines.' ) label.props.justify = Gtk.Justification.LEFT box_left.append(label) label = Gtk.Label( label='This is a right-justified label.\nWith multiple lines.' ) label.props.justify = Gtk.Justification.RIGHT box_left.append(label) label = Gtk.Label( label='This is an example of a line-wrapped label. It ' 'should not be taking up the entire ' 'width allocated to it, but automatically ' 'wraps the words to fit.\n' ' It supports multiple paragraphs correctly, ' 'and correctly adds ' 'many extra spaces. ' ) label.props.wrap = True label.props.max_width_chars = 32 box_right.append(label) label = Gtk.Label( label='This is an example of a line-wrapped, filled label. ' 'It should be taking ' 'up the entire width allocated to it. ' 'Here is a sentence to prove ' 'my point. Here is another sentence. ' 'Here comes the sun, do de do de do.\n' ' This is a new paragraph.\n' ' This is another newer, longer, better ' 'paragraph. It is coming to an end, ' 'unfortunately.' ) label.props.wrap = True label.props.justify = Gtk.Justification.FILL label.props.max_width_chars = 32 box_right.append(label) label = Gtk.Label() label.set_markup( 'Text can be small, big, ' 'bold, italic and even point to ' 'somewhere in the internets.' ) label.props.wrap = True label.props.max_width_chars = 48 box_left.append(label) label = Gtk.Label.new_with_mnemonic( '_Press Alt + P to select button to the right' ) box_left.append(label) label.props.selectable = True button = Gtk.Button(label='Click at your own risk') label.props.mnemonic_widget = button box_right.append(button) def on_activate(app): win = LabelWindow(application=app) win.present() app = Gtk.Application(application_id='com.example.App') app.connect('activate', on_activate) app.run(None) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gtk4/display-widgets/examples/picture.py0000664000000000000000000000200515074674453025146 0ustar00rootrootimport gi gi.require_version('Gtk', '4.0') from gi.repository import Gtk class PictureWindow(Gtk.ApplicationWindow): def __init__(self, **kargs): super().__init__(**kargs, title='Picture Demo') # Let's set a windows size so pictures don't start at their default size self.set_default_size(500, 400) box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6) self.set_child(box) label = Gtk.Label(label='Here we can see some nice pictures:') box.append(label) picture = Gtk.Picture.new_for_filename('../images/spinner_ext.png') box.append(picture) cover_picture = Gtk.Picture.new_for_filename( '../images/spinner_ext.png' ) cover_picture.props.content_fit = Gtk.ContentFit.COVER box.append(cover_picture) def on_activate(app): win = PictureWindow(application=app) win.present() app = Gtk.Application(application_id='com.example.App') app.connect('activate', on_activate) app.run(None) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gtk4/display-widgets/examples/progressbar.py0000664000000000000000000000432115074674453026027 0ustar00rootrootimport gi gi.require_version('Gtk', '4.0') from gi.repository import Gtk, GLib class ProgressBarWindow(Gtk.ApplicationWindow): def __init__(self, **kargs): super().__init__(**kargs, title='ProgressBar Demo') vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6) self.set_child(vbox) self.progressbar = Gtk.ProgressBar() vbox.append(self.progressbar) button = Gtk.CheckButton(label='Show text') button.connect('toggled', self.on_show_text_toggled) vbox.append(button) button = Gtk.CheckButton(label='Activity mode') button.connect('toggled', self.on_activity_mode_toggled) vbox.append(button) button = Gtk.CheckButton(label='Right to Left') button.connect('toggled', self.on_right_to_left_toggled) vbox.append(button) self.timeout_id = GLib.timeout_add(50, self.on_timeout) self.activity_mode = False def on_show_text_toggled(self, button): show_text = button.props.active if show_text: text = 'some text' else: text = None self.progressbar.props.text = text self.progressbar.props.show_text = show_text def on_activity_mode_toggled(self, button): self.activity_mode = button.props.active if self.activity_mode: self.progressbar.pulse() else: self.progressbar.props.fraction = 0.0 def on_right_to_left_toggled(self, button): value = button.props.active self.progressbar.props.inverted = value def on_timeout(self): ''' Update value on the progress bar ''' if self.activity_mode: self.progressbar.pulse() else: new_value = self.progressbar.props.fraction + 0.01 if new_value > 1: new_value = 0 self.progressbar.props.fraction = new_value # As this is a timeout function, return True so that it # continues to get called return True def on_activate(app): win = ProgressBarWindow(application=app) win.present() app = Gtk.Application(application_id='com.example.App') app.connect('activate', on_activate) app.run(None) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gtk4/display-widgets/examples/spinner.py0000664000000000000000000000176515074674453025165 0ustar00rootrootimport gi gi.require_version('Gtk', '4.0') from gi.repository import Gtk class SpinnerAnimation(Gtk.ApplicationWindow): def __init__(self, **kargs): super().__init__(**kargs, title='Spinner Demo') button = Gtk.ToggleButton(label='Start Spinning') button.connect('toggled', self.on_button_toggled) button.props.active = False self.spinner = Gtk.Spinner() box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, homogeneous=True) box.append(button) box.append(self.spinner) self.set_child(box) def on_button_toggled(self, button): if button.props.active: self.spinner.start() button.set_label('Stop Spinning') else: self.spinner.stop() button.set_label('Start Spinning') def on_activate(app): win = SpinnerAnimation(application=app) win.present() app = Gtk.Application(application_id='com.example.App') app.connect('activate', on_activate) app.run(None) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gtk4/display-widgets/examples/spinner_ext.py0000664000000000000000000000574115074674453026043 0ustar00rootrootimport gi gi.require_version('Gtk', '4.0') from gi.repository import Gtk, GLib class SpinnerAnimation(Gtk.ApplicationWindow): def __init__(self, **kargs): super().__init__(**kargs, title='Spinner Demo') main_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6) self.set_child(main_box) self.spinner = Gtk.Spinner() main_box.append(self.spinner) self.label = Gtk.Label() main_box.append(self.label) self.entry = Gtk.Entry() self.entry.props.text = '10' main_box.append(self.entry) self.button_start = Gtk.Button(label='Start timer') self.button_start.connect('clicked', self.on_button_start_clicked) main_box.append(self.button_start) self.button_stop = Gtk.Button(label='Stop timer') self.button_stop.props.sensitive = False self.button_stop.connect('clicked', self.on_button_stop_clicked) main_box.append(self.button_stop) self.timeout_id = None self.connect('unrealize', self.on_window_destroy) def on_button_start_clicked(self, _widget): '''Handles 'clicked' event of button_start.''' self.start_timer() def on_button_stop_clicked(self, _widget): '''Handles 'clicked' event of button_stop.''' self.stop_timer('Stopped from button') def on_window_destroy(self, _widget): '''Handles unrealize event of main window.''' # Ensure the timeout function is stopped if self.timeout_id: GLib.source_remove(self.timeout_id) self.timeout_id = None def on_timeout(self): '''A timeout function. Return True to stop it. This is not a precise timer since next timeout is recalculated based on the current time. ''' self.counter -= 1 if self.counter <= 0: self.stop_timer('Reached time out') return False self.label.props.label = f'Remaining: {str(int(self.counter / 4))}' return True def start_timer(self): '''Start the timer.''' self.button_start.props.sensitive = False self.button_stop.props.sensitive = True # time out will check every 250 milliseconds (1/4 of a second) self.counter = 4 * int(self.entry.props.text) self.label.props.label = f'Remaining: {str(int(self.counter / 4))}' self.spinner.start() self.timeout_id = GLib.timeout_add(250, self.on_timeout) def stop_timer(self, label_text): '''Stop the timer.''' if self.timeout_id: GLib.source_remove(self.timeout_id) self.timeout_id = None self.spinner.stop() self.button_start.props.sensitive = True self.button_stop.props.sensitive = False self.label.props.label = label_text def on_activate(app): win = SpinnerAnimation(application=app) win.present() app = Gtk.Application(application_id='com.example.App') app.connect('activate', on_activate) app.run(None) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gtk4/display-widgets/image.rst0000664000000000000000000000144015074674453023121 0ustar00rootroot.. currentmodule:: gi.repository Image ===== :class:`Gtk.Image` is a widget to display images. Various kinds of object can be displayed as an image. Most typically, you would load a :class:`Gdk.Texture` from a file, using the convenience function :meth:`Gtk.Image.new_from_file`, or :meth:`Gtk.Image.new_from_icon_name`. :class:`Gtk.Image` displays its image as an icon, with a size that is determined by the application. See :doc:`/tutorials/gtk4/display-widgets/picture` if you want to show an image at is actual size. Sometimes an application will want to avoid depending on external data files, such as image files. See the documentation of :class:`Gio.Resource` inside GIO, for details. In this case, :attr:`Gtk.Image.props.resource` and :meth:`Gtk.Image.new_from_resource`, should be used. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gtk4/display-widgets/images/label.png0000664000000000000000000014607415074674453024354 0ustar00rootroot‰PNG  IHDRìjA!¤sBIT|dˆtEXtSoftwaregnome-screenshotï¿>&tEXtCreation Timedom 18 dic 2022 14:24:56àô IDATxœìÝy\TÕûÀñ ˈ"†  .©‰»©ˆä–Š©i– j*fän¤¹öSÓ´\Ê-#Å̾-fšû‚ûWÜ*·ú*‹€;Š€lÃï`†Ùíy¿^÷…sïÜsŸûÜ3ãárÎ= „B!„B!„B!„B!„B!„B!„B!þõ¬Š±¼¢.[!„Bˆ’,GÇ¿-bI£ÚJã§æ6i° !„Bˆ“´7Ôs4~šÄœFµfc\ýµú¿­Í H!„Bˆg”2ï§zÃ]³¯«Q¯“) vÍ;êÖj?µ5ÔmL D!„Bˆg\vÞO͆»RËzõŸz•2òàÚî¢[küÛZc½ÜaB!„ÿ&6{½P:G™c%ÏnB!„°œœ+ 4»Ãä/zí¨­Án¥å§zc=1<ªB!„"Ÿz[Z³»úÏÍl}ƒN5ﮫw1f°ªB!„â1õ¶´æ¢³óŠ®.1VÿVo¼ç=“]î¯ !„Ba‚ü¹ÔéšíîBl]]b4g7µÍ[ìT‹´×…B!„0…Ú¢>ë© ŸÅ^¨ÑnhЩB-ÆM™ÁÕèhÂ׬¤\™2&ïß/à=Ê•)Ëše‹ÍŽ¡_À{([µLg|VVV8W¬ˆ{•*tjÿ*¾­[™}L!„OžÙ v¹Á.„:¦¤3qÿ¢ˆAŸV-±¶¶">1‘óýÅÙ?þ òØ ¦Lø Ž,„âI°à»4Ù…ÿf9j?Kb“=wÝè÷†Rºti®üóó>ÿ’c'ÿËžƒéøªo[!ž?½ü‡P¯îK|4~,åÊ•àÁÇ,\²Œ?þºÈOëŸh<Ò%F!ŠØƒˆØògΟçÎÝ$Ê—/Kë–-Ø÷-ìlmUïKKOç³/VpúÜT(_ŽžÝºÒ¥c;ÕöGéé|»i 'þEJZ*/שÃð¡yÁÅŬ¸j׬ÉýXº2„]»÷«솎Ó? ïÍq°wàØÉSX[[óz玴hÞ”µë¿åò?W©ä\‘÷‡ ¦~Ý:(•J~øùW>Ê­;w¨êîŽÿ[oÒ¬IC3³*„ONµªî\¸x™Ÿ,`δÉXYY1ë“…\Ž¡ª›ÛÇüÇ3æÈ"‹,²ü‹—|Z¶ÙÙÚsâT/T®Œw‹WPf+ùù×ílùqký“““¹qã¼^æÆÍ[¬ ]ÇÉS§Uïùlér~Û¹›:/Õ¢EÓ&D=Ǽϖ¢ÌVŒA×¶–ÍšoÒqö<ÌésPÕÝ{II„oúžq“§“‘™‰³Sbbãøü‹dddB¬û– ›ÀÆÆ†& ð¿«×˜³p]¸üô¯,²È"‹åã)“¨âZ™è˜8fÌ]ÀŒ¹ ¸CåJ•˜9e¢ùe›Iî° !Dsp°gíò¥ª× ‰75ñCN=Ë€>½Uë*T`᜙X[[³ïÐa¾XµšßvíᕦM¸é3çh֤nj =#ƒ#ÇOŸ˜hö…BB¡ -íÙÙÙÄ\¿nÔqK³rѧX[[³qËØüŸŸéøª/£Þ `lðGÄ^çz|eË”açž}T«ê΢Oþví;ÀŠ5_ó㯿ñrÝ—ÌŠ]!žçŠ™;ý#¦ÏOtl.•œ™=}2•+UzâñX0èÔ‚_„⹑£õûðâå+lû}7Wþþ÷“““Còƒ‡Þk[ªVÖVäCëV¯ðåWkˆ‹'‡â®ÇpêôYz R ìä‡ËÑ÷}œ£_FF=Âõ¬m¬>޵µ*Ö—jÖÀÊÆJµ½vÍšÄ^çÁÃdîÜ»‡R©¤IÃXÛX“Cm¼[²bÍ×Ä^¿.ÿ!ž 66¥°³µS½¶-e‹­­íSù“;ìBQÄâ™õÉB*WvaLà0ªVu'ðƒ‰z÷IÏÈ ”Mî×r™¼GE6kÒˆ€Aý ¼×’»;çþü‹œœªW{ÑìãX[îMicóxÝ£Géd+³UëÒÓ3°²²ÂÁÞÞìØ…âI¹—tŸ™Ÿ, îz¼ê/qññÌúd!³§OÆ©Bù'ù v¹A"„Zû%^ºô7™™4kܯ—ë¡T*ÉÉÉyüþ<22ÈÈÈÄÎÖ–3gΓ““C5w7ÈÝݰ¶¶æòå¿)W¦,e5ŸõžWŽ2G©ÿûX-¾„Ä›|ýMÖÖÖôíÝÓ¤ãú·®u9Pͽ ÿ:Ëàþ}±³µ%êÌYrrrðx±šüÿ!„(ñæ,\¬j¬Ïž>€™sÏœ‹X­q}áví;Àßÿ»JVVV¡}ö8D³Æ iÙ¼)W¯Å þÝÙåµöDÇÄqü¿§p}Á…þoõâ庵Uï>d•œØy„ÿl݆ë .ÔªQƒœ%VVV Ð5aáìØ³Ÿ& P¯NíBñ<|kkkÜ\_à•&y«W÷¼Æúã8 ç1#o±“Cð# ‹ØLÔ™sœ:{–:µk1Ä¿n®/è(G!JŽ7¬S{•ûåT¾‹çý_uOŠ•–uÖyK)À6oQä-¥2@Ë¿/ýiþ|ÚB!„BüËÔªSpx¤iyKfÞ’(óóŸÃ.„B!„(v2èT!„BˆLú° !„BQ‚I—!„B!J0 f:B!„B7éÃ.„B!D &}Ø…B!„(Á¤»B!„%˜4Ø…B!„(ÁdЩB!„%˜ƒN¥É.„B!Dq“.1B!„B”`fßa¿sµ(ãB!„Bhavƒ½¥oÇ¢ŒC!„B¡…t‰B!„¢“»B!„%˜4Ø…B!„(Á¤Á.„B¥ÏÀA´jÛAçK@àH~Ùö›Î2ü‡ ã› M>¶¹ûý›º–P*•,úr]zô¢ß !\½vÍì²4ã”km¾ŒŒ Zµí@ÜõøBÛL­–Ös÷Ÿ1{K—¯P½NÏÈàÑ£GO4†¢*_ßõ(Jæ?‡]!Äs',t (•DlÞÂɨS,þt¾j»B¡0XFÛ6>Ôyé%“mî~¢xlýí7NEacØZ¬¬­)W¶l‘•-×Z¨[¾ØëqÌ™9ãi‡RbIƒ]!„Š£ZƒÜÎÞkM*cÄ{ïšuls÷Å#&&Ž—ëÔÁÙÙ¹ÈË–k-„i¤Á.„ÂdQQgøië6®^»FU77& ¢QC/ ÷OÈoöìÁÝ^àØ‰„„®ãjt4•œ+Ò¡];F/T¦9ûeff²rõ"áæ­;¼PÙ…€Áïеs§å¶këËC‡µÆ«YÞWkÖ²gÿ¥§Ó¶M‚F¢tiBÃÖ³ÿà!Ö¯ ÁÆÆ†ÔÔGô<„ÀátéØÑ¨8|Û´æPä¢c£ñôðäÃñã8}ö?oý•›7oÒ¬YS¦O¤B… ª}ºvîÄî}ûøçŸÿQÝÃàqc©W·®Öë¢/~MJ¥’ðˆMlÛ¾ƒ»÷’hØÀ‹àqPÅÕ•O?_ÌÏ¿n`û®]Ôðð üë5&å]Íkmè™r^ùfÍùeŽRu×6##ƒ7úôçõ.ù`ÔÒÒÒèÔ½'ß…‡1ýã9ô}»7¿mÿ¿.\`ÞÜÙ4mÔШëªïÚnèܲ³³Y½v¿ïÙCjJ*­[µ2*ÇÆ^£ÃGñÝfnÞ¼ÅËõê&33³Ðû’“2yÚLz¼Þ•­[6³ð“9´µÁòÝÏÖÖ–ªîî,˜;‡akéÖÕ9ó[à}ÇOœdò„qã]ôår¢cãX²ŠoBCˆgEHC ;+‹Í?üÀšu_S«f ºûùÇOE1õÉlÙ¸w·* Á›7X´`ëÖ„w=ž•kÖØgëöŒù>›¾]Oƒúõ3!˜‡jÍ›¾ø5…†}ÃÞý˜?ûÿX¿æ+ìlm=n"™™™L™4}ûЭKïÝU ±nJÞM¡ï™r^ù|}Zs*êŒêõ™óçÉÌÌäÐáÈÇëΣª›înn,þr]º¼FÈŠe4òªoôyºFú¶:·•!k8zâ$ŸÍ›ËúÐÆ5–ýÖíÛÌýxáëB©Xщ‘AãUýÉÍÉ»©ÞñïOÀ;ƒx­C;ïÝU¨±nÌw¾ï#}õÜæ^KIƒ]!„ÉztëJ½:uprªÀþܹ{—¸ë× ½ïÖí[dfeÑÚ»%eË–¡†§§Î»Ãæî÷V¯žÔðôÄÝÍ!àVÅ•¿.\,ð¿Î¨óRm½ñ¦¤¦ò˯Û>t0NN¨ìâBàðDr@“'N$t]GŽã·ßw15x’ÉqÔ®U‹ŠNN ìלœöë‡[•*¼X­*=ºúqîÜùûôéÝ‹†^^¸TªDÐèQTt*Ï®={ åÁPüê222ØøÝf¦LO͹1Ïš:…””>ªçʘ–wSèºF¦œ—:ï–-xœÌÕèhŽ?ÉþܾsظÜkòÔiZ{?¾C8lÝýü¨U³FŸ§¡k¤k»¡sKÏÈ`Ë?ñQðj׬IWWÆmtN‰½WnÔ¬á‰[•*L›Œ••{ö0;ïE͘ï]ßGEQÏÕYz=,!]b„BX¤Š«+ …‚ÔÔ´BÛ<ªW§YãÆ €·7otï¦úÓ³>¦ì—””ÄÎÝ{9ûÇÜ¿Ÿ»÷牺â‰E©T2eæ,¬° +;‹ÔÔÇwJ7j@§Ž˜4u:3§N¦R¥Çý»MÃã:ÒÓUë<=«“šV8ù¬­­iPß‹˜¸¸BÛŒ‰?ßõ„D²²² üT(Ô¯ÿ2×b¢u_©çk õkdÊy©stt¤i£FœŠ:ƒgõê=~‚ÏæÍåâåË9vœ~o÷æä©(‚FTícoogñyê»FšÛ [|BÙJ%uj×Vío¥÷¬-‹ÝÎÎŽF ¼ˆŽŽ1;ïEÍÔïõºSõ\¥×ÃÒ`Ba1+«­ë­­­Y¶äs¢ÎœeÛöL™6“fM›°ð“9zË3v¿ÔÔG¼;r Ú¾Ê𡃩ü ŒžlV¼esŸ‚òõW+©èä¤s_ww7”J%övÿnNÚþ£·2â¿kkì ÿÞØø23ÒQ*•dggcmýøív¶¶ØÛÛŒÁܼ›"ÿ:¯ŒŒ Úûu+°nÕKhØÀ+·[Ìé(|}¼!GIUw7^õmÃö;ñëÔ‘ø„7l 3sÏS×5ÒÜnèÜ232P*•(•Ê×ÉæÆngk‹­­­Iõ©8™ó’_wŒ­ç99Ú¿¿4Yr=,%]b„B»¦1ã£É¬Y¹Œƒ‘‡¹uûv‘ìwñò%’îßgôˆ@<=¢ó=×bbßÁ£FðùÒ/Tý‹2M))©^ÿyñžfşϽjî Â3çw¿Q*•\¼t™Zžž÷/ÎóÕdè¼ììì8¼wW¥aƒÜ‡¾>­‰:sŽ£ÇOàãí»ÎÛ›óþÁ¡#Gy¥YSJ•Ò}ïÒØó4ttm7tnªë¤ÑMÊF_#µÆjNN]¸H Oñµ¬¬,½ÛÍù1¦ž+D_‹1*FK®‡¥¤Á.„¢ØfäûÌýt!þC‡Qɹ"=^ïJ)µk§™SS®GQÒö©´Î[J¶y‹"o) ”Z¦¦<\\ìщ"×gà bãtOŸûÝ·ëùxμÏÇÕä?d];¿ÆàL:¶¹û=¯4ŸClì6SËzû !Ї|6K>C×H®¡PWÚ±Ìà8ðHÒò–̼% Pæ-*r‡ý_F¦B!„x¶Hƒý_F¦B!„x¶Hƒ]hõ,M;®y }Ó[š¢8 pd¡©©[6ofò”â–NÛmNžöôÒB!„(Ò`ZåOóëZùB¾^ÇÔYóÓæˆƒhàñ”ÁA£GÑ©cnݾEºÚ$ º»ŸúÔÊöööìÞ·Ÿ9óðr½ºT¯VMkÙùÓ[Wvq){hØ7>z”ù³ÿ{–­ aô¸‰|¦:·Å_.#hÌ(‚ÆŒ¢ªûã$ùSŠ;;;³tù †Ž Ÿ·X´`YYÙL™1‹•kÖ25x¢YqëblYùÓK+„„~ÍÈ ñü°1}¹œÛ·ï°.d™Y™Ì™·€!!…¦€B”,ëV¯zÚ! ]#¹†¢(Èc…VÏÚ´ãêtMomìÅÚ¦¦Î/×”)Å‹rÚîçazi!„B˜Gî° ƒžµiÇuÅnìÅÚ¦¦.¿SŠå´ÝÏÃôÒB!„04Ø…QžµiǵÅnéTÜÊÔºîñÚ¢œ¶ûy™^Z!„æ‘.1¢H< ÓŽ[:·)Š2îgmzi!Ò32x¤ç/@#ùeÛoOäX¦ßÈ0¾Ù°±(B+VÚλ(ój)mñ=+¹}R å###ƒVm;w=wî”â¾æše=ÉúdÎçX“f¾Š²|ÍkUñšJìÂ"ÏÒ´ã–NÅm câÖ7U÷Óž^ZK¬ßÀ' ?{&õ¬Ìñ$slmñ=+¹}RLÍGI¿æ–(îs³´|Íkõ4®…t‰yÖ¦·d*nS·¾©ºŸæôÒæL.ÄóBæ‹(>’Û‚$ÏŽ’p­´µR¬ó–R€mÞ¢È[Je€–©)?© …B<9–Ìg±‰•!k€Ü±*½zt/ôøÐ€À‘T®\™˜˜h‹æ Ðv¬qcFœ·@}Nˆ””†ÃkÛóîÁ…æ‹0”‹ììlBÖ®cçî=¤¥¥ÑîÕW‰:sš% x,,@·7ßæãSUì/^ºÌûc>àÀ®ªcuí܉ÝûöñÏ?ÿ£º‡ÁãÆz‚–®ޤzµjÄ\¿®5VSæc0ô^}yÑŸfnµÍ{ñ¬Î1kÎ'(s”Ì™9Èí¢ñFŸþ¼Þ¥3Œ@ZZº÷ä»ð0¦<§@>²³³Y½v¿ïÙCjJ*­[µbÇ®]lÙø-û4ëšç3f>m×Gýµ¡yL6}ÿ?oÝÊ»÷ðòªOð¸¨äì¬÷غꋡz /_êŸ=]ås>ÚrcÌwœ>¥ËLŽT -oÉÌ[²eÞ¢"wØ…Bbî|ïø÷'-5Øëqª†‹6E1o€®c;Bvv6Sgýµk×äÝ!ƒÍÊÅŠ5ü7ê4ŸÍŸKGGÖoˆ 6®ð#pµuû‚Çç6¾ØÄ˜ Áü¼9‚2eÊ{žÄĤ¥iï"aɼê4eÊÜ -[¼Âð€!Ìž¿€Ø¸Â“­“‹n~]X°h1]¸À½{I¬ûæ[ïoèåÅ/Û~#1ñ‰7nðÓÖ_ ½'4l=‡!))‰Ð°õ¤¦¥Ò¾­¯Áó6Ä”¼šz ´15¾¢<öÓäêú.•œÙ´y mZ·r»Ê4¨ïEhØz|´ô_ãê’¹9óæQmès_¾\9ÚúúòùÒeDÇÆ’’–Fä‘#¤¦>2êØšçf¨˜úÙÓ,ßÒyY´]‹‘Œcõ×a¦\“Hƒ]!„I&Á»UK>œ>“ï’üàaù ºvîDC¯ú `úì¹ZËÈŸ7 Ï ÁÄÄÆš7`È@–|±ŒŽ¯÷`TÐ.]º¬µÍc©ÏÐgÐ`FFê»!àá™œÝ IDATA4iÔˆ)3f˜5sáÄ ±4kÒ„ S¦1èÝ÷HÏÈÀÚºð-Ä1#ßÇÅ¥þC‡1vÂ$ܪ¸RJãi-š7eùªÞòÄù?ÿbÕK´>±Â˜k;WcójÊ{µ1'¾¢:öÓöªwîÝ¥aƒúªuí|Û˜xï-tî§^—¿@µªŸ&cINù\ø÷}›ßwïaÊŒYZ_úÜOŸLMOÞÄoõeãwßóàÁ}£Ž­íÜ ÕCù2T¾¡óÑG[y’“q®X|ݸä9ìB!D¹s÷.Ý{÷aÿÎí& f…ÂϽB<;:wïÉ'³g©æYÐÅÜç°Ëv!„¢ˆ\¾r…ªîULn¬ !ž]ñ dfeÑÈËËð›Í$O‰B!Ìt-&†˜˜Xš5iÌí»wYÊÀþýŸvXBˆ'¨´BÁ¢OçaWŒ¿¨Kƒ]!„0ÓÃ䇬 ßÀÌ9ŸPÙ¥½{ö¤WîO;,!ÄT¡Bš6®P¬Ç>ìB!„B<Ò‡]!„Bˆç4Ø…B!„(Á¤Á.„B!D & v!„Žä—m¿™½zF†Y“•”ò-‰ÃÈ0¾Ù°±HÊ×¼–^—g¶œ>ëç‘‘A«¶ˆ»nÚlº–Ös¥RÉ¢/—Ñ¥G/ú ÂÕk×Xóu§NŸ)²cˆ'GìB!ŠÔúð |²ð³g¶|KâhÛÆ‡:/½ô”"zö•”k[Xš‹­¿ýÆ©¨3l [˪eK©Vµ*{÷ïçÂ¥KEv ñäÈc…Bˆ"2â½wŸvBÇËuêàìì¬ZñMØÓ HXDî° !„(äðÑãøJG¿nŒ?‰˜Ø8Õ¶no¾Íɨ(Õë‹—.Ó¶“á›Xþ-»÷îǧC'>[òEr333ùbÅJú DÛÎ]é;h0Ûwî*ðsÊW*•¬ß°‘¾ƒóZ·7˜0e* ‰‰ª2Gòõ7áޤC××ywäh.]¾Â¦ïÀpýºñá´$%%§®8´ußÈ=ÆP:w琢˘<è3íãÙ|² àÑo6Fðá´ÖÍšó 3fÏQ½ÎÈÈÀ¯go¾\ù•j]ZZm:væz|<#Ù¾scÇO¢£_7Žÿ÷”Q±Ždó–ÿ8z,ýº1lÄh.\¼¨Ú~ìÄ GÒ®Ëë¼=`+W‡:'}u'*ê ÃFŒ¦½_7ÞögÏý¡Ú–™™É²•_Ñ«¯?~={3ÿ³Å¤¦îæaj.Œ©Sš¹ÈÎÎfÕêPzõó§s÷žÌ[¸¨@–äÂPLù>ý|17϶ßǧC'Þöž*æm;~7˜oQòÈv!„…ܺ}›¹ÏB¡p $ôkFç‡á888èÝïÿþ¤¥¦{=Ž93gÚnkkKUww̃½½=»÷ígÎü¼\¯.Õ«U3—®òCþáðѣ̟ý88سlU£ÇMä»ð0lmmøï©(¦~8ggg–._ÁÐÀôïó‹Ì#++›)3f±rÍZ¦O4§¡ó̱‰»ö0kÚTœ+rúÌ9*”/oq^kßž…K– T*±¶Î½÷yø½ßìYà}¾>­YüårÕë3çÏ“™™É¡Ã‘|0jDîºsç¨ê憻›‹¿\FИQEUw7£cݺ}Áã? Š«+ßFlbÌ„`~ÞANLž6“ Ñ£èÔ±·nß"==Ýèk p=!àñàZùB¾^ÇÔYóÓælmmYôårn߾úUdfe2gÞV„„<>È¢\¬þ:Ì`ÒÌÀÊ5œŒ:ÍgóæRÆÑ‘õ"TÇLN~hQ.Œ©çS&MÀ±tiîßÀô>,T¾¡|‹’Gî° !„(¤WnÔ¬á‰[•*L›Œ••{ö(’²ßêÕ“žž¸»¹1dàܪ¸ò×…‹†wÔ!##ƒßmfÊÄñÔ¬‘[SHIIáÐᣪ÷ùuîDíZµ¨èäÄÀ~ýÈÉÉa`¿~¸U©Â‹ÕªÒ£«çÎ/²8³³³ ßÀä‰ã©[ç%\*U¢ókP(—ߺU =JW½ÿÞ½$.]ùßÖ­ ¼Ï»e $'s5:€cÇO2d ?·ïÜ#6î:'O¦µw+Õ>ÆÑÝÏZ5k¨~A3&Ö>½{ÑÐË —J•=ŠŠNåÙµg/·nß"3+‹ÖÞ-)[¶ 5<=©W·®ÑyèÑ­+õêÔÁÉ©Cúsçî]â®_'%5•_~ÝÆð¡ƒqrª@e‡p òp¡2LÉ…±uJ3Wélùñ'> ž@íš5©âêÊø±£Uï·$ÆÆ$žOr‡]!„^vvv4jàEttL‘”—””ÄÎÝ{9ûÇÜ¿Ÿ»÷î’nÁ“*®'$’••U`°§B¡ ~ý—¹­uê!‘´´4êÕ­£u»%åÛÛÛÓ¦u+"Å«þËD=J‹æÍp,]ºÀûiÚ¨§¢ÎàY½:GŸà³ys¹xù2GާßÛ½9y*Š Ñ#Õʶ³8VkkkÔ÷"&.Žž=ºÓ¬qc ÀÇÛ›7ºw㕦M:Omª¸º¢P(HMM#&6¥RÉ”™³°Ê›¼=+;‹ÔÔ‡…ö3%ÆÖ)Í\Å'$­TR§vmÕ:õ)å=ªW7;æÔsñü;ìB! ²³µ-ð'÷œœ³ÊIM}Ä»#Çpëöm†Ì‚ys©U³V¡÷™R~fF:J¥’ìììB1ÛÛÛkÝÇJëºÇkSŸ‡“Ü~ÇšŠ¢ü×Ú·ãàá#Œ{®Pw˜|¾>­‰:sŽ£ÇOàãí»ÎÛ›óþÁ¡#Gy¥YSJ•ÒýwccMII-ðúÏ‹—ðôðP½nÚ¸3>šÌš•Ë8y˜[·ok=ž¾œjªâZG…‚ȼ_\ 16æÖ)Õ~j]«´1'ÅQÏ5!J.i° !„($âû¸xé2÷î%±lUÊœlÚú¶ ¡—¿lûÄÄ$Þ¸ÁO[-°oåÊ.œ>{žÄĤ©u1pv®HJJ ÿùé’’’ø}÷þ¾òO÷˜Z¾£BA×_gá¢%\¸x‘»÷î±dÙrœ*T Å+ÍÍ:câÔwžåË•£­¯/Ÿ/]Ftl,)iiD9Bjê#£Ê/_¾< ‰ª¿6h¾¶·³£Ok–|±œÆ âèè¨õ\\]_À¥’3›6o¡M^£ÞÑÑ‘õ½ [Zÿuss¶žC‡””DhØzRÓRißÖ—ÉÉüº}·nßæÑ£GD9‡B¡ \¹r…Ê0”SM¥J•bà€þ¬XʉS§P*•ܸySë/I¦äÂÜ:å¨PÐͯ -æ¯ ¸w/‰uß|«ÚnI.Š£žkË÷”³ØdVy¢øHƒ]!D!Í›6fòô™ô4˜˜Ø8V,]¢º ;fäû¸¸TÂè0ÆN˜„[WJ©u—éÚ¹ ½ê3 €é³ç(·zµjŒÈêuaô4˜ƒ‘‘´hQ°±aNù‚Æàݪ%NŸÉÀ€wI~ð¥Ÿ/ÀÊÔÛÖ&Ä©ï<óMŸLMOÞÄoõeãwßóàÁ}£Ê÷ïû6¿ïÞÔ³´¾èؾ'NÒÙ&ß«>>ܹw—† ê«ÖµómCbâ ¼[´°8-š7eùªÞòÄù?ÿbÕK°µµ%99™½2xx ]zôâç­¿2ö,ìí ÷•7&§šÞÄþ,ùb_ïÁ¨  \ºtÙâ\˜[§&¥Y“&L˜2ÁïP­jîd,ÍEQ×sÍc(•JâuÞñO¶+l·”lóEÞR(´LMy¸øI)„BˆÂbbã0t¿ÿò£Î;ìOB@àHÞìÙƒ7º½þÔbâYPÚ±Ìà8ðHÒò–̼% Pæ-*r‡]!„xFˆŒ¤yÓ¦Oµ±.„(~Ò`B!žQ»÷î£}Û6O; !D1“»Bñ Š‹çÊßÿàëãó´CB3éÃ.„B!Ä }Ø…B!„xIƒ]!„BˆLìB!„B”`Ò`BQdfÌžÃÒå+T¯Ó32xôèÑSŒ¨è•´s É/Û~S½ÖŸÿa|³a£Ùe Ýþm¹ÒV¿Jj222hÕ¶q×ãŸv(“»Bˆb³>|Ÿ,üìi‡Q¤Jú9i‹¯mê¼ôÒSŠHžMi…‚i“ƒUë¾ÙÁþÅÂOæh=ïü:f̵h×Ö—‡kÍuvv6«×®ã÷={HMI¥u«V:÷¬‘»BˆbñŽÒRÓˆ½Çœ™3 mON~Èäi3 =ŠN;pëö-ÒÓÓM:ÆÖí;ŸÛpù6bc&óóæÊ”)cp{hØ7>z”ù³ÿ{–­ aô¸‰|†­­-‹¿\FИQEUw7Z6oVèœL=ÿžŠbê‡qvvféò Aÿ>o±hÁ<²²²™2c+׬ejðD“r†snJîÔ-úr9·oßa]È*2³2™3o+BB 5ÖŒ)»ª»; æÎÁÞÞžÝûö3gþ^®W—êÕª©ö×Ì»­­­ÁýV„¬á¿Q§ùlþ\Ê8:²~C±q× ÄeN¹ÆäêzBÁã?Àµò „|½Ž©³>æ§ÍªÚ?pØ0ºûùQ«f  ßM6ç<ü:w¢v­ZTtrb`¿~äää0°_?ܪTáÅjUéÑÕsçΛ”sÊ]¾”ÔT~ùuÇÆÉ©•]\ÀÈÃf•ýV¯žÔðÌÍùp«âÊ_.Ø_[Þõí—žžÎ?þÄGÁ¨]³&U\]?vt¡¸L-ר\õèÖ•zuêàäT!ý¹s÷.qׯ]7²³³ ßÀä‰ã©[ç%\*U¢ókP(×UÍõ†®§¾XŒÑºU =JWåðÞ½$.]ùßÖ­ îk̵ðë܉:/Õ.”ëôŒ ¶QžUfßa ]ÊÜI˜"6oádÔ):_µÝ˜ kî <óüÓ¼ÆëÃ7uÇèI(©õÏPŽ,ÍaLl£ÆMäÝ!ƒùèÉìܳ—ñN!tå2jתeIèâ_Ê£zuš5nÌ€¡øx{óF÷nªnæ°¶¶¦A}/bââ n¿žHVVVϲB¡ ~ý—¹­ZgooW¬çááQ€Gjw]==«“š–fÔþEE_îbbcQ*•L™9 «¼ Ò³²³HM}hVÙIIIìܽ—³üÁýû÷¹{ï.é7´å]ß~ñ d+•Ô©][õ~mS¹›Z®1ç£©Š«+ …‚ÔÔ4êÕ­cT݈OH$--÷ýš,­«šë ]O}±ÃÞÞž6­[yä(^õ_&òèQZ4o†céÒ÷5õZ¨çÚØ:ð¬2»Áî¨Ö ·³·ÃÆÚGGG“Ê0wŒ žyþ•äk\’c+N›¶lÁ·µ7þ}ß`ÈÀ\º|™ˆÍ[˜9uÊSŽN<‹¬­­Y¶äs¢ÎœeÛöL™6“fM›èçš““cR™6ÖÖ8Øk¿®¾=3#¥RIvv¶êÏöv¶¶ØÛÛùy袭Aa¥e­©y0‡®Ü•q, À×_­¤¢““Ee§¦>âÝ‘cèÐöU†Lå^`|ðdƒûÚ/++ ¥RY †1ÌÇP=³²Ê½^ÆÖ‡“Üq666¶e]Ã×S_,Æz­};BÖ†1â½w9y˜ŽíÛÜÇÜk‘ŸëÌŒ ³êÀ³¢ØÏ(*ê ÃFŒ¦½_7ÞögÏý¡Ú¦ÙÕàØ‰¹ º¼ÎÛ±ru¨Ö2ÍÙ/33“/V¬¤ÏÀA´íÜ•¾ƒ³}ç.qŽdý†:cW*•¬ß°‘¾ƒóZ·7˜0e* ‰‰öß¾scÇO¢£_7Žÿ÷”jý×ß„8’]_çÝ‘£¹tù ›¾ÿÿÁtôëÆ‡Óf””dVÜú[Öá£Çñ<”Ž~Ý;~1±qÊX¶ò+zõõǯgo涘ÔTÃÝ,fÍù„³Aeddà׳7_®üJµ.--6;s=>¾À5ÎDµ{ï~|:tâ³%_¨öÑW¿ò…†­gаádgg¹_ o¼Ý_wì0+¿šõ/;;›•«CéÕן.=z1ÿ³ÅôøŽê¹¯†ê’:}uY_îõåHßvCõXÝž}èÔ¡}u:tÔûgq! ·1¥OÓÆ˜ñÑdÖ¬\ÆÁÈÃܺ}…Âèk1z÷MII-ðúÏ‹—ðôð0¸Ý½jUΜÜõD©TrñÒejyzšuNºÎÃRÆäÁ˜ø4Ê]¾*®•qT(ˆ<|Äèãë*ûâåK$Ý¿Ïèxzxà¨P`eÄmPCû¹¹»pÆÄ®DÆÆcl®t1T7ÜÜÜP*•\¸t©Ð¾–ÖUM†®§¾Xòª_­Z¶äFb"W££9}öœQÝaÌ­ùTyzÝÉž†bo°çÄøOÄê×™©³>&33³Ðûòíôx½+[·lfá'shÿjƒå»Ÿú`†akéÖÕ9ó«³ìü Úb û†½û0öÿ±~ÍWØÙÚ2zÜÄç¶øËetéò!+–ÑÈ«¾j}þ€£-7àîV…¡#¸qó‹ÌcÝšâ®Ç³rÍZ³ãÖÅØ²nݾÍÜg¾.”Š4^Õ÷yїˉŽc]È*¾ !>>ž!!íëÓšSQgT¯Ïœ?Off&‡G>^wîUÝÜpws+°ï;þý xg¯uhÇá½» r2¦~ 8€ì¬,6ÿð#kÖ}M­š5èîçW$ù]²†c'NòÙü¹„­ù +k«BôÕ¥|†ê²¾ÜëË‘¾íÆÔcÈízÿþ}ÜÜ ^›«U%%%…”'üç{ñì¨\Ù…ÓgÏ“˜xƒ4zò 9™_·ïàÖíÛ²¨®jcèzê‹´×/Í:hogGŸÖ,ùb96,ÐcäãXýuX¡¸Ì­ùÌ­ÏŠbo°ëˆ¡ÉÜÁG¦ìgÌ`uº6X:ÄÔG¦Æ­1eõêÑš59˜šž¼?&ˆ7ÞêËÆï¾çÁƒÜïVsëª.†®§¾X´Õ/Íúб};Nœ:U¨;̃ädœ+îŠcnÝP§^¿@µªnöz6<ÑÇ:ªÐdî Sö3u0ƒ®Ø‹t°’Ž,‰[“©eÙÙÙѨÑÑ1 mç¢/7šeZYY1 __ôë«ëÔŒ.ûÿþ¼ãß_羺ònh?¦LšÀ”I€Ü ›¿W}g™[.è?måîÝþ¸Û¤±u£lÙ2Ìšö‘ÖmæÖU]ë ]O½±h©_šõrÿO+Uª¯úìsëÖm^|±Ú˜S7Ôs­YÞ>LgyÏ’'þöüÁšÌ´cì~æfÐ{Q14à¨(â¶´,;[[lmm-xäëÓšS§£ðõñ†%UÝÝxÕ· ÛwìįSGâhܰÉåªÓU¿ÜÝsûåÙÛ=þk‡¥ù5w “¶8õÕå¢ô¥É”zìXº4Ž ±qqÔPë3™@ùråt>îN!ž–ËW®PÕ½J‘ý¥C˜æ@d$Í›6-Ð&>!̬,yy=ÅÈžM%n­¹ƒv ígé`uE=DŸ¢ŒÛè²ÔžF““Ã_.RÃÓìGê|}ZuæGŸÀÇÛ;w·7çÿüƒCGŽòJ³¦”*¥ûwHcQér-&†ð |0jŸ/ý‚‡sïL[š_s:飭.›{C9Rßnj=öõña§Æ3š÷8Hû¶¯<'!„(n×bb8y˜””¢ccYÊÀþúâ³{ï>Ú·-8¦°´BÁ¢Oça'¿D™¬Ä4ØÍ´cì~–fPWÔ@ô1&nÍÁº¶›ƒˆïàâ¥ËÜ»—IJU!(s²iëÛÆ¨Gúbqu}—JÎlÚ¼…6y#ÆiPߋаõøèé¿nì *m”J%s?]È ýЯ/õêÖU=ÆÒüå }uÙ˜ÜÊ‘ævSëñ€þ}ˆ>|ÿã4lðø©9í|Û°`ñR¼[´Ð™‡®;qäØqФqÍÿÄènøn3©©i èÛ€IãÆ2`h_ëHó¦M,Ê/ärYº|%¦LÃÆÆ†.¯uôtÒÆP]6”{C9Ò¶Ý”züRíÚ,Yø)_…®%,|uj×bÙâÏð¬þ¢Iç)DQÑÕ?רíÿfÅ™›§•w¯ú/³.de‘—+õÈtÕªºqd¤ˆ\" IDATßî§ÆsE[‹Â:o)Øæ-м¥4Ph™šòpñ“ RˆgÉ»wéÞ»ûwn—¾“B!„P)íXfpx¤iyKfÞ’(ó•Ó%Fˆç… tB!DQ*1]b„xV]‹‰!&&–fMsûî]è$„Bˆ"%wØ…° tâéHÏÈPÍœ/ p$¿lûMÇÅ/##ƒVm;w=Þ¬í¢øh«/B<+ä»*®NBýÖ‡o öz\¡Éš„ÐFê‹x–Év!„B!J0¹Ã.„¢MßÿÀÏ[·rçî=¼¼ê<º¢T* ØÄ¶í;¸{/‰† ¼TÛ ·KJß·{óÛößùëÂæÍMËæÍt®ÏÌÌä«5kÙ³ÿÒÓiÛ¦ A£GQº´ƒÞXvïÛϺðÜ9öî?H¯Ý Tà¦}<›Ò Ó&«Ö}³1‚?þüËà,Ú™™™¬\½†È#G¸yë/Tv!`ð;tíÜIõžììlV¯]Çï{öš’JëVç“0´ý؉„„®ãjt4•œ+Ò¡];F/K@àH|Û´æPä¢c£ñôðäÃñã8}ö?oý•›7oÒ¬YS¦O¤B… FÅ8’vm}9pè0W¯]£ª›“ÆѨ¡—Ź+.úêKhØzö<Äú5!ØØØšúˆþƒ‡8< wŽ -õE[½lÚ¨¡ÁÜé¢ïzޤkçNìÞ·þùÕ=<7–zuëu½@÷çÒÐçÈØz&J.i° !„( ·‘ýmÄ&ÆLæçÍ”)SÆà1õ}.õåÅÔz&J&é#„B%;;›°ð Lž8žºu^Â¥R%:¿Ö…BAFF¿ÛÌ”‰ã©YÃw77fMBJJ ‡U•8lÝýü¨U³:×§¤¦ò˯Û>t0NN¨ìâBàðD6‹1Z·jÁ£Géüuá"÷î%qéÊßøæÍ´lŒ·zõ¤†gî¹8·*®ªòÒ32ØòãO|<Ú5kRÅÕ•ñcG«ö5´ýÖí[dfeÑÚ»%eË–¡†§'õêÖÕ‹_çNÔ®U‹ŠNN ìלœöë‡[•*¼X­*=ºúqîÜy£bW/³ÎKµqrªÀþܹ{—¸ë׋$wEÍP}±µµeòĉ„® ãÈÑcüöû.¦O2X®¶újLî4s=ûôîEC//\*U"hô(*:•gמ½©ï³`(/¦Ö3Q2Év!„*ñ ‰¤¥¥Q¯nBÛ®'$’••E—^R­S(Ô¯ÿ2×b¢UëìíµÏA ¹>&6¥RÉ”™³°Ê›Ç/+;‹ÔÔ‡c1†½½=mZ·"òÈQ¼ê¿LäÑ£´hÞ ÇÒ¥.#))‰»÷rö?¸ÿ>wïÝ%=ïI#ñ d+•Ô©][õ~õÙ m÷¨^f3`h>Þ޼ѽ¯4mjT\Õx¤v§ÔÓ³:©iiFÅ®MWW ©©iE’»¢f¨¾4nÔ€N;0iêtfNL¥JÎËÕV_M͘~=­­­iPß‹˜¸8ƒÇÔ÷Y0”Kê™(9¤Á.„BåáÃd”J%666¶ef¤£T*ÉÎÎVu“°³µÅÞÞÞäc•q, À×_­¤¢““I±ëµöíYƈ÷Þå`äa:¶okô¾©©xwä:´}•áCSùÿٻ︪êÿã/PÆSq2ô§82*¨ˆ¸Å•6¸1#g82MSKM³rå ¥@Í‘Ù4ÓJMœ‰¨•£o%¢bŠ+².¿?€ãŽs.}?ûxxÏ9ŸÏçýùœs¯‡ó9÷¼kÔ`ò´éºõi©©hµÚ<·äfj½µµ5+—½OTôivíÞÃŒYsháÙ\Ñ=âúÒ”[åZj*vƒõZeêþ]˜±+ ¦Ž—®®.hµZìlí ncŒ¹cgÎþ,cm½½É6}LKaŽ3QrÈ-1B!t\\²NvÎ]¸P`kÍšDŸýï¶ ­VËù ©ï榺-g§ê8h4DDVKŽôôt£m´ööæŸë×ù;&†S§Ï¨º¥ãüŠܽwñc‚p«S«\gʺñÈuJn¦ÖçðlÖ”Ù¯Ogýš•üÉÍøxÅ1š»…»¢`êx¬Dv›6oå•qcxù ò¬7u¼@áÇÎØþLLLʳíoç/àV§ŽÉ6}”Œ‹©¸DÉ''ìB!t*V¨€Ÿ¯/ï/_ILl,‰ÉÉD>LRÒ4úôìÉ»K–qîüyn߹ò•«p¬T ¯V-U·U¶lY† Äêu¡?y­VË?7nèNJŒÅP½z5N>Ëõëÿœ}+HÅŠ‰‹»NffÖ•b;[[Úù´eÙŠU4kÒÅñU©R™ÄÄD¾øêîÞ½Ë÷{÷ñ¿?þÔ­wÐhèåßÅK–òû¹sYO"Ùø‰âõÿÞ¿Ï·»÷p3>ž}FC… T¥ÚØ•(ÌØSÇ‹V«eÁ;ï2tð @£§žâƒ5êÊë;^ô1wì”ìÏÐð Š<ÌÝ»w ß@Rrý|M¶iì³`j\LÅ5cö\6mݦngˆ‡Nn‰B‘ÇÓ§±ôƒ•¼4|òIÕm›[®(íüî;NFE³%ü#¬¬­©ðÄ|¼a±W¯0Îl“åÛ·óáÉõ-ˆM› ´›ÌôÅ»ÿÀ4å4´hÞÌ"q!„âÑ%WØK°µ³¥ŒuÝ{¬­MïÆ1/½ˆw«–ªÛ6·\Qº|ù O7lH•*U¨ìèHÙ²êþî4šVžžE]Á1ÓïÖá 4°Èb˜✵³tâáÍré›-´´ü}‘cÄ|Æfb Q2#œöøSgi™=ž=o>ËW­Ö½Ws€1r…ýÍW;wñ÷¥KÔtqáÕIÁ4mâdxÏöíÃ3½zpôøqBBÃø;&†ªU*Ó©CÆ.P§9åÒÒÒX³n=‡sãæ-jT¯FàðaôèÖUQ?ÒÒÒøpýGì;p))øµkGðøq”+gÏ;ï/åëow°ûÇ©[§ݺv&lÓ'ì?ð3ýúôfÚä`ƒõçïS¯g_àÍÙ3u'ñç/\äå ¯pðÇ=Fû¼ië6½íæ®__¼›>^O`ÐX^x®½ü»›ì3@FFë> ãû}ûHJL¢mëÖŠÇRɾˆß² {{{“±‰ÒÇ!× yîY;5Ƽôb¡ã°DâáÉ=[ø°È1òpéÛÇ[7†_@BGNØ!}zõ QÆŒÀWßìäÊÕ«¸Õ©“g»›ñ7IKO§možx¢þp ŽŽ•ÈësÞ*–DsÇJ S}NIMeÇ—_ñáª4¨W€ÉÇóÕ7;Õ¯d_ôëÓ‹zuݘ5}Ï e߃thï[¢ö‡x¸ŠbÖ.·ÂÖ¡d)0h,ü|9x(Ro? ÕkhV)4|~>Ćõ!”)S†¤¤ >‚ ÑtïÜYQ<¾íÚr(â01±1¸ÕqãµÉ“8uú _ïü–7nТ…'3§M¥R¥Jº2=ºueïO?ñçŸQ»N¦MšH£§žR¿1Z­–M[·±k÷nß¹K“ÆL›ô ÎNNg ÍÝ/Jå?FLíOsú>wþÛh3µº /©©©<Ó=»wã•qcHNN¦kï¾|º)œ7ޜπžã»Ýßóû¹s,\0ϦMí{cûÑÔú¢š‰Í¡tFØ”¢Ž3§Ò0{¬o&Þ\rÂþˆrvrB£Ñ””\`]ÚµiѬƒGâÓ¦ Ïôî¥èžn5åîÞ½Ë{÷sú×_¹wï·ïÜ&EÁ=\—ccÑjµÌ˜3+¬HÏH'))ÁdÙ¢`îX©aªÏ×ââÈÐjiØ ®Œ•ŠúÕî [[[š6ö &ær‰Ûâá*êY»ÂÖ¡téØñLŸ2‰êÕªíGc³J#† fßþŸØþù— xõaS¿^]zûû(Šç—“QÌ|m*UªTaùªÕŒ àþϳdñBÒÓ3˜1{.kÖÄÌiSuevîÞôÉY'ÏŸlÝÆ„)ÓøzûVÊ—/xÁÜY±ÐðD9¢yoaooÇʵ!ŒŸ4•O7…+ž-T³_ÌelšÓw_Ÿ¶,ý`•î}ôÙ³¤¥¥q(2BwÂ}æ 5]\puq`é+ ž0Žà ã¨éꢸϦö£±õE5›CÍ>6¦¨ã„Ò3{¬o&~î³ÌªK~tú³²ÊÔ»ÜÚÚš•ËÞçýE‹°µ±eƬ9¼6Ëô­$JË%%=àű¸Ïè‘ÃY¼põë){*Ky‡¬{"?þp _~º…/?ÝÂÎÛÙ¿[Ý?RSSñéÔ5ÏëÌÙ_ nŸ™iÙ±RÃTŸÓRSÑjµh³ï9VÃÜ}akcƒÅö‡(rfí+1bH·nßæÊÕ«¶Ë?U×ÍÍàÕ_CÌ­ãù~}©ë憫‹ #† ÆÅÙ‰ßÏϳ·®4|²É~À3^£GÇѱÕ«U#ht #"¬…éS§Îá#Gùîû™9íUÕñ4¨_ŸÊŽŽ 8ÌÌL† ˆ‹³3ÿW«&}zøsæÌÙVŠ“\aŒy6kŠg³¦ 4€Á#_äf|<ÕªV-t¹ó/p÷Þ=Æ Ò-³RxIØÙ©: ‘‡y¦w/UýIOO×ýÛÖÖ–Èý?**§ÑØsé2^-ZÜÆXŸs·kS}v­™5}}æ,-=›«ª[ñ¾ÈõKff&¿Ÿ;O»¶m µ?Ä£¥(fí,Q‡Ú$cýe³|Íš6¦kçN¼:ó æÌœNÕªÿÝï«6ž:ujð ×l‚›[m’’õÇY»{pùʳâ×çjÜuÒÓÓóüÀS£Ñàîþ4—.Ç-«¹³¬jåÞŸæöÝÁÁϦM9[íÚ9vœ÷.àüÅ‹>zŒ/<lj“Q«+cgg[ µ}6¶ó¯/ê™XKy˜q>n³ÇrÂþú÷þ}~ŽˆÄ»UKž(_ž¨è3h4*T¨`‘rUªT&11‘/¾ú†NÚsì—“üï?¡«þû+V¬H\Üu233)[¶,CbõºPœœhÙ¼97ãã¹}çŽîþ|}ªW¯Æßìäúõ¨X±‚¢§\ähâáÁ7»¾Ã×§-XÁW;¿UÜç´›ÃTŸ4zùwgñ’¥¼õÆLœœÙþùëË=žJ÷ÅÖÏ>çÉ ¨Q½:›¶nC›™Ÿo;Eû#w{VVV̘=÷§1,`ê±%›©Y»¨èÓìÚ½‡³æÐ³9ï¾=_qÝæÔ‘3ƒÔɯ=£G§zLž6Ýì~@Þ¯ÊŽŽ·suuA«Õbgûßý®æÄ£ïdÅJÁ)Lkkìí Þk«4þüÒRSÐjµdddäyT°­ vvvŠëó÷‹¹rö§©¾§¦¦ÒÑ?ï…‡µ+–Ѥ±¾>m9y* _Ÿ6©¥¦« í}Û±{Ïøwí̵¸8š5il0sûlh?æ_oªo¹gb•<깨<¬8Ío}³Çj>'ÅIn‰y Ý¿Ÿýføè º÷éÇ×;¿eѼ¹ØÙ¼b`N¹Úµj1~LëÂÂé?t8?GDàåeøYî^àû½û˜1{.Æ2bHËV¬¤sÏ>Œ žÂ… ÆÖ£[Wšx¸3807æ-P8Y&Œ}™jÕª0r§¼Š‹³e³ïm5Õç´››©>O žH‹æÍ™2cÃ_ʺZ^«¦‹Þºr§Ò}ÑÒ³ÓߘCÿ¡Ã¹{…ÕË—éžoo*¶ÜíiµZ®Å]çf|¼Ùc!J/ÏfM™ýútÖ¯YÉÏ‘fjêÈ=ƒäV§âÙº™¼³ÿÝŠ£Õj9á"õÝÜTÕU”ã`Œ©¾ç̼æ~5iœõcU_Ÿ¶DEŸáÈ±ãø´i“µ¬MÎþö+‡¡U O£9?”öÙÔ~4´ÞTßrÏħ‡§âcLÏìq]7Óãii…‰¹Â^ê ÀðÁ–‡­[[`YîûŒs¯wuqaé; µgn¹aƒ_aõnÕ’/¶mÖ½·²²bðÀ 8@ïö³”›â«yÚL-Öeþû[µ²£#K/ʳÍð!ƒÓ}Ö×nþ}¡/Þüۘ곽½=3^ÂŒW§è–½>|öå—4iì®[ÖÁ·‹—.§——ѲJûll?šZoªoSƒ'²|զ̘…MYzûû癉ý÷þ}ªT.üíù÷‘ÚãÏTœJÛU2Þ9³Ç‰II4kÒ¤Àì±±8s··hÞ›\‹»NõêÕTWn]9|ôƒiÞLÝïÐrÓ÷)´Î~•l²_šìW9 <à”˜°ÔìV…(&oÜÄÁC„…¬-Öûü„B©üÏ"¥“©ýXÔû¹[ï¾¼=o®ÅM,Ô)çP~ p H’€äìWZö+Ðf¿täŒE<6222¸pñ¬^¶DNÖ…B<6®ÅÅ‘–žNSà ÃDÉ&·ÄˆÇF™2eX¼à­âC!„x¨Êi4,yg!¶*nS%‹œ° !„B<Â*Uª„g³Jņ(¹‡]!„Bˆ‡@îaB!„â$'ì¥Àk³fóêëoX¾bÍZzö{žÄ|)¬c¯\¥mÇ.ü{ÿ>#F±qóݺ”ÔTäKÝ4–ov}GqÉß¾¾ó÷Cm…‰GmÛB!„–$'ì¥@ëV­ˆ>s­6ÏìŽ !1‘ãÇɳüä©S<Õ°!žx¿v>4|òIݺ ›6óö»ï=”¸Í¥/Æüýx˜Š³m!„B9a/¼½Z’ÀŸý¥[KòƒdztëFäá#y¶ÿ%ê­½Z0æ¥ñV™¥®$*Î~<*c(„RE=ëfªþÔÔTZûuâÊÕkE›¾Ùò×õ05s>çùûN²DýJÈ {)àêâB­š®DEŸÑ-;zìm½½ñóõ!âèÑXELìÂBÖ²14„k×®±:$ĬŽ?Áô)“ôŽ—±¶îßO`ú¬9ôéÙƒ;¶óîÛó騾Ùq!J™+Z2¾ÊÉX=z䄽”híÕŠèÓ§ÉÌÌ$%%…³¿žÅ»UKìlmñjÙ’È#Gøåä)Z¶ð¤L™2ªêïÓ«6Äѱ#†pëöm®\½ªw[ÿn]iP¿>•2p ™™™ 8ggþ¯VMúôðçÌ™³…î³)ýŸëGªU­JðøqTv¬ÈûöØ.1)‰o¾ÝÅè‘Ãqt¬DõjÕÈÁˆH³ÛöïÖ•†O6(0^¦Úº“´ôtÚ¶ñæ‰'ÊS×ÍFO=evB˜ËÔL±Y7­VˆÍ[0t8]z=Ô3‰»~]·^ͬde!^».”~èÖ»/ ß]b4öÈ#Ç>’Îþ½˜8ùU.Ç^Ñ­S:›¦o6/--«×ÐÈPüºõ`ÀÐáìþáGƒq$&&0<6lÔÏÆedd°f](ýнO?½·”þC†évÓãªtæÑÜÙV53•¦¶566jfZwÿð#'¿Jgÿ^ûå¤ê8K‹¹óßfö¼ùº÷©©©ø÷}ŽÖ|¨[–œœL»ÎݸzíZ±2ö+ìì»ÚÏ>¦¾S€ì™ü‘tëÝW·ÞTÛ†úfêÚ”=T IDATQúd¨~%ýQK'•žÍš‘”œÌ¥˜þ¹qƒ† ž¤|ùò´o×–mÛwðòèQür*šÖ…ü«ÚÙÉ FCRR²ÉmëÔ© Àƒ”Ý27·Ú$%›.kIÖÖÖ4v÷àò•+Ö]ŽE«Õ2cÎ\¬²S¤g¤“”¤ÿj¼Z¹ÇËT[ujצE³f ˆO›6<Ó»­<=-‡JåÌôG×θ“”\ŸaøoÖÍ©z B>cæÜ7ùjûVlll ßHä‘#,š÷ööv¬\ÂøISùtS8666ªãY²žQ§xoáÊ;8°aóV£ÛߌgÁ›sÑhì ý˜±Á“ù|Ë&ìííYòÁ*âão²–´ô4æ/\Ìê³uÑœ”LìÕ+ÌŸ3[·¼¦«+‹ÌÇÎÎŽ½?`þ¢Å<Ýè)jת•§|FF3ç¾EƒõxqÄpƒ±æÌÆU¯V­À8®YÏ/Q§xoÑý޽¢ÿB‰R;wïaÚäWpvrâ“­Û˜0e_oߪûÿÂXßÁø~W:¶€¢m ±øò[úÁJ‚'Œ#xÂ8jºº(n»´ñõiËÒVéÞGŸ=KZZ‡"#xeܘ¬egÎPÓÅW—å}ÆÌ=rØØØ(þÜbê;eÓÖmüðã>æÎšI•*•9}†J+šlÛPßL#J¿“ Õo¬?æ’+쥄F£¡ic¢¢OsøØqÚ´öÖ­kצ5þý7qׯ} / LƒYYe*ÛNﲂK33•ÕWe¬­±·³/°¼¼Ã|üá¾üt _~º…;¶³·å~ð’3^¦Ú²¶¶få²÷yÑ"lml™1k¯Í2þ’–¦d¦ÇЬ[jj*[>ÝÎŒ©“©W× WæÎœAbb"‡"hѰ”ÔTv|ù¯O›BƒzõpvrbòÄñFËôëÓ‹zuÝpqvfÖôiXYY±ïÀA‹Ì¦=߯/uݲú5bÈ`\œt·êdf²äƒ•$&%1kúkFë34—’’Âç*û­„Ò™GC íw5c«t[Cc£FШQôö÷§~½ºØÛÛÉŒjIÐÆÛ‹ïßçï˜ ëwl#†ëŽî¼'OѶMëeÍùŒåP:û®èsc€©ï”ŒŒ Â7mfúÔÉ<ÕðIªU­J·.Ðh4fµmê)Ìx)é¹ä {)â}ûÿûïÌK·¼bÅŠ4öxš°ŸP©b½]ç–žž^Ô¡æ¡ÑØsé2^-Z(.£$ÆÄĤ<ï;‘C þ±âìT†ˆÈÃ<Ó»—âÌ¡´-ÏfMñlÖ”!ƒ0xä‹ÜŒ§ZÕªE›9ÔÎôäžEºwôôôFë¨^½_|³“ë×ÿ¡bÅ º¿P‹R¾Ùõ¾>mÁ ¾Úùmžõ+V$.î:™™™XYY)Ž14|5]]hìþ4;¾úš¤ä$:úù¨³lÙ² <ˆÕëBqrv¢eóæÜŒçö;4jXð Í®Ý{˜1k-<›óîÛó –É™EJKMA«Õ’‘‘µõ“´¶66ØÙÙéÞ+UKKME«Õ¢ÕjóÔ§†­ 666yf¸*;:ª®')é/Ž@'¿öŒ9œê5j0yÚôÛµôô$ær,Û?ÿ‚q/¿¤ªœqLOO7«ßjg+ Í<*¥oöÐÔØš»”ÎìEÛ¥¯O[NžŠÂ×§ dj©éêB{ßvìÞóþ];s-.ŽfM(g‰ÏX}ûHéçÆSß) ÷¬ûÂóÿ>Ïœ¶M#…/¥ß‘jÉ-1¥HƒzõÐhòÜ“Ã×§-Z­V÷üuCztëJwòƼEjƾLµjU 9ЉS^ÅÅÙ‰²¹î ðßïÝÇŒÙsUÅèÕÒ“UkCx>`(gûµ+–éî«Ë_gà°¡ŒÀ²+éܳã‚§páÂE½õæ/«–±¶îß¿Ïþƒ?3|tÝûôãëß²hÞ\ìlmÑjµ\‹»ÎÍøx³ÚB-ÏfM™ýútÖ¯YÉÏ‘ŠŽ=ך5¬{hshµZÎ_¸Hýì 9³jJèêSóCõ\'­™™™ü~îçÉ ¨Q½:›¶nC›™Ÿo;Õ³iùgóªT©Lbb"_|õ :´çØ/'ùßB×®Êz{µbtàæ-ZL¸[]jÕ4~+¢¾qTÛoSã ÆgõÝÔl«š±U»ô1w6Øm—TNN5¨Vµ Û¶ï`Æ«S¬[e»{¾ÁàŸ•k…™}Wò¹É?sÿ;ÀØwŠ••~¾¾¼¿|%óç¾AÕªU9uêžÍ<µ­¯oÆŽµŸÍüõ+ùŽ4‡\aBˆÇŒ±™%¦O Mko^{cC_äþ¿ ,±î2µ³jSƒ'Ò¢ys¦Ì˜Åð—‚Œž·ôlÆô7æÐèp.Ç^aõòeº+‹jfÓòÏæÕ®U‹ñc‚XNÿ¡Ãù9"//ÃÿÁJó¦M™1{¶Y™s÷{è‹/‘’š €µµþË“¦ÆŒÏ<ë»jÆVͶúf6¸°m—dí}|¸uç6M»ë–uðmÇõëÿÐÆËË`9SŸ±ÂŒ·’ÏMþÏ|þ÷¦¾SÞ˜>znuxyB0Ï4|òIÝû ›6óö»ïcD_þ1x””¦ýYšb}\©ý¬<Žû´¨¿O䱎BñóÒ‹ÅB±“1Bù¬˜VÔc$'ìBñÊÆ~ÓÖm„mú€ý~¦_ŸÞL›üÐcJKKãÃõ±ïÀA¤¤à×®ÁãÇQ®œ½.æ/<Çw»¿ç÷sçX¸`Þ-[˜,gHî18zü8!¡aüCÕ*•éÔ¡ã‚F›ŒyͺõD>Ì›·¨Q½Çѣ[W“ý5Öž’±èàçËÁC‘ü}é5]\xuR0M›xÜŸ…©3ǶÏ>çë;¹uûîL›ô ÎNNfïC±jµZ6mÝÆ®Ý{¸}ç.M{èÚ2&0h,=ºueïO?ñçŸQ»N¦MšH£§žÒ­×w kï·æ£±³cÖŒ×tílܼ…ßÎ]`ñ‚· uüù¶kË¡ˆÃÄÄÆàVÇ×&OâÔé3|½ó[nܸA‹žÌœ6•J•*1ëÍy”Óh˜5}ÚqlÙʯ¿ýλoÏ/Ô¸˜ïüŸsŽ¿‡­4~Ÿ#·Ä!ÄcnXÀ ‡ ¥K§DîÿÑâÿ¹¦¥¥“œœ\à•ß’V{…°µl áÚµk¬ ɳÍÒVÒ½{BV¯¤©‡»âr¦Ü¿ŸÀôYsèÓ³;wlçÝ·çÓ±};“ålll¨éêÊâóÙþ½zø3Ñbbbc Õž’>;~‚éS&ñÅÖ͸»?Í̹o’––fp¦N@wB7wÖL6‡„—.TªXQqÝúŠ54|#ûdѼ·Ø°þClml?iª.cvîÞı/³í“ 4voÄ„)ÓHHHЭ×w k¯[çN:r­ö¿Çbÿy˜n;ªï¿œŒbækSÙ±e3®.ÎŒ Ã?7þaÉâ…„­áÊÕk¬Yÿ]:v$âÈ‘ÙGÇJŒÀ­Û·¹rõªÞö [gFFá›63}êdžjø$ÕªV¥[—Nh4‹íƒ©©©lùt;3¦N¦^ݬq;s‰‰‰Š9;9¡ÑhHJ*x¥Ñu^‹»Nrr2žjh‘º¹wôôô>m°··çÜ… ë{:µx’¢[ææV›¤ì«Çvvv´kÛšˆÃGðpšˆ#GðjÙ‡råT·•{\,1Þ¦Ž?KzÔ¿O ‘v!„Å®¼Ã|üá*;:y¹ü¬­­Y¹ì}¢¢O³k÷fÌšC Ïæ&ï NJzÀ‹c'Ðɯ=£G§zLž6½Pí™Û'+«Lƒë [gBÂ} ë^ç2eÊX¤nCÒRSÐjµddd`mýß¶66ØÙÙ©®¯Œµ5öv†ï?VÒ^×.X¶b%ã^~‰ƒ‡"yö™>€eûn¥wYÞ¥]:v ä£pƼô"?GDÒYáí0ú䌋¥ÆÛØñ÷°•Öï£uš]R!Ä#%==½ØÚvvªŽƒFCDäá‡RÎÏfM™ýútÖ¯YÉϑ܌7ºýù‹¸{ïãÇáV§ VúμT´g©>åÞŸ…­ÓÅÅ­V˹  ¬³D¼¹cu­Y€è³guË´Z-ç/\¤¾››Éº“ò¼ÿíüÜêÔ1¸½’öZ6oο÷¸øÇœ¿pïV-˦´ööæŸë×ù;&†S§Ï(¾ KaÇÛù>Qÿ}bŒœ° !„ zõjœ:}–ë×ÿÑý€kÆì¹lÚºí¡´_¶lY† Äêu¡?y­VË?7nè=A´D¹üþ½Ÿowïáf|<< *ú † *-W¥Jeùâ«o¸{÷.ßïÝÇÿþø³PíY¢Où÷gaë¬X¡~¾¾¼¿|%1±±$&'qø0II ]wþX4úôìÉ»K–qîüyn߹ò•«p¬T ¯ìecBÃ7p(ò0wïÞ%4|IÉItôó5¸½’ö¬­­éÔÑ÷—€Okolm³n¥°Ôñ§”­-í|Ú²lÅ*š5i‚ƒƒƒâ²†Æ¥°ã­|Ÿ˜÷}b46³K !„xdôèÖ•ÃG180æÍšóÞÛó¹wêÕ«=´‡ ÅÞÎŽe+VrýÆM*;:2,` ¼oÚår»ÿ>ûþÌêu$%&ñµj±hÞ\ìlm–«]«ãDZ.,œµ¡¡xµl——é“Sí¶Où÷ç’EoºÎ7¦Océ+yyBÖ#"6¨Oýºõ(WξPuë‹uJðV‡¬ãµ7æžžŽw‹–,1V ¦/¼Zz²jmñ·náááÎÚ˰±±1ZFI{Ý;wæ³Ï¿äÅÃó”µÄñ§FçŽxmÖlæÎz]U9cãR˜ñÖG¾OÌû>1Fßž°Î~•l²_šìW9 <à”˜°ÔìV…Qý‡ %öÊ5ƒë?ýdoÎ_˜çyŸùŒEn]>d°ª¶Í-g jÛÎÿÌÓüRRSÉÔj±·7þìT€€áôîÕƒ!¨ŠYi»ùû¦ÕjY¶j5?ü¸J+ò΂·Ø»ÿžÍ›Ñ¢y3³ÚMMM¥}Wvlù„š®.yÖ™«üÔnoéòBaŽÇá»çrìÅ÷ß|©ø ûã0.¥E9‡òS€c@$g¿Ò²_é€6û¥#WØK ðÐõýœÕ­Ûwp"ê$KßY¤[¯ÑhLÖanŠÜâLÕmé¶7lÚLìÕ+ÌŸ3Ûä¶íÛùðdƒúEÖnþ¾íüî;NFE³%ü#¬¬­©ðÄì?pM9Ù'ìB!}#"héé©êvQúÉ { äë„ÜÖΖ2ÖeT0ÍM‘[œé‡‹³í±…È>¦Dþ¾]¾|…§6¤J•*ºe[7†i B!J¿½ûâ¹¾}Š; ñÉNK±¨¨hFOGÿ^ õ§Ïüª[4–ov}§{ôøñ¬TÂÝ{òÂ࡬Yª·NsÊ¥¥¥±bõúŠ_· :œÝ?üh0îÀ ±ìþáG&N~•Îþ½8öËI½mgdd°f](ýнO?½·”þC†qåê· ƒœÔÈ{÷À§SWÞ[¶ÂèXæo»×³/p"*J÷þü…‹øuõ79.†ÚÍ]ÿ;ï/eËöÏØõý÷øtêʰQ/é¶Ùµçû<ãºr͇ô€ßçXôÞR’’þ{¶sFFk×…Òo`Ýz÷eá»KŒö1w½JöWä‘c Igÿ^Lœü*—c¯ä©ÃXlB!,/öÊ5þøßŸøúøw(â!“+ì¥ØÕ¸8¦M~§ê5ù8Œ™sßä«í[ ü¸&'Enðøqtí܉›ñ7IÉ•˜Á¥år§æ¶³³cïO˜¿h1O7zŠÚµjé­{é+ ž0Žà ã ÜocuÈz~‰:Å{‹PÞÁ ›·{%o5Cc0,`ÉIÉŠo‰QÃØ¸(iwÆ«Sp(WŽ{÷þå×_3ØÎ’V‹°µ¤¥§1ábV‡„èÒ<¯ Yω¨S¼·ð¿ñQBéþºÏ‚7ç¢ÑØú1cƒ'óù–MØÛÛ›ŒM!ŠCغµÅB‘ªUÓ…Ã?íU]îQ—Ç\a/ÅúôêA£† M¦67E®šrjSsçOœ_JJ Ÿù¯O›BƒzõpvrbòÄ‚™Í”Ž%EÊáüL¥GNIMe‡‚ñ1DÉþê×§õêºáâì̬éÓ°²²b߃OC.„Bãä û#ÂXZ`sSäª)§65wþtÀù]‹‹#C«¥aƒºe¦.õ°R#EÊáüL¥G6g|rS»¿lmmiÚØƒ˜˜ËOC.„Bãä„ýb(-°¹)r•–375·1éééhµZ´ZmžTɦKœššJGÿ^y–­]±Œ&=ônŸ™iÙñTÃTzä´ÔT³ÆÌß_¶66ØØØX< ¹B!Œ“[b#æ¦È5U®°©¹õqqu úÌY[—;5²­­-‘ûÌó2t²®ÑØsé²ÑºKaS2›J¬K%mÆø(Þ_¹þ`ÉÌÌä÷sç©ëVç¡§â¥SJj*òÍÚäÿqwi£¯O%ÕìyóY¾jµÞu­ý:ñÛïçrD¥Ó£x듚šJk¿Nyê u=œº”’öÇ€¹)r•–375·1 ½ü»³xÉR~?wŽ;wî¶ñUuèK¬T¾ÙõׯÿÃõþá«ßêÖ™—´›ÃTzdµãS±bEâ⮓™™©xmýìsÎ_¸È;wY¹6mf~¾í¥nÎÝ<ܔԢdذi3o¿û^q‡aQbŸ„q²ÏEI!·Ä<ÌM‘«´œ¹©¹M™<‘å«Ö0eÆ,Ê”)C÷.°¶Vvù^_ºk¥&Œ}™ï¼KÀÈQT­R™>={P6ûé;¦Æ¥0íæf*=rîñ±±)KojÕÔÿÄ€/°xÉ2þºt‰Å æ)Ú_-=›1ý9$&%ѬIV/_FÙ²eÅ–»½EóÞ|è)©…BˆG‰¾3ëìWYÀ&û¥É~•ÊÞI‰ KVBܺ}›ÞÏõçÀ»Mþ±¡Öˆ—^¦ÿóÏÒÛßßôÆB”riii¬Y·žˆÃ‡¹qó5ªW#pø0ztëªÛ&0h,ü|9x(’¿/]¢¦‹ ¯N ¦i“¬ÛÈ´Z-›¶nc×î=ܾs—&=˜6霜شukBÖY¿ùè×§7Ó&4–ÚµjqùêU½u¦¥¥ñáúØwà RRðk׎àñã(WÎ^Ó€žã»Ýßóû¹s,\0ï–-òôíèñã„„†ñwL U«T¦S‡ŒËNŒ¦¤~C}6Ô§ÂÔ™cÛgŸóõÎܺ}wÝ8šªÛ˜ÙóæS¥re&M(øô¨Ö~øhíjÜŸnT¨qWŸ¡~;–rÚ÷m×–C‡‰‰Á­Ž¯MžÄ©Ógøzç·Ü¸qƒ-<™9m*•*URÔ'cÇIŽ¢:Žs3G¯g_àÍÙ3u58á"/Ox…ƒ?îQ|l’‘‘ÁºÂø~ß>’“hÛº5{~ü‘[>¡¦«‹É}¢¦.5ãñ8ÄUΡüà$ÉÙ¯´ìW: Í~éÈ-1¢Ô¸øÇÔtu¶øÉzjj*—b.ãê¬ÿê´šÜÏâßþ½zø3Ñbbbcólwìø ¦O™Ä[7ãîþ43ç¾IZZ¡áÙà ‹æ½Å†õbkcÃøISIKKcXÀ ‡ ¥K§Dîÿ1Ïóùsr'è«sÉ«ˆ‰½BXÈZ6††píÚ5V‡„ä‰ié+éÞ½ !«WÒÔÃ=Ϻœ }zö`çŽí¼ûö|:¶o§[¯¤~C}6Ô§ÂÔ èþ“Ÿ;k&›Ã?¿K*U¬¨¸ncÒÒÒINN.ðÊÏÜqWŸ±~;–rür2Š™¯Meǖ͸º832h ÿÜø‡%‹¶>„+W¯±fýGŠúdê8ÉQ”DZš8Œ1vl³&d=GŽŸà½… Ø‚½&ïIª’}¢´.5ÇÉã—¹ä„]”X—._æçˆH‰‰eMH(C ²x;Ÿlû”:µÿ¦~€*Ä£Hɳøý»u¥á“ ä9HMMe˧ۙ1u2õêfÕ1wæ 9yÄh»†r'(}¾¿±Ær$(­ßPŸõ)l„oÚÌô©“yªá“T«Z•n]:¡Ñh,’ïà󯾦£¯/súÜÕÄg¬ŸJ%ÿn]iP¿>•2p ™™™ 8ggþ¯VMúôðçLöðMÅf‰\…=Ž-‡šã5‡©<j>ߦêR3C\…!÷°‹+á~a›63gþÛT¯V•çúö¥_ŸÞm###ƒ ÿÇêeKT?QˆÒLí³øsç9¸wôôt>ù¤n½F£ÁÝýi.]ŽQCî:•>ßßXc9ÌÉ`*·Caë¼wääd=ÕÐ"uç7¨ÿóo‰QÛNþqWŸ±~šs,Õ©S€¹2o»¹Õ&){öÀTl–Î¥aÎq\Ôqc*‡š}bª.uÇÉ£WaÈ »(±<ÜŸ&,dM‘¶Q¦L/x«HÛ¢¤1÷Yü9yÒRSÐjµdddäùC×ÖÆ;;;U±äÔi‰çûË‘`nýÆr;¶Î„„û@ÖïÊ”)c‘ºÕ2·5åŒõÓœcIßï¬r-5[QäÒ0ç8V‡¡| ¦â0ÆT5ûÄT]jÆãqˆ«0ä’¢B¨)g¬ŸJŽ%K÷IMn’¢<ŽMÅa,ˆc_™ÄºÃ ,7•ÇCÍ>1U—šñx”ã²ÈgµP¥…B”:–È0%x«CÖñÚsHOOÇ»EK–¿¿«ìKõæä#0õ|SLåH(lýúúTØ:ߘ>¥¬äå YˆlØ >õëÖ£\9{£ukµZ‹å70·jÊë§©cÉÒ}R“›¤(cSqˢĿ÷ïS¥²þÛ=LåñP³OLÕ¥æ8yã²ÔgUžÃ.ŠÍk³f£Õfòþ¢y–¯X³–ïØËg[?ÁA£Ñ-½r•ÃF°ç›/yyB0=ºuaøÁ@Ö¯¸3µÚÙ@c÷FL˜2„ýÉR ›ºjR_¥þÏõ£‰‡ÕªV%xü8*;VäÇ}û lg‰ÔåùJsý0R} !„B?y¬£(VžÍš‘”œÌ¥˜þ¹qƒ† ž¤|ùò´o×–mÛwðòèQür*šÖ…¼ßZiÚf0úúa±¶¶¦±»—¯\)°Î©ËQ“nÛÒ)¶…Bñ9aÅJ£Ñд±Qѧ‰‰¥MkoݺvmZóöâ÷ˆ»~¨èS¼2îåB·§$m3˜N}CmÚhs”±¶ÆÞξÀò‡‘º\iºí¢Hõ-„Bˆ,rKŒ(vÞÙ÷±=vœvmZë–W¬X‘ÆO¶ñ*U¬€«‹‹‘ZÔ¥¶sÒF+‰111)ÏûßÎ_À­NÛ=¬ÔåjÚRšê[”.ý‡ ¥µ_'ƒ¯˜ØØ?bÎ/`Ä(6nÞ¢ºmsˉ’ÇÔ1"„0LNØE±kíÕŠ#ÇŽ’’’J]7·<ë|}|øv÷¼Z¶2Z‡ÚôÑ–`*mtÅŠ‰‹»®» ¯4ÆÐð Š<ÌÝ»w ß@Rrý| Ô©6¥xþxÔ(lªoK¤eÅ'˜*—žžŽV«E«Õbm­|’ÝÜx å‘È¡47†;¹%F!D±0÷¹ý¦Ê¿x»÷î1~Lnuêà Ñ`¥ï2²Jrøú´%*ú GŽǧM›¬emÚpö·_9tø­ZxR¶¬þëc†ò.˜ÛSå\²Á}æ¬éÊTÔkª?BˆÂ‘v!„•©çö¶\•*•ILL䋯¾áîÝ»|¿wÿûãO³bU’ïÀɩժVaÛö´kÛȺU¦±»¡áð1pÿ:λ`nL•sÐhèåßÅK–òû¹sܹs—°Ÿº^SýQBò5a˜Ü#„â¡2öÜ~K”«]«ãDZ.,œµ¡¡xµl—WK³ãU’ï ½Ÿ}ù%M»ë–uðmÇâ¥Ëiãåe°nCyÌ탒rSƒ'²|զ̘E™2eèÞ¥3ÖÖ†/á+ÇX c$_ƒÆÉsØ…BˆbPRò.ܺ}›ÞÏõçÀ»MþÑdLIé%™<‡]!„ª]üãjº:êd]Q´ä–!„â1réòe._Ž¥EófÄ߾͚P† TÜa !Œv!„â1’p?°M›™3ÿmªW«Ês}ûÒ¯OïâKa„ÜÃ.„B!ÄC ÷° !„Bñ’v!„B!J09aB!„¢“v!„Fõ2”Ö~ ¾bbc Ë7»¾3XGÀˆQlܼEuÛæ–+j)©©è;~ô-êYêøš=o>ËW­Ö½7µŠú»Jž#„¨ðÐõ ÍúýÓÖí;8u’¥ï,Ò­×h4&ëðkçCÃ'ŸTݶ¹åŠÚ†M›‰½z…ùsfw(¢ÒwüÈ1U²™Ú?Eý]%'ìB!ŒrÈuBnkgKë2888¨ªcÌK/šÕ¶¹å„âa*êï*9aBaQQÑ|µs_ºDM^LÓ&@Á´õG'$4Œ¿cb¨Z¥2:t`\ÐèušS.--5ëÖqø07nÞ¢FõjFn]óÔÛÁÏ—ƒ‡"õÆ«ÕjÙ´u»vïáö»4iìÁ´I¯àìäĦ­ÛÛô ûüL¿>½™69Øä¤¥¥ñáúØwà RRðk׎àñã(WÎ^Ó€žã»Ýßóû¹s,\0ï–-ôމ±Øµ3wþÛh3µº«„©©©<Ó=»wã•qcHNN¦kï¾|º)œêÕªY$fcŒµ’þfddòQ?ìÝGrr2Ú·'*úËÞ]LMW‹{~‘GޱõÓíܸq“§5bÚ”Iü_­š&÷¾ãÇÉ©†Þcʱ¥G·®ìýé'þüó/jשôIiôÔSŠ?+ùÛðlÚÄd9SûÅÜzõ'‡±Ï¡9Œ}æsÇeÎwœRr»B‹¸ǴɯðÅÖ͸»?Í̹o’––V`»û÷˜>k}zö`çŽí¼ûö|:¶og²~¥ålll¨éêÊâóÙþ½zø3Ñbbbcólwìø ¦O™¤7ÞÐðì?pEóÞbÃú±µ±aü¤©¤¥¥1,`ÆҥS"÷ÿ˜ç?ncc°äƒUÄÄ^!,d-CC¸ví«CBòÄ´ôƒ•tïÞ…Õ+iêánp,ŒÅn¬_Ÿ¶œŒŠÖÕ}ö,iiiŠŒøoÙ™3ÔtqÁÕÅÅ¢1bl¬•ôwuÈzŽ?Á{‹¾þC¬¬­ˆ½rUW¶¨úp3>žoÎeSX(•+;26x²îgcmê;~ S–Š}çî=Lû2Û>Ù@c÷FL˜2„„ÅŸ•üm()gj¿˜[¯±þäPú]¤”±Ï¼>æ~Ç#'ìÂl+×|Hÿ!CMn·lå*úJJJÊCˆJQ\úôêA£† qt¬Äˆ!ܺ}›+W¯ØîfüMÒÒÓiÛÆ›'ž(O]7·hÔ(zûûS¿^]ìííÿ¿½ûŽ‹ºþ8þY( †–nSqkîÌr›Š©å(wšš–3s‡#Ôœ9Z¿,K+G.påH+E+¨ˆ8Öq÷û8ïð¸Êûùx|É}¿ßÏúÞ]o¾|¾ïO¶õd×vSõ4jÈ£¸8®\»À±ã'د1÷îkƒ©“§ÎÐ$ q®·ÙsÇ:»þ&''óíw;xâ8*W¬ˆ·—cß©=//ûЭK'*V(·7S'MÄÆÆ†}š]§)¹ÙöÝ»QËߟ’%J0zäŠ{¸±gß~À¼ÏŠ¡:ŒgêºX[®9ýó¿‹òеßqÆÈ”‘çÒÒÒHU¥¡V«M,„x.x{y¡P(P*ŸØWîÅ©_§}@×Îx©^=“eZrÞƒøuï~þøóO>|HìýX’dxÐmïͨhT*•Þd …‚5ªs5òš½²ÌÈë×Q«ÕLž>›ŒEÆUi*”Êx½sÌ.ßšz\\\¨W»6§NŸ¥ü‹/rôø ÌÍÅK—?vœ^¯wçä©ÓŒ9û?íþ™ÉS§S¿^]>™3Ëhyæž§T&ñæðQ´jÞŒ!ƒPªtiÆNœdv{SS’Q«Õ¤¥¥akûøÑöö8::š,ÇP™®.EX÷ÙJŠ{xXTFnר„SgN5e|}hÔ”Ý?ÿJû¶­¹EZ5‰Š¾“§mëÇ:³¿*• µZZ­Ö;?S^».{{ìíís­Î¼l{[[œ¬þ¬˜:ÏÔu±¶\SýÉNvßEyÅÚï8£eæbû,²aíöíÚɾ];2h µkùkÞ·k'e}}sTþÆÍ[˜óÉ‚\jíó/°U[ƒÿÖ©T©­š·Ðþ¼pÉ2B×­·¨Œ‹—.QÕÏ/Û2Eî³4-—©ïù2®^Ú|ðþ$Ö¬ áБ0îÆÄäÊy/EðàáCF¾=ŒòåÊá¢P`cèö^6|ˤ?8xöüyíkjµš‹—¨T¾¼ö5•Jev™Þ^¥pQ(8n~C¬`N=AM8}öGŸ 0 ýµ€Îÿõ'‡ÃòRýzØÙÙ=•6›;ÖÙñɈΞ;opžöA£Ñù§†¿/\¤Bùrf×ièý£ûZn¶=!A©÷ó_#(_®œÕŸS発.Ö–kª?yÍ’Ï´éÔ•wÆNàÂEý¹f†æº_¹ɸIïór—n¼Ò£7‹–}ʬyóõ)x–9Bï‰ô T«âgä }÷bc‰‰‰¡ªßãà1k™"÷½=ôM½Ô ¿›ñÜ{Ç»ænL IIIœ>{…BA±bÅråžöÑ,ŽŽLüžöøM[¶ò×…æÏþȬ´eæ~ÞL¥û2'}œî6cu›Jó•Ý~Sm( âââØð+BW£LPòBٲ̛9GãsqÍ=ïŲeùö0V¯ßÀªµkiØ > Zö‹Ø¸Ñ£Xºš÷¦MG¥RѨ~–.œMÆí¾íÚ~ì8}ƒƒ©[§.‹æÍ1Yfðýqrtdɲ¢ïÜ¥¸‡oôéE5?ó™7‡9õ4 äëï¾£VÍÇYEZ5eþâ¥4l˜ã6?Š‹Ã³¸ái}z¾ÎüEKøïêUæÏžir¬M?ú–._ɸÉS)R¤/·i €­­Mžõ A½:Lš6¥’:µj±béììì̪ÓÐûÇÐk¹õžiØ ËW…sïþþ5Xµl öööVVÌ9ÏÔu±¶\cý1E­Vs+*šR¥Jš<6+K>óÖ~ÇchÔl36;À>cSdl΀+ÐH™¿ØêZ³Ø´uÇŽŸ`å²%z¯¼h 11÷˜úÞRU©Ìš;Ÿ^(«ÍM:àÍ¡tíÜ™>=_gÙŠ•\‹¼Îâùé«ï­þ|½Ñ©6oÛί{ö1uÒD<=‹sæì9‚P(|»ã{êÖ®…££#{;@èÚulÛ´^;§>xØp 'FA©’% ]·žÃGÂØñÕ¶'Þ0ÁÆcckËÔ÷& P8ºv¿Ÿ9Ë·[7ãääd´OS`«¶„íßóÄ¿ Yùûä»/·j¿X“SRè3 o/–/Y¤=îPؾޒ¼Lš6èÛ·YºJû—•JÅk}úÓ²ycF=ù$yV­:tD©L¢šŸ^^¥8v•JÅÂy³µwŒ>Y²”ÿíøJ+P¶Œ/‡Ž„“––ÆgŸ.£NíšÚrtç°*aáG©\©¾>Þ„;NJJŠEsØ×¬ÛÀ?ÿ]aþìøûÂFÏÞŸ~Ôö7üØqœœœx±l¢oßá½iÓy£Ooí/,k7läÒå´óݲ–qé2¦LeôˆáÔ¯[—®üGQW½;ò9}‡¬üŒ“§ÏðÁûïáêâÂÆ-ÛØñÃNƒsؽ cî‚Eìúîmÿ‡ŒEŸ¯Óºe “ŸK?oª´4&ŽM€¿Ø¶wÿÂ÷_mÃÕÕ•Õë6vô(ÓߟŒ““#!«B¹tù¾Ü¼{{{ƒ»±ºM}ÏÚoª B<Úu~…93gäøA;kÜ‹¥s÷øuwޤüìCn*(ÏÒåÖu)(ý±–³‹ë8à8(ÄŒ-5cSêŒM«ÀÎ;1•ÎÈÞÞžIãdzvýÂc×/{˜2q‚Ye§¥¥±aó&KU¿*”,Q‚vmZi—×ÎI:0Cr#õ“Z­fIÈrº÷îGÏþ˜¿x©v_÷Þý˜öÑ,^ëÓŸ>‚9xø°ÞÏý}€˜˜{Œ?‘®¯÷¢ý+ÝYñÙj³ÆË{û"zwAx¥K'Îÿõ7á‡ÿlóf~Ä”÷Ò¯ý×ß}Àí;wØñÔ/WŽ «?cÞ̘4n _lÿÒ`y‘×o~¯Ò¥Yº’g}ĸw-ÀóÂ¥KTõ{üdü…ˆKT©\Y¯¿M7¢^ÚxzzR£z5üªT&%5EïÝà[·LµZÍ3g1aô;´iÕw^ªWOïxÈÙû89%…oÌHɦ?«¢R©øóï¿ô/í+ÿ]!Ђ´q–|Þ²K÷emª>Kê6%'é…xVÜŠŠ"U¥¢¶þLá»tù2e|½sæwžG¹q] ³;%ÆœtFujפmëVL˜2éS&Q¢„§YeߊŠ&11‘jU ÿI)'éÀL±6õÓ‰ßçÏ¿/ðÍÖÍØÚÚêå4¾}›e P¶Œßÿø#³>^ÀæÏWãUº4_~ó?–­XÉê!xx¸óÞø±øúøð(.ŽACߦYP 5kX¾Ð…1e||HNN&>>¢E]õö%(•ÄÅÅçÊïööÚ ¸uËé‹+DFðïWP«Õ4nô’öO”mZµfî‚E\½vÕ`yW®¦¿žùÀ€[17‹Ûqé2=»wÓþ|1âU³<ÈxóÖ-ö8Èň>|Äß#xUg:ÏňK¼Þ­«Á2Ïž;OB‚’ À@£íÈÉûØÜ”\`ú³jooOËfA ;J-Ž„‡€““"",NfÉçM7ÝWn¤êËiz°ÜJ(DAæ¬P°èã¹8<¥Àìjd$‘‘ש_·1±±¬ ]K¿Þ½sTæÓîÃó(/®KaV`vsÓùúú V«qt0ÿîl||~§²H‘"zûršÌÖ¤~z¡lYîÞaÁÒOiÑ4—t–¶±±¡l™ô) mZ·&dÕjí|ض­Z°ykú¼ç"EŠ’’º›ˆ¾sµFMLL¬Ùí6Wìý¸¸¸<¬¸8;ãììDÔíè\­3óûŒ@;11=0MKKÓ9& ›lS쥥¥ÿõÉÙYau;bbîqïÞ=ü*ë܈ Ÿ^ÚŸO9Ëœù Пw†¿]^멽CžYFÕŒ‡T³–ùûé3T®TÉèƒÙ9Ok—bvJ.sÞÇmÛ´bɲF¼5”ƒ‡Ãxµk³Ï5ÖNsd¦ûÊ­T}9I–›é…(¨ÜÝÝ©WÇý©ÕÏúÍ[˜>k¥J– û+¯è=Ïd§Ý‡çQ^\—¬ÀN‰1'ÑÕÈH6oÙÆ»#ÞfáÒezËÒBöéw||Òƒ|COZç4˜A9LýàãíÍ7[7óR½zü°k7ƒ† 7¸‘}–_@ìtæÄF\ºÌô™shØ £GÈ•?õ%&¥è-÷«ÑhØýë™óW£juvþ´‹””½óR,\681)‰äŒ2Ž?‰F£Ñ¦u*_îÂÂi ?~FCåŠõÊQkÒÇ1óAàÌyë Ê‹ÚtñR¥K•ÂÃ#ý‹>9%…+W¯Q¹b%í1ë6n¢×ë¯Ñ¥c¼½¼¸ríÅ=<(Y¢„Á2²þüèÑC4ê4ŒÉµ´vf¤ä2ç}Ü n]ÅÅséòe.F\ÒfbÉ‹”kÙ¥ûÊiú¸ì˜Jó †ð IDAT¥»?¯Ú Daæ_£:ëCWrà—]|õÅ&‹’ëW¯Ê—ùÞyu]ò«?ù­Àì¦Ò©Õjfü ýûö¦o¯žT«Z•OW~¦=ßXú·bÅhÄÂ¥!\»~„ÄDŽ„‡£T&å8˜!9Iý”)!!¸¸8ZµhÆ´I¹~ãñ –“—ÿû7·bT«ê‡­-Ñwnk÷ÙÛÛ?¾K­óoSi­bbbxgüöìûCGÂ?y W®^eä[C³=çí¡o}›á£Ç²wúy“¦MçVT”Þq¦ê~ðàƒ†¼Å‡³ç1aú®}{ö Bùò4jø7oÝbÐa|8k. —~ŠƒƒÁÞЖáîæÁýû]»ooj×òçú› 6œ³æ°hYÈõk×ňËzsÉããâHKKãêµkÚ÷á»w9÷çyîݻǹ?ÿdUèZªêLÏúïê5Š+¦ý…,k™~UªpæÜyŽŸ8IrJ çÎÿ©]RdÝ3¶,¨)µ j»Ä³ŸîK!Äóí¹Kë(òßÓLku!"‚øøjf,âQPSjÔv QÐõ8˜M[¶æIÙÉ))$É€ô,KII¡qóVܸy+ÏëR«Õ,ú4„—»t£WÿÚÌYÖÈkbMÁÆóÃO»ò¨EBäž›%F俼Jk¥Ñh˜¿h uëÔÆ«TinFÝbõºõtîÐ^û@hAM©UPÛ%DA×¼i ^:ËÜ´qó£ X óìܵ‹S§Ï²uÃçØØÚZ<íRW~\yˆç™ì"[y•Ö*%%…"EŠºv÷bc)[Æ—×_í¦}!/ëΩ‚Ú.! º·‡¾™ßM&DFÞ ºŸžžæ­i"„xz$`O£££vÙy!rÓúÕ«ò» Ï”í_Ë÷;wr/ö>þþ5˜8æ]¼½¼P«ÕlÞ¶ŸvÿLìýÔªé¯ÝéÓ‚š6áð‘p®]¿FùråyoìÎüqŽïwþÈ;w¨_¿S&ŽÇÝÝ]{ŽîóÁÆӢy‡qåêUÊøø0aÌhj×JŸn–––Fèçëùuï>iѬ§ÏžaÉ'ó)ãûøáçÍÛ¶³~sz£ýÑ­Kg&Žm²™RSSY¹z GÂùs÷¥K•$xÀth×V{Œ©¶f-ï³5Ÿ³ïÀA’’“iÞ´)£GŽÀÙÙÉì~¯þ|=¿ìÛ‡2AI“ÆÍ¾ž^}?˜¢}¾æbÄ%Þõ.÷ül²î.æû`÷ž=T(WŽÍëÖ˜õ^èùzwvíþ…¿/\`îì™\º|Ùà5ÉIûL]§ìÞ¦®‡®©ÎÄY¡`꤉Ú×6mÝÆŸýÍ'sf™}„È 2‡]! ¡Ì lÆÔ)lÙð9íÛ´ÁÝ-=sÔÚ ›Øà óf~ÄÆ5Ÿá`oÏÈ1ãõÖ\øýÔi¦¼7žo¶nÁ×Ç›AÃÞæöÛ,š?—õkB¹qó+×|n´ ÇOœdÒ¸1üoÛjԨΔjëXº†c'N²`Þl6¬ù [›'Ò—¼Ñ§7Áoô§M«„íߣ½`N =m__æÏžÅÖ ŸÓ©CûôU“¯_7»­º}ºœk×o°>t›Ö†rëÖ-V„†š]ÖÊÐ5=q’sg³qm(N ó4GvuOž0޾={Ðéå— Û¿‡ÍëÖæãâOCxùå6„®¡¶l¯INÚgê:eW§9×#S›–-9rô¨Þ'GÂÂiÕ²¹…£,Dî“€]! ™´´46lÞ¤ñc©êW…’%JЮM+ )))lýò+&KÅ åñõñaÆ”É$$$p8쨶ŒöíÚR¹R%Š{xЯW/4 ýzõÂÇۛʖ¡K‡öœ3±ðVûvmñ«RwöëýØXnܼIrr2ß~·ƒ÷'Ž£rÅŠx{y1ö‘f÷ÏÜ>dz­Û+T(Ÿ~ÜÀ~}ññöâï Íj«®¥’~ü‰!ƒàááN©’%6$˜ƒGÂÌëwJ ßä ßæ0§™ÌÇaƒÓ¹}{*U¬íJÒ¹Ñ>s®“.s¯G¦&’””¬-óþýD\þ‡ &MrÔ'!rƒL‰BˆBæVT4‰‰‰TÓY°+ÓͨhT*•Þ¢ …‚5ªs5òšÁòÊ•{€¤Œ×Ê—¥Å¤²ãíå…B¡@©LäVTij5~•¯?`I–zKûðàÁ~Ý»Ÿ?þü“‡{?–d#ÙFtÛª+òúuÔj5“§ÏÀ&£Åª4Je¼¡bž(+§ý¶TvýÈdî8::æÍCøYÛgéu²ôz8::Ò´IcŽ„Å¿FuŽ=JÃõqqvÎýÎ a! Ø­Tò=÷8˜íÚ0 __‹ÏMNIA£VëÝ ÉÍ>uXøÝê»ñVKó^JNU£Ö€Â!ÿÿèSÚ"D^ˆÒÓø)RDo_jJ2jµš´´4lmìíqtt4Xž¡ ÒÆŠPÓÆF€J¥B­V£V«õÚ`.Kú T&ñæðQ´jÞŒ!ƒPªtiÆNœdv[u¹º¤gUY÷ÙJŠ{d¿è[ve¥¦¤ä¨ßž…ˆú‘Éš÷B^µÏšëdÍõhÓ²¡Ÿoàí¡orèH­e:Œ( $"y†å$MÚÆÍ[˜óÉ‚\nÑcmk¥º¯ù]µïS¾ŽÊ³öX¢ µEˆ¼àããƒZ­æBDÄû|ˤ¯|öüãé,jµš‹—¨T¾üÓiŸ¯ozLL©Ñ¥R©´ÿ¶¤/EðàáCF¾=ŒòåÊá¢P`í¢³Þ^¥pQ(8nÕùÚv[Ðo] …×®FZu®ÑöXù^н&9mŸ¹×I·Nk®GãF¸Í•k×8óÇ9™# ØŸao}“F/Y¶ÜüÓ2®CI‚ª¸äw3„¸+Fó  . áÚõë$$&r$<¥2 …‚.;òÉ¢%\¸x‘Øû÷Y²ww>¥ï…‚Ní_fþ¢Åü}á÷ï?`ý¦/²=¾T©’œùã<ÑÑ·ILL´¨žžÅIHHà;~àÁƒü²wÿ\þתvÛÙÙѯooV¬^ˉS§P«ÕܾsÇà/FÖö{ø»cX½nƒÁókùûóÃO»ˆŽ¾MôíÛìØù£UýÐmµï…¬×$§í3ç:e­ÓœëáææFTT´öM›°dÙrêÔª…‹ËãÿMþ`›·m7»ÍBä¦|sìÄ B×®çʵk”ð,N«-1l@ž¤3–ÞiƬ9¨5jí‚ )))tíÑ›Ž/·ãÝo˜˜HÛίðåæ œ>}–;2˜šËœÔ^YSa5jPߢT–¦IË”]ú«œöI׫ˮÒ'Àž ݵ?¿\Ó•=ÅóOt2/x:0ãU/”W°úÀ=Vîàçsqôjì·¯z‘ªÒ°øç»ì:÷ˆ¤5mü‹1¥Ki\m´e ò໓9w=‘ehZÙÅh]€Ñr³kËáˆxÿÿw’)Y´jcBÇRf½Ï…(ˆ¦MšÈâOCxkTzê;¿Ê•¨T¡"ÎÎNŒ=Š¡«yoÚtT*ê7`éÂùØX{ëÙ ãG¿ÃÒå+7y*EŠáå6­°µ}² Úµ%üØqúS·N]Í›cv^,[–‘ocõú ¬Z»–† êÓ°¡õ¿˜¿Ñ'GG–, !úÎ]Š{xðFŸ^Tó{òySý¶··£sûö”-ó8壸8<‹žÞ1jø[Ìþøú L ÏâtéØ;{{«ûXý^0tMrÒ>s®“¡:M]>=_gþ¢%üwõ*ógÏ u˼7õfL}_[¶Z­æVT4¥J•´dø„È5†>q¶›`Ÿ±)26gÀh¤Lˆ_œ“ŠãââéÜýuFAÛÖ­¸s—äädªU­ Àêu;z”éïOÆÉÉ‘U¡\ºü_nÞ€½½=ÁÆ£P81ö‘xzz²tù öìûÞ=^£G÷WQ©Ò˜üÁ ükTgÊÄñ|¼h 11÷˜úÞRU©Ìš;Ÿ^(Ëı£Ù»ÿ7ºœ];¾àÄ©S¼ÿÁ‡÷pãë-éÁíÑãÇY¶|Û7o xØpììì7z^¥Jºn=‡„±ã«mØÛÛ­ Òƒë·n2zÔªV®B_œœœLž§ËPÀ®P81zäJ•,ùD›t­þ|ý+Âå´Oº ìÎŽ6LéR/7{–þr—½ÅqhJ%ìílXúó]®ÝKaI?_m|ÍG*æöð&5MͤíQ”/åÀ‡¯ziËŒ¼—Ì”®¥ñ÷Uð‚§= [“u™*7k[%ªi2ë2Sº”¦sbÜ~˜JRªšše½ç…Ö»Kçî=8ðën ñJÃí:¿Âœ™3´¹ÌE~ƒ¾ƒóËßéÝa"78»¸ŽŽñ€HÌØR36 ÎØ´òmJÌݘ»¤ªT4 hDÑ¢®T(_^¬çEZ1Sé5äQ\W®¥?ù~ìøIöëC̽ûÚÜ¿'O¡IÀãE,ºtê@5?¿'ÒO™›J*k*,KSPbIÊ.CrÚ'c^©çF _'<]‹ðVËâÄÄ©¸v/Åà±qÉj¾:~ŸwÚ–ÀÓµ^nöŒi_‚=Æé7æåR¼ÖÀ?oG½‡D³«ËÜruÝ~˜JªJM‹ª.SØRÙËQ‚u!ž²K—/SÆ×»Pë·¢¢HU©¨íÿä‚M"÷{Ž£ÇOþZ@çÿú“ÃáGy©~=ììLyÖ¦öÊiJ0KeM¹eÌÓh[ªúqïëa‡«£-¿ýmÝüì˜[®n[25ªàÌü^>|9ª{ÿŠãöÃ'—%BäÿÕYº’¿ìâ«/6Ñ»ÇkùÝ$Q”-ãCøo{síÆ”¹%ßöGqqü¸ûgîÆÄ””Äé³çP(+V,OÒŠ™“ÞÉË«4%Kx²ý«ohš‘{ÕÅÅ…š5üY»a#:ó×sZWnžg C)·ò³mÞîvœüWÉÍû©(SÔØ±aHKOìºCØåÒÔ¢¤òç ë¦÷hûaF¹YÛòP™Æ7'pûa*‰)jŽÿ«ÄÙÁwçôg$Õ—B!òR¾M‰‰‹‹cÿÁC¬]2AÉ eË2oæ íEy‘VÌœt[Íùú»ï¨U³†öµAM™¿x) æj]¹yž¥ ¥¿2%/ÛöJ}7\L Ó¢iXÁ…ÕƒË2¢U œìm™½#š[TxµcX‹âø—ÉÙŸ¦ÊÍÚ–^)Í/çãX¸ëñÉÊ—p`ù_ím%Õ—B!ò\¾¥uB!„¢0±6­c¾.œ$žO•'^Èï&<5—TËï&!„â9'»ÈuÄ !„Bäž|Ï#„B!„ÈžìB!„B`° !„BQ€Év!„(Ä4šœ­†,„¸œ¤$Ï$»BB†G÷ïs?ö.‰Ê„ünŽB<—Î.x/I1î° !D!£Ñhˆ¹EB\¥}ÊRÌÍ=¿›$„Ï¥GpûÖuRR“(QÊÛêr$`BˆBD£Ñðð~, qqT®V3¿›#„ϵbnîssçò…óØÛ;Z]ŽY´Dïü÷§Ï`Ö¼õ^ÛøÅ&¼?РV§±aó¼Ö§­:t|¢}í»vãä©ßµ?_¸AÓVmôú»ë—_1z,-ÚµçøÉ“OôÍXÌœÉÔ?Ô›’’L»Î]Yºb…öµÄD%-ZqóÖMʆÍ_0hØ[4kû2ý æì¹sÙ^ CmËzŽ?ÆÀ!C jÓŽW{õayh¨Áò²»F²ôÍz° !„XRR×oÜ fê9*gÓ–mü¸k7M›Æ¶Mèж-înnzǤ¥¥1yú‡T©\‘!ÁõöÙÛÛS¦Œ/ æÎæËÍèÒ±͙ǵÈHôëÃàoжuKŽÜÏ{ãÇèß¶U+‡‡£V«µ¯>Fë–-X½~ûüÆüÙ3Ùüùìíyû1¤¦¦šÝÇEË–Ñ¡}[Ö¬\NíšþOì7VG³À@~?uF{ìÙsçHU©8tøˆöµ3üA__|}|8vü“Ççû¯¶ã_£:“§M϶½¦ÚöèQ<ߟF—Nùéß²pÞlZ5köÄqÆ®‘x~IÀ.„…F#Û³²]¿q Fƒ›»‡Ñã2oâúY¥Jcýæ/˜6ö/_&¨I’“SزíK&O˜@Å éå8u <ž^vÖ÷m–÷26øM:·ï@¥ŠqttÒ;ÞT6äQ\ÿ]¹ŠFáÇN0°__bîÅyý œøý4µõux¹~U*ãîîÎÀþý¸ûøØ¬×ÆPÛtÇëÎÝ;¤ªTP´¨+ÊW ZÕªze˜sd+¸[NHÀ.„B`%KxpóæM«Ë¸…R©¤ZÕìpܹk7?üøŸÌž£ƒƒÁcIÀ.„B`nnn÷ðàèñV— 7%«—ê×ÃY¡àËo¾1¸_©L$ø­á܉aHð@ÌC¥ŠÙ?ôjH›Ö­8ÀÁ#Gh“1&%5µZMZZšÞñvö8꺚ܦ4§ŽfM8uú4·ïÜA£QSÆ×—fÍ‚;vŒ‡r+:š:µke[‡ÕÍÃÖÖ–K³øã±wpཀྵ0qÊT½cL]#ñü’€]! %lÏÐÖ·wO¾Øº›·n9.ëu}ü³¯7jµš ³=×Û«4³¦ÀæmÛ9pøðÇ\Œ¸ÈÃG5ü-*”/‡‹³B'@}\ŽJ¥Ê¶Í•«W8söš6ih(ã›>'üì¹?´ÇªÕi\ˆˆ Rùò€…BÁի׌ô9kÿõ7sêhÖ4Sgÿ üØqš‚8ÿçŸ ã¥zõ°³+b¤¾ìÚ`þëõêÖfƔɬ]¹œƒ‡p7æ®Ù×H¶‚¾YOv!„¢€ëÛ³~~Uðæ0¾þßþýï ‘×¯óóž½θcíæîÆ­¨hƒw¡ÝŠ£EP /ãZd$ J%‡ÃÂQ*õŽkÜè%†Ä̹ó¸~C ާgqâãøö»ïyðà?ïÙË?ÿü«wL©R¥8ýÇ9¢£o“˜¨_6€£ƒAMX´l9uj×Â5#‡¼‹³3];uäã…KøûâEbïßgñ§!ww§QÃÔªéÏ?ýDtôm¢oßfÇ?X4†æÔáåUšR%=ÙöÕ×6ÀÕÕ…šþþ¬^¿¦M O‡É ãâøq×nîÆÄ””Äé³ P((V¬˜ÞqÆ®‘x~IÀ.„Bpvvv¬\º˜¡ƒƒÙ³?CGŽâÍ·FðíŽïIHHŸîÒ·g~Þ³—IS?0XÆ´÷'Q¡By†Ž|—.¯õ`Ëö¯xôèÑÇ ðuk×fÒ´izóÓ_|áF ‹Ðuëy½o>B£—èÛñå¶Ô®YƒÞ1õ£™ÛѺeKNüþ»v:L¦ñcÞ¥I@#&N™FŸÁÄ=ŠgÙâØdÜÆwÄÛ”,Y‚^1rÌx|¼½±w°7{ Í© Y`SbcïQK'“KË  ¢£oШ‘EõY">.Ž}ÒðÚvêÊ÷;wòñ¬ ÎUÏî‰ç—¡ÙV¶›`Ÿ±)26gÀh¤Lˆ_ü´™—>˜9‹=û~Ò¿ËúúÒ­kztmÁù}æÄ©S¼;n"mZµdö ý/ãàaÃyõ•.tíÔH_Z£Vãää”+u[:F¹]¿%²ŽEN˜êGNë2T~^]NË7t~nŽyvú L‡vmЯ¯YÇ›jS~¾Gó“F£A¥RñÏ…óT¯ÝÀô BäÈë×é30˜_v~«‹áUZ…xýýÇïÔh68ÄJ 1cKÍØT€:cÓ*8i>êÞ­+ûvídÇ—Ûè×·«×~ÎÆ-[ó»YzöìÝO£õ ?v”䔣Çnܼ…9Ÿ,ÈÕú-£¼¨??äu? •Ÿu>Íó­Õ¼i ~:™rêyy ñ,:xø/Õ«'Áº€p°·ÇÅÅ…%<éܾ=C³ýëoó»YZ©©©üvè0#Þ†MŽŸ8ùÔÛPÐÇH<ßÞúæz9•ß_ÉVX·=û÷Ó¢EP¾·C6Ùžþf=»ýœªS»&W[ó9û$)9™æM›2zäœÓÿÌ~ìÄ B×®çʵk”ð,N«-1lˆÉ}Y;qWWüªT¦ÑKõùíà!š5 4xìæmÛY¿ù ö8D·.™8v´Ác‡…óùÆMlXýYŽÇÈTýjµšÍÛ¶óÓ½ÿ€Z5ý™8æ]¼½¼ ô7û±15æY™süö¯¿åû;¹{ÿLó.{;`Ö8†=ζ/¿âλT¯V‰ãÆðBÙ2tzõu>ü` /Õ«ÀňK¼5ê]îùÙà8yy•¶j삇 §Eó ãÊÕ«”ñña˜ÑÔ®¥¿’^NɃïÅ TIDAT¯±÷ÖéÓgÙ±ó'ƒõ[rͲû¬eâ’––Fèçëùuï>iѬ§ÏžaÉ'óµ™ ²k“%Ÿ!Dîº~ã&—ÿù—f†ÿ&„0LvîÝ»‡§§§^@±øÓFÁèQ#´Á¢O—sõ¡«HU¥2kî|V„†2qìhâââ™4u:£GŽ mëVܹKrr2€Ñ}†üºoŸöiõ&³$d©©©ØÛ?ù°Í}z“¨LäúÍÌšnøÁ£L†´´ìsòchŒŒÕ¿vÃ&ÂŽeÞÌprr$dU(#ÇŒçËÍôúajlŒ¹!¦Žß¼m;¿îÙÇŒ©Sðô,Ι³çpws3{ïÆÄ0ûÃ(N„®]ÇðÑcùvëf“s£³+ßÚ±;~â$“Æ¡TÉ’„®[Ï”²ã«mzc›ÓkclLnFE1qì»x•*ýDý–^3CŸµ¬V„®á÷ÓgX0o6®..lܲí‰l ٵɒψ"w•-ãËÑûò»BzD‚RùÄÏ9£ì¤¤¤°õ˯˜<~,+”Ç×LJS&“Àá°£zÇScž•©ãÓÒÒØ°y “Æ¥ª_J–(A»6­P(fõ  [—NT¬Poo¦Nšˆ û4û|SÌ»öíÚâW¥2î ìׇ{±±Ü0cUDK®1]:u šŸßõ[zÍàÉÏZVÉÉÉ|ûÝÞŸ8ŽÊ+âíåÅØwFšÝ&!„âY#wØIŸ±ýëo±±±ÁÇÛ›Þ=^çµn]õŽqtÔO«yý:jµšÉÓg`“‘lG•¦B©LO¯UîÅ©_§}@×δS#ŒíËêpØQll4T«âGbb"Î +”ç·ƒ‡­J/uùŸ4ìm½×^îÒ €À&,š7ÇàyæŒQvnFE£R©ôT(Ô¨Q«‘úKNScž•©ãoEE“˜˜ht©nK888P»¦?×®EæJy`ÙØeÊ\;k~åÜ*ßÝú-½fðäg-«[QQ¤©ÕøU®¬}ÍÔâ‚–ŒIa‘ƒ#…B§]bØØ>]û¢X±b4¨[WïuooªU­ÊoàææF”ÎrÔ¥J•äÌç³]:“½½E]s?nÖú] ºtìÈ'‹–p!c9è%!Ëñpw§a–T}ÆÆÆÔ˜g SÇ»+Fó  . áÚõë$$&r$<¥2ÉìqÜöõ·\Œ¸ÄýûYŠZ“Fó ¦Ôò÷營v=^F{çFÇ)§c—×ׯÜ1ÑeÎ5³”‹BA§ö/3Ñbþ¾pû÷°~Ó•ai?ž'666¸¹yp÷vT~7E! »·£ps³þ/Í2%&‚ßè“£#K–…}ç.Å=]{÷ýF»6­ þÙ¿m«lÙþF¿KŸž¯3Ñþ»z•ù³gÒ¡][§op0uëÔÍv^z@£Fy²Ì²¡úÇÅŠÐÕ¼7m:*•ŠFõ°tá|½å £ãÆÇxb,L?mÒDÂ[£F“ššŠ_åJTªPgg'³Æ±A½:Lš6¥’:µj±béììÒ?V£†¿Åì?¡Ï Á”ð,N—ްә.c¨üœŒ]^_›ìÎ7ÅÔ5°ÆøÑï°tùJÆMžJ‘"Ex¹MklmÍkúñ<°±±ÁÆÆ—bn¤ªR¸rù"%K{ãZÌ-¿›&„Ï¥øG¹{; gWW\rð]kèÿn¶›`Ÿ±)26gÀh¤Lˆ_lu­B‘‹îÅÆÒ¹{üºû‰_|…¾ôt®i¤¦¦¢Œ‹ãÑ£X’ÌÈ%„ÂrNÎÎ+Vç¢E±··§˜›û8à8(ÄŒ-5cSêŒMKî° !žy—._¦Œ¯·ëf°±±Ñ>díêæ†ÂÕµZƒFBBˆ\eƒ ¶¶éß¹™›µ$`B&tEXtCreation Timemié 14 dic 2022 23:10:40 ]Ê IDATxœìÝw|õýÇñ×¶,ï=;{ï0V™Z6…PF”Qf™-«…2ÚÒöW(” -mé Ê&ÊJHÂÎðÞKûôûC¶b›,%ŽÛïg÷°%î>wR¤·¿ßï݈ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆÈ0dìÆåõõ²EDD$y±­ü¾KvåKÞèõ³÷c """/Æ–ƒC¬×ϤìÌ—|ïpÐýv÷ßÍ)HDDDú”Õù³{è*¶2¶*™Ñ»ÅÁìösKÁÁ–L!"""²[D;öÖîïþs›ì;¸ò-µ2˜½~7{ݯ‘gcs`èúiÿ®ÞZhØnˆØ‘ˆÞ­ ½C‚Í¢{pìÀ²EDDd÷ Ó38tMQz†Šî­ÛíÒØ^ DïðÐ}²±9<Ø, H<;°lÙý"€hj†ÎûlÄCD”øw}÷.®ïþ­†ˆý’ïì+¶é@Ù Ï?{Ƹ1cŽÀ ˜ŽÀÙcĈÑòùêÕÏrè÷ë€f67Dz=Ãb;¶õEoÐsŒC÷Ö†®)˜X¾æó{‰ Ù³5—Žwð PC<”XLãDDD ׎wð>ЄØ"ºº5z¥Ñs[[4=®0‰Š´wþtÓÖ®þìqÒúdcDDD¤ßÄ eÔ˜ñ'Aâƒ-#?»¶Üb+ÄŽjÙ½ £«õ!÷¹gž>MáADDdp2 í¹gž>øN6oì:šr›¶ zŸë¡÷ø‡¼qãÆ¾«Å‹ˆˆÈÀéü.Ïcó÷{WƒAïó=}ɶŽÂèÝѵpa˜F*±>»&‡ˆˆˆô3Ã4R‰it°yìC”ø÷~Œž'›êaGÎÑûÜvÀ³b†ŽÕ¼b±˜xéÙ}Ñ5móPÎ-ˆÞ×¼è=¢kê»k‚ŠˆˆÈ@éþÝÞ{ D÷Ÿ=¾ö·5ˆ²wëC÷® ]çBDDdhèþݾ¥KSlÑÖº0¶t¹î^§°VûƒˆˆÈÐýÒ[8¹Åq[ëÂè}öIGçäLLÊ"}®®¾€œìì®DD†g·©ûY)mlùÊ€.x%Òo.¼âÖ–—`š&9YYLŸ2‰“Žû.Y™øÎùÑ嘆ÁCwÿ—˹Íåƒ!¢Ñn·Óìß^ÅîÛbÙYYrèAû³pß½ûµ; Ô!²söš= €ÏV¯æ…W_ã“ÏWsÇÏoÀét2rD ¦a`wØ·ûì®{îåµ7ÞäÎ[ndÔÈ‘»¿ð-Øoïù˜¦AEUïô+?ø€×ß|›+~tþ€Ô#"ýgZ !D’ÿ?óÃsÎ Í磣£ƒË®¹¼ýî2ì3ŸÛn¼îKóooyÛ¸ÖÍn_ßygž†×ëàóÕ«¹ù¶_óæ;ïòâ’%|eÿ…ý\“ÈÐvÔ §2iâx~|ÑIK‹Ÿº¥­[+>ú„<þ`¿Ö£. ‘âõz9pá¾<ò翲±¢€ã…Ãáäá{~€eY<ù¯ÿðêëoPWß@éÈÌQ¼øê^{ã-.ºüLÓäÉGï§¥­ïyÆá–ë¯à=Ê¿žyŽ_|óçÎæøEg±ïü½ÈÍÎæù——ŸŸËÏ®»Š@0È#ú+o¿»œv“'LàŒÓN"?7w‡¶gܘ1œzâqüòwwóü ¯$Äö–{ü¢³ØgÞ\Ü.7o¾³ Ó4ùêa_aÞÜÙÜ÷à#|¶z-9ÙYœ}ú÷˜2qBb¿üíŸÿfÉÒÿQ[_OIq1'ómæÌšÞw/ÈfDI1ò×Üt 7\u9†apÝM·²¶|=%EEý^ÏÎwœÆ4iÒ”ÔÔ¥Û}‘H€¬ÌŒ-ÎsÏðÈŸÿJ$e¯9³¸Ýnö7‘#J8âƒ9þ裶¾ž-Ü~åµ7øË?ž"%ÅK鈃_üò7<ýÜ L?–y³g±|å*nþÅ/±¢Öm 1˜?'Þ=³¡¢"qßv— ¼¼d)ï­ú€’â"›šxøOáÂ˯&“™Áú ¹íW¿% 'öË£Oü ›ÍƬéÓX³v7Üz;}üÙÀ¿Îš4í¦é'W\BaAåë7rÍ·pÍ·°¶|=y99\{ÅÅ;¿ì¤‘`YkË7ðü˯`·Û™6iÒ—æ©ohà¹_¦¨ €_Ýr#‡£Ção¼õ6ë7läðCJz „išÜ|íUŒ;€µë׳lÅ*æÌšÁÅ‹Ï  ñÆ[ïPQUµÃÝx<<~€h4ÊúM›vh¹))^~wûÏ1M“Çþú$O<ùO¾²ÿBÎ=s?¼ôÇlØTÁ¦ŠJR}>ž{ñeF”sûM?Åf³ñü˯òÛ?ü‘¿ÿûi&OŸÔ¾,²³²¸ñêsõ?£|ÃFrs²¹þêËÉËÉé÷zvaå.Ä‘aì{g—øÝ4MNÿÞ‰äõø?#ƺ °,‹™3¦vªìù.Öíg¬Ç­ÍËèyÏæû<ãÆŽJÜÞ¸©€eï­ä¨Oí±žÖ¶¶­þuþë …äçbÚÌ^®iÚ0Lƒ1Ɖ‡Ãf$7f 6UÐÒÖJ}c#–e1kú4L›IŒ ö™ÏoÿðG6lÚ¤Ï&Òl6;NÇæ#´v‡c@Þ÷jégóçÎ!Å률 ½÷šËˆâÂ-Îç÷ûã¿XÉ0D£Û<…ý—ø|>æÌšÁ¢“ïñX2Ù¬úð#b±¥#Fîôr·tHªÍ¶ù¾@ @ÔŠ&î C†ÛåÚáZE›Æ¦f®½é6nªH´Þm¬¨àº›nåú«/'3#½_ëÙù¡/²SÎ;s©_¬À–ÿ/Å (¿€e+Vqj(Œ³W†Ýf ½µ-± —Ó…alÜTA¨ó9ápdËëêöûÈâ"LÓä³Ï¾ Í—Ú³¾­ÕØuçc•U5üñ¡Ç1M“cþÄ’\îVöCïÛ]ëÝå+ùÞñÇât8X¾b%±XŒ²‘#ôÙ$CÖ ·Þ‘×_}9×Þx +*¸á–Û¹ãæëûµµ@ˆì¡F••2eâ>üäS.½ú§Ìœ>•õ6pÜ1G1qܸø—%pïC²×ì™ûíoát8SVÆk×rùµ×“™‘ÁÊ>Ü239üàƒxæ…¹âº9pÁ¾ÔÕ7Ðî÷sÉÏÙêóî~àal65µu|¾z ‘H„SO<ŽQµíìr·edI ³¦Oã½UïsÉU×2º´Œ·–-ÇápðÝos§–)2¬]WΨґ\sùÅd¦Ç[®¿úrn¸åvÖ–¯ï÷zt‘~·#CŸã_~áy<øø¼÷þ‡<ûÂKä …€GöÖ­ßÀÛËWð⫯³ïü½U:’óð}îº'>Àãqsæ©'q÷ýoa½=k8ãÔÉÉÎäå×ßàɧþCA~.cG&³0Œ-_OgÉÒÿaš&Eùì5k&ÇõõÎðÛ‰åî`1.=ÿxü –¯XŲ•+™0n,§žð]Š òw`ߊ Nôþn·âïóÌô4î¸ù§=îë/[úTè~ÕÍ®k`x:'/àæñé‡wôW‘"""²{Œ0åGÀ[@Ðø;§pçaó51tYnIšQŠˆˆHÒ4BDDD’¦. Iš.ç-"""IÓIšÆ@ˆˆˆHÒ4BDDD’¦!"""IÓ JIÚ. ¢T„®Ô…!"""IÛéˆMë×öe"""2ˆìt€˜¿ð+}Y‡ˆˆˆ "ꑤ)@ˆˆˆHÒ DDD$i Òg®¹þ~ù›ßnñ±½8˜?ú¸Ÿ+’¡î„SOç¡GÛ£× …»¹"‘þ§!"ƒÖ öcÂøñ{ôz|øQnºõ»¹"‘þ· ÓX?8óûÃj½"{áp˜ßÿá>^|åUÁ ,XÀç‹×ë`ÑYçpìwŽæégþËGÌÍ7^Ïü¹s¶û¼.×ÝpVÌâ†k¯  ñÍïÏW?ŒóÏý~¿ŸC¿þ-þüðäåæîÐr»üé/ãŸO=E}C#S§NáÒ Ï'';›ßÝó^ã jjëÉÏËeÑ÷NáÈÃMùô3Î^|>¯>ÿlbù;óþßÚk‹ÅXtö9Ìœ> Ÿ÷¥íÙêÂ>Gðûý_šz»ý׿¡|ÃFî¿ûÿxèÞ»©¨¨à·wßÝcž;~}‡~wÿö.fL²ÃÏX¸ß¾,[¾"q{Åûï‡yméë›ï[µŠ’¢"Š‹Švx¹@â õº«®äÑîãˆC!#=‡ÃAIq1·Üx=p_;ònøÙ-”oØÐãùo½ý—ÿèBž|üQ¦L™Ì•×ý„p8ÜcžÖÖ6.¿êZ¾ñÕ#yê¯OpëM7pÐþ vxÿíèölo=÷>ð/½ò*?»þ§<ø‡ßãt88ï‹{Ôûî²å\yÙÅüõ±G).*ä´³~@uM5·ßr3÷ÿán6nªàw¸/éÚ’Ù_Û{mvf½O=ó,‹Ï9›?=ò Ó¦Lbñ.¥­­-©õžrÂñ,:åd9ø@–¾ô<—^tÁV××[²ïÿm½–†a›““q"}ABúÔßþñO:âk_šºkïèà_ÿþgœö=233ÈËÍå¬3ñêëK{ÌwÖé§óõ#Ž`ì˜Ñ¸Ýî~À>óçÑÒÚÊÚòrÞ|ëN=éêêÙ°qï,{}÷Ù;©åF£QxøQ.¿ø"&NOnN‡r0€cŽú£G¢¸¨ˆSO:‘¢Â>úø“Ë8â°C™0~™™œzÒ Ô74°qÓ¦óÔÖÕŽDØwŸù¤¦ú=jTâ¯ßíÕ›Ìölk=¡PˆÇþüW\|cFÇ·éº+¯ ½½×–þ¯ÇöŒ;–¬ÌLN:î8b±'wE……ŒQÂ7Ž<‚U«ÞOº¶dö×ö^›Yïw>ŠéS§’›“ÃçKVf:Ï¿øRRëÝɾÿ·õZüâæ9íä“v©&‘îÔ…!}êøï³Å&Ò½88ñûú °,‹+®½€H4BGGÏ¿î\.gÛ;ú<€””fϘÁ²å+UZÊÿÞz›_Ü|#Ÿ|öo¼ùÇ}çhÞY¶œ Î;'©åVTVá÷û™4q·¿©©‰ç^x‰•|@ss3 ·1¿° ÇCGGÏVš²ÒRæÌœÉ‰§-b¿}öá›_ÿZ¢¹{{õ&³=ÛZϦÊ*"‘HÁ‚‡)S&³n}ù·§¬¬€@0˜¸oÔ¨R::[¡’©-™ýÛ~mvu½¦i2mÊTÖoܘÔzwE²ïÿm½–"»ƒ„ô;_J*üýïÈÊÌÜmÏ[¸ß¾,{o9 ÷Ûb%ÅEì¿pÏ<ûGú**+™9}•U5;¼Ü¶¶V >6Àf³õx¬£#À÷ÏYÌÁìϧ}¼ü|.ºôòíÖi_¾²­išÜuçm,_±’ÿ<ó,W\u-sfÏâÖ›nØî~Hf?mk=áP˲ˆF£˜ææÆJ§ÃËåÚò¶lñ¾Í÷îìkßcy[Ø_°íצ/Ök3MÜ®/—ØÖz·%–ä·· Ûz-EvuaH¿+,È#Åãáõ¥oìÖç-Üo_–¯XÅÿÞz›ýöÙ'~ß>ûðþ‡ðÚÿc¯9³±ÛíI-·¨¨˲øøÓO¿ôØ'Ÿ}JSs3çýà,F••‘âñ`lé5 ³gÎàš_Î~wK^_Jm]ÝvëÝ™ý»¥õ—”ññ#],Ëâ“O?cì¨Q;µ=;ûÚïˆm½6;³ÞööŽ·?üäSF••%µÞ.‘H¤ÇmÇMùºõ;\ ìø6léµÙ ¤ßÙívN:ñx~{Ͻ¼½l–eQ]S³Íày^AA>¹9Ùü鉿²`ß}xׯ´)S¹÷ÙoŸ½“^nzZ,\Èm¿¼‹ò h÷ûyý7èèE{{;Oþã_455ñß^ä‹ÏWïÔ>jimåßÏð þ:`aRëÈËË录ïSUUP<}êTþõŸ§©ªª¦ªºš<õïínßö¶a[¯%À×\ÇÃÿ)éý*²5ê±蔓q»\Üù«»¨ª©%+3“SN8ŽI¶Ýœìóößo?þò÷¿3}Ú”Ä}.\À-wü’}æÍÛ©å^}ù¥Üñë»8{ñ„Ãa&ŒËØÑc(1‚ó~p÷Üÿÿwï½Ì›;‡yóvî‹¶µµ•—^]ÂoヌŽöFŽÁÏ®¿—Ó¹Cõîèölo=?º`1¿½û.»úZ"‘óçÌå—·Ý‚± M+;ûÚ½6^¯;éõΛ;›ßüßÝÔÕ×3uêþïWwâp8’^Êo¾Å‰‹1kæ,nÿÙM,>çlnüù­œpÚéädgñ¯‰}+Ëîn[Û°­×Ò²,**«ÈËËÝ¥ý+ÒÝ–>ÌÎÉ8:'Oçä|ÀüŽö¶;ú«H‘þ´¥ó<ˆ UÞ߀·€6 ðwNáÎ)XS‚º0DDD$i """’4IšQŠˆôrÿ=ÿ7Ð%ˆìñÔ!"""IS€‘¤)@ˆˆˆHÒ DDD$i """’4Iš„ˆˆˆ$MBDDD’¦Iɰ‹Åº¤v劤"C„ ½ƒB×mÙY]¢wP°áBB†¼X,– –eõ¸¯ë¶H²LÓÄ0ŒS… dÈêÞÊFˆF£X–Õ À²¢Y¢ V†i˜˜f<8˜¦™¦iv΢!C›„ IÝ[º„eYD- +MÜŽD"]ª B†a`·Û1M›Í†ašØm6LÓ$‹%‚Dï– ‘¡DB†œîáÁ²,¢Ñ(áH+% ÒÜÜL]]mm­„Bá.W!Ã0p¹]¤§¦““Mjj*‡›ÝŽ£3X¨KC†:’ºDWxˆ„ÃÔ×7ÐÖÖBvV&ãÆŒèe°3ÀÀ ¹¹…uëÖ‘ŸŸOjj*v› Ã0°Ùl\¤Èî£!CJ÷Ö‡®ð…hjjfㆠLš8›i‚޾]ƒ1ÒR}¸=nV½ÿ!S¦LI„ˆ®î ‰¡JB†”î]‘h”H8L  ²²’©S'³,¤¯9ìvfΘFEU N§34B†8‰R†Œ®Ö‡DˆˆF ‡Ã444P\˜OL‡lÊndn—ƒööÂáp|ÀnâˆÅVzÔ!CN¼û"~„E(¢¹¹…ô´PÛƒìF†¡P˜X¬·Û…ÝnDzٰ,K-2$)@ȋŰbñ1‘H„@0@4ç@W&C]($ƒH$Òy¨°ZdèR€!%Ñdluˆø8ˆX,¦öÙí,Ë" ÆßVÌêqB3µDÈP¢!CF÷ꮣ0"ÑH·“E ÍѵÝúrx–%ëvÆS!LB†ŒDpè:„3& Åû¥­Ø È±XŒŠªj>ÿb5PÔ“&Ž'+#c‹óG£Qž|ê?Œ=ЙӧõK5µu,_¹ŠH$‚Ýn'-5qcF‘›“Ý/ëß“Y–EØŠ‡‡D£Q¢Q »=¦r dXˆ1(òå6r×Ý÷RßÐHfF:õõ \vÑÉÜJ€À0XòÆ›˜†ÉŒ~ ë7nâGÿÄøqc …BTTU‘“™Å§žÌ¤‰ãû¥†=Õ`x‰ô&G„X±ê}ü~?÷ýöNLÓ$‰`3MZZ[‰D#XQ‹p8Ljª_J ¦ipÙ…‹IõÅ2©¨¬Âãq1M“¬Ì ´ûýØL@¯ÇCFF:oõhhl$ áv9ÉÌÈÀ4M**«ðz=øA¹9Ù¼´äuž{ñeLä­£ƒÓN<Ž93gpÙ5?¥° €öŽößoŽ?ú¨x‘]û±sŸåpÜÑGqßC…innáÁÇþLccþ`€‰ãÆræ©§ðß^æÕ×ß #=ƒÊêj òrÉÊÎbÍÚuøýN?åöÛ{/¾úϽør¼; á¤caï¹súeÿÏ5“×þ÷¿üÝ=ÌŸ;›§žù/#KJÈÉÎÚ±÷Ï x‰ôHJd²ï¼½˜9m ÿåI®ûÙ­Üù›ßÓÞÞ@CC—þð\Î9ã4>øðc^ãÍ/=?2{Æ4~zåeL4‘·Þ]–x¬©¹™ Ï9›sN?•êš:–­XEcs3÷?ò8Ó¦LæêË~Dnv6¯¿ùV|üH$ÊÈân¼ú ŽúÚ‘Û¬{Dqþ@€H$Âò+ÙXQÉ•_ȱG}‹×ß|›Úúúø645qÉùçpÊñßáãÏ>glY?»î*œNËV¬¢¾¾‘‡ÿ3,ؗ믺œIãÇò÷§žéÃ=¼mS'Mä'W\BM]-ýåIÜn7‹Ï:ìÌÌ~«Ad°P „ ±Î{ºÌÌt~ôÃsøæêµ¼´ä5^]ú?î{äqŠ óqؤ¥§29e<¦ÍFM]]·mÚ¼}Þ”|¾ÆŒ)ãíwßK`Ô¨‘Dc¦i0rd1™™‰5ôþÙõ{SK3é©>ì;5uõT×ÔpÃ/n ¨ ŸP8~ÕSÓ´‘žžFYéH ÃÀãu“šêcü˜1Ö®_i˜”AJŠ—Y3¦óÎòýöÚEcõ M˜†‰Ãn'fÅhkï 'G'ƒéMB†‡AÒ…á0 ƒqcF“••ÉGŸ|F}CEù„#a¡0µõõÄ,‹Œ´´žÛÔëwcóýݺŒÎééØLÓ§LæÔÅ4mØl6\ç–—Û]çr[ÛÚyêéç˜2yN»ƒœì,€´Ÿ^»w—¯àw÷ÞϨ‘#8pá~ü ~ÿǹø‡ç—“Ó?Eˆ  "{üûiž~îEJGŽ ®®žêÚZŽ;ú(*««iimãòënH\(lÁ¾{ïòú2ÓÓ9ô yîåW0 “0~Ü9`ávŸûûû" ñá'Ÿâq»¸â¸ó±ÛíL?—ÓÅu7ý‚y³gQ×ÐÀEç½CõŒ*ɨґÜÿèc¼³l9ï¼·‚“ŽûÎ.nåŽ{ÿÃÉÊÈà’ ãóz™ˆr444`aàóùp:8Nl6;v»-qeN‘=ÍM7ßü_`Â@¤s²ºM_jÇÝÒ»Ùìœìl žÎÉ ø€ùímwìŽ ÙY]×¾…ÃZ[[immå‹/V3uò|¾”.q§=ù¯ÿðìó/qÏ]·t)² Ÿ±šhÌ  ?ŸÏ×$\¸\Nl¶xˆÙÓxS|?ÞÚ€Àß9…Ù(º‚D‚º0døc ¶k(lÃP¦×G†&É(Ê­˜0vtgsáàÝZ dXÜñ&OšÈäIõ6ˆÈТ!ÃÃ`O28Ä˫ŠIDATØòÈ2‘!HB† %éJ2|hH°ˆˆˆ$M-2,¨ýAúƒÞc2œ(@Èð‹Å'é 2,ÔVUÒævnF‘]ÐÒ܈/#{ Ëé 2,L›3ŸŒôô.cF©¨¬dÃÆM´µµáõz=ªŒ‚ü|Eq¼÷Þ{465 t"ýBBDhkoçÅ—_á•%¯±©²’ææ,Ë"?/Žý_9ðÜݯª)"Úþ¤:ü~^zåUž{áEZ[[Ió¥’—›ƒÓá`íºuüîž?ðêkK‰i‰ˆtR „ˆ°aÃF>ýì3ÒÓÒ˜·×\öž·™¬^»ŽÇþüK^_Ê¿Ÿy†éS'SXX8ÐåŠÈ@BD¨ª®&fŘ9cí¿?ééiLš0SN<ʪ*Ö¬]Çû~¤!"€º0DˆF-<^%ÅE¤¤x÷Œ*I鈑øý~°JÙ“¨BDð¥xÉHÏÀ4âGbØí›?œN'‡ò ˜={ÖV)"{!//—šº:š›iii%7×Õãñ½çÍeþ^s0 ]çADâ D„ü¼=ñ/¿²„@0ȇʉÇ~›ÍÆ5×ßÈùçþ€iS§pîQ\TÄGŸ|BÙÈRŸs6…ùüúwwóÃsÎÆérò‹;~I$jQ¾~=ûï·/g,:€?ó_žúÏÓ¤¤¤ÐÜÜÄ­7ßÈ›o¿Ã«WsÉ…$¶mÍÚµŒ;¯×KKk+Û= ûYD’£!²‡[öÞ bVŒ¶ö6l¦ï}áp˜¿üýœîÈHOçž?ÞϜٳ0Mƒp8Ì‹ÏŲbü䯛8åĸãÖŸó—¿ý{þx??¹úJö™7¯q MM\xÉeì;>cFê±ÞhÔbß½çsÑóðãóÆ›orÌQßê1O0âìïŸNzZ·ÞùK**+ijnæ³/>ç?»‘––V®¸æ:À`ڔɌ()éñüƦ&Ö¬]Çßÿùþ6mª`ñ9? ¸¨pwïVÙE: Cd7zT)¸?«Þÿ²²R òó)ß°å+VðóÛîàÊë~ÂÛËÞ%ð“MnNÅE…2~Ü8ÒRS™·×6lÜÄ/ßýâ+¯òø! RßPÿ¥õ:NJŠ‹ðz=Ì™5“ææ–/Í“™‘A~^.99ÙŒQBmmåååÌš>ì¬,JGŽ -ÕÀ˜Ñ£™3kf盦‰Óáä„c¿ËÙß?1cFóŸgŸíë]("»Z Döp™™Œ*+ãì3ñà#qà¤ùÒ˜:y7ýäZ<ObÞM‰ß ÃÀfšÄb1ì6;±X ¿?ÀÅ?¾šc¾õ Ÿ}UÕ5‰y¶&~äÇÖç1 ³s]Q+F(Ú±mKO'=#'Þm1rD +V¾¿CÏ‘¥‘AbîìÙdefòîòäädápØyów±,‹úÆFÂáð-§ÃßA}}=#F”ÐÒÖFmMMŸÖYVVÊÿÞz›Êª*ÖoØHKk+ú)Kß|³Ç¼£F•ñégŸñþûP]]Í+K^gá~ûöi="²{¨Bd0M“o~ýëüûé§Y¸ß>œýýÓùÍÿÝÍ-·ßÉü¹s¸èüÅ;´œì¬,N<þ»\òã«().¦¬¬´Oëœ>e «¿XÙçOéˆttø1 øèãOùbÍjöÛ{ïļ%ÅÅœvÊIÜùëßÐÔÜÂi§œÄÞóöêÓzDd÷ØÒÙZÌÎÉ8:'Oçä|ÀüŽö¶;ú«H‘F‰D"„Âa‚­­­´¶¶òÅ«9ø+“‘ž>Ð%;­mm\|Å•üîWwbß'ÀÚS¼÷Þ{465QŸÏçÃçóátºp¹œØl6LS¾²çñ¦ø~¼´€¿s wNÀêœôn‘> …ø|õï,[Ƥ †ExnÔ…!"}* óŸgžå¥W—0gæ ÿàì.IDvéS>_ .>— Ÿ;Ð¥ˆÈn¤. Iš„ˆˆˆ$MBDDD’¦12lD#êêªiihèRd±Ùmdfç’™½ë—7L dXˆF"ÔÕT‘–‘Ié¨qÆ–N"’¼Hç{«ºb#–emÿ "C„º0dX¨¯­&5=“¬œ<…éSv»‚¢\ní­Í]ŽH¿Q€a¡µ¹‰ìܼ.C†°ÜüBü]†H¿Q€‘¤)@ˆˆˆHÒ DDD$i """’4àí·ßæØcå£> ½½Ûn»½öÚ‹n¸–––®PDdÏ¢!ÃZ$á¶Ûn㦛nbýúõzè!jjjø×¿þE]]÷Þ{ïW*"²gQ€aoáÂ…<öØc%îûïÿËé§ŸNaa!gžy&Ï=÷ÜV("²çQ€aÍn·3þ|RRR÷jkk)(( ¨¨ˆ¦¦&ÚÛÛªL‘=Ž„H/˜¦‰ÃáÀétb·ÛikkàÊDDö "½äææ‰D'»Zrrr²,‘=Š„H/v»±cÇòÑG‹Åøä“O˜6m6›m KÙcèjœ"[°hÑ"}ôQÞ{ï=Ö®]ËI'4Ð%‰ˆìQ D:ÝrË-‰#1ößFM]]Ç{,ÅÅÅ\ˆÈžEB¤Ó¸qã¿ÛívÊÊÊ(++¸‚DDö`!"""IS€‘¤)@ˆˆˆHÒ DDD$i 2,¸=ÚZuEMÙ}Z[šp8]†H¿Q€a!;¯€ºš*üºž…ô-˲hkm¡¡®–ÔÔô.G¤ßè0NÜ/.‡êÊM„CA Œ.I† ÓÀår“›_@u]tt tE"ýBB† 77eû3ŠˆÈv© CDDD’¦!"""IS€‘¤i „ –eÑÑÞF0àèRd1 ·×‹ÛãèRDú•„ ±M uØmvròòAGaH±¢aêkk ƒèjDú„ ÍÍd¤¥“•›7Ð¥Èc³Ù((AÕ¦øý:ψ !ÃB{K YÙ]† aY99üê“áCB†ËŠb³Ùº Âlv;±˜5ÐeˆôIš„ˆˆˆ$MBDDD’¦£0D¡P8ÌúõëimkÃn·SŸONv6±X Ã00ŒäSµ,k‹Ï³, ÓŒÿ±©¢Ó4),(è³í‘ÁK-"ƒŒeY¼ðÒK457STXHZj*Á`Ã0XùþTTV&½Ì÷V½OCccû‚Á ï¾·‚`(@‡?ø]DD-"ƒL[[•U~È!=Ž,ñûý446b¾”RRRhni!ãr¹HOKÃ4M:ü~b±¿‡Ó‰Í4ihhÀëvãp8HKM µ­ÆÆFª«kÈÎ΢0?³s}---¦I À0 ÒRSéèè  áõzñ¥¤`¡p˜––,Ë"-5·ÛM8&ŽDÈHOO´rˆÈà¡!2È8].¼+V­büر¤v~á‡B!ííí´ûý¦ÉÆM›ˆÅ ¦®–)'Q\TÈú Y½f y99äãõz ƒ´¶µá÷û"  iniÆçKaͺuø¼)Lœ0žU~H(&77‡êêj rr²!£¦®žù{Í%ÕçãÃ>Â0m³X»®œÙ3gÐÜÒÂÿÞz›üÜ\223HKMU€„ô¿Vdq»\}Ô·hkkã/OþW__J{{;ééédggSR\LQAi©©LŸ:•™Ó§1fÔ(ªªªË(ÈÏgîœÙŒ()!;+‹¬¬,ÊJKÉÏÛ|¦Îì¬,2337v,Y™™_ªcDq1Ó&OföŒÔ760yâDfLŸŽÇ㦩¹™@ @m]“'N`Ú”)D"‚ÁxHfFsçÌfüرØíú;Fd0Òÿ\‘AÈír±ÿ‚̘>O>ý”ÿ½õ6û/دÇ<í¬]»Ž`(HcS3©>_â1»Ýžô@ËÞºžŸ‘‘1ˆÅâ‚HII!fY´¶µÑÐØÄ[o¿ƒaD£lvã§ÞÕõ‹ÈÀR€¤ à #=Ù3g²äõ¥D"ˆÅ_äë7l LŸ:•Šª*jkë¶¾°XŒ-] *‹%}¨®Xê󑑖Ƽ¹sp¹\‰ÇÛÛu½‘¡@]"ƒLKk+o¼ù7m¢®®Žå+Wâñzp¹\¸Ý.jëjiooÇf³Q[[K{‡Ÿ 6í´¸%†iRWWGGÇæk9˜¦I(¢¾¡ž@ ˜t.— —ÛŧŸßï§®®žh4ºSÛ,"{‘AÆãvSTX@uM kÊËÉLÏ`î¬YØl6&ŒÝá |ÃJGŒ //—Ï>ÿœÜÜ\JŠ‹ÈÊÌ 7§ç…Å&OœH dã¦M‰ûÓ§LaSe%5µµäçå%ÆB’‘žÄ[BÆ›8"$7''10rÞܹ˜¦Éª>¤±©)Q¿Î%!2ø© Cdq8”•–RVZú¥Ç dX0L‡Ãišj>gšfü’äº>˜ # 2l†¡An²[èÊ¢2)@Ȱ¢z‘¾¡!ÃF,# ‰„ºB ÃÀápbw8º‘~¥!ÃC,FKS¡`§Ë¥–é3–eÑÒØHJZ›+É„ m-ÍØm&%¥£¤ÏÅ,‹5ŸBÀß1Ð¥ˆôHJ†…†úZr Šd·0L“ü¢ÚÛZº‘~£¡.—‹XLm̲{¸Ün¢Ñ&®.E¤_¨BDDD’¦!"""IS† #ê¾é+ 2l µá@€†ÆFÂá0N§“ì¬,œN'±Xl—‹véZNUu5Y™Y8:×ÁÖ µ÷—Èö¨ CdŠF£üñÁ‡øÛ?þɳϿÀ“ÿü5µutøý¼ôê‚Áà.-ÿý?bÉÒ¥‰Û<ü5µ5»Z¶ˆ !j„>ýüs6UTpí•?Æáp‰D°Ûí457óβeÌŸ;—kçøbõjÊ7¬ç€ 8ÿ¼sqïÂòDdèQ€adè´1Ûí6)_¿žQe¥‰®…ç^x‘×–.¥¼|=Çç¦M›Â?Ê¦Š ¢–űÇ|›}æÍãÇ×\KAA›6Uà8éøãÙ{Þ\ Ã`ÃÆM<ûüóTVUD9÷¬3¸ö†9ÿ¼sYRÂ…—^NNVUµ5”S\TćLk[‹N9™¹³gQ]]Ãýuêïɾ4tÞ_";BB†¡ÔG=fÔhö_¸€ßÝs/©©>Ž<ìPöš3‡C¿r0ëÊË9ïì³HIIáîûþHqQ!g.:uååÜtË/}û(b1ÈÍÉåû§Æú øãƒ1aÜX233)).æˆC¡|Ãz.\¼8¾ÂX|ŠÅâ—®þîÑߦ°¨ˆŸß~}>®ùñå,yý î{à!f͘ÁÃ=ΔI“9ôàƒXúæ›üþ¾ûøù ×C Ü7W]~)Cê5JÛ"²# D!Ó49þ;ßá;GÅ‹¯¼Âm¿ú5?8ã æÌš™˜'²zÍZκñzLÓdê”)Œ9‚70¢¸_J “'N$3#ƒ†ÆF233·»n¯ÇCff&¾”ÆŽMnn^—‰ãÇq_m-¬-_Ï’7ÞàÞû jEIõùÏŸ±, §ÓI÷}ÔµœÍºßî\G·Û]Ç}8]N¼7·ÞtÆëõüÞËJ†â6‰lŽÂ„ÊË×óüK/QQUEeU+W½Ï„ c±Ùl´¶µQW×€iL›2…[ïüUÕÕ¼øò+DÂaÊJKxö¹ç©¨¬ä¿/¼ˆ³ÈËÍI,ß—êã‹5kikkKúôßN‡ƒùóçqû/ºšÖ¶6**+ûtûEdà©Bdr8,[¾‚ûx›ÍÆ×8ŒC:§ÓÉ öåòk®áë_=’Žýmþ.ùñUŒ)+ãç7]Çã›ôÊk(-Áå]Ôã¨.à•%K¸ìêkøÙõ?%55›Í@ªÏ‡iÆÿöðx<8ñœ6›ÌŒ Žþæ7ˆY—]}-Äàû§žBQa!©©©-"2Ømél3fçd“§sò>`~G{ÛýU¤ÈŽˆF£D"Bá0Á@€ÖÖVZ[[ùâ‹Õ”ç3wï]âãŠk®åk‡ÎÂû t)CF4áùÿ>ÓBA~>>ŸŸÏ‡ÓéÂårb³ÙÁKdOâMñýx h:çîœ"€Õ9%¨B†õQ™öIßѾ”áEqXd*).Â×íÈ‘d©BdZüƒ³ºä dØHöh‘dèý%ú0dH3 Ã00m6¢ÑÈ@—#CX4Á´ÙW0ÝÕ+¢Šìé dH1 £óà"Ó4SZzuµ\ euµUxÜ^LÓÄ0ÍnAb€ ÙMÔ…!CR÷ð`ši™ÙD‚ÔVW’“§Oué3ÑH˜šª œ.7^_*íña:lS†4rLÓH|x›6‡ƒòuë00hmm¢½õ-b±XbÙ]Ýcv»¯/ _ju õ¤¥¦b3m 2ä)@ÈÑõÞõ¡m³Ù°ÛìäååÑÔÜŒ¿£¿?@("‰`E£X–µý‹li³Åßcv;Áíx¼^|>6[üý×Õ•Ñ5‰ % 2dtÿ 6:„ÓéÀ—šŠiš<ü‘p8 ,K-²ÓººÈìv;§·Ë…×ëÅíöàtvžyÒ0dÈR€!%Ñú`š8,ËJ´2Ø:»3"‘‘H¼õ!¦³ÊN2®_9\.7.—§Ó‰ÃáÀf3] 2Ô(@ÈÒ½û"#â¡Â†ÓåJt]¨BvEbŒCWW†ÍŽÓéèl‰V …Š dÈ0 #âÜN§+ñ!îp8ˆö  ²³º·éêÊèjå²Ùì‰û»æj dHé>ê=þ` Èx‹uµÐEDvcUDDD’¦!"""IS€‘¤)@ˆˆˆHÒ DDD$i """’4Iš„ˆˆˆ$m·Hªçub‰‹Y–EÔ²6ŠD"D"Âápüg$B4! ‡imk£²²’p(Ìܹs™2eòî*YDDdÀ|øáG¼ûî»8œ Iõùp8â—ˆ·Ùí8ìvìv;‡{çï¦ib˜æV/â¶;O§®IšNe-ƒ’ß ¾¡ž¦¦f:üÁÄc]iÛf³a³Ùp»Ý¸Ýn2ÒÒHOOÃáp$úpUU]MUU5N§“”/©>iiiØí}÷‘P[WGeU56Ó$%Å‹Ïç#-5§ÓÙgëØtµ²†#šššhni! …ˆF£D¢ì6;v‡TŸôÔ4¼)^¼6›m ËÙi 2(µ´¶òáGóñ§ŸRQYE}}Câ±x“¸\.Ün7¹9¹äæf3~ÜX&އÏçÃétëñÅê5¼úÚRÒÓÓ().btY)c\®> ëÖ•óêëKq:œ”RVZʘ1£‡d€ˆF£ttt°fÍZ>ýü ihlÀðxݤ¤¤P6r$ãÆŽ¡¤¨{^g ËÙi 2(…B!êêëÙTQAuM-­mm¤úRIIñÒ à ‰R__OskKü²Þ†IqQ!…Cî‹,~¿Ÿ†Æ FfF:ÁP¨Ï¯ThllÂår’‘‘F0²¬>]Ç@ŠÅbX±@€êêj**«(/_OUu@h4J,faGhoï ½£¿?@(Ö•aeÐS€AÍétQXXÀ(·›ñcÆR:rDç»…¿#€?`ÍÚu¬Y»–Ï>ÿ‚ººfNŸJFzưi©©Œ(.&-=œœ|>¦Ù·C¢|>Å……8]NrrrHõù°Û†ÎGN ˆ„Ã455±|ÅJV½ÿ‡—ËEYéHòrsÀ01Mƒ¶öÚÚÛÉLO'ÕçÃét ë0†Îÿf–ìv))^r²³˜8a<“'NHõÓÚÖN[[;‘H„ú†ZÛÚ¨­­#';‹éÓ‚¤ZVŸiY™™Œ3oJ ÙY™¤¥¦öi÷@zz:£G—á°;ÈÊÎ"==½Ï×1"‘MÍ-TVU³aã&6UT0ª¬ŒââBF—0¢¤»ÃÃn§©¥…¦¦&œ¾”<ÿ CÀÐùß,Ã’a˜¦‰Í´a·Ûq:‰Am¦ÍFŠ×Ëøqc°Ûí¬úàVnÚDCc#`€h4º[qÚ“ååçár»±Ûí¸].\î¾ÿ›“ƒÓáÀ4L\nn— §ÓѧëHÁ@€›6²fíZÂá0ùùyLš8™Ó§‘’’BJJ fçûÓív“•‘Í4±;8;ÃÌô–A/"lf¿êx ° Ã0YW^N[{;D"¬Î aFb}Àï' &ÎK‹Å—ßu,¶×ãÆíö`ômmí´¶¶b˜ñy-Ëê\FËŠñ£BâËðàp8:Ï!  …âçF‰ÅâÇyÛíx½¼^oâ¸nˆ÷»‡B!ü¡`P8B4Á²âýé¦iÄCÛÝù…íŒï‡^LÓÄn·a·ÇTéÝimm%àpÄ›ÛÃá0ápËŠbY±ø2l6<^^'q\zb†‘Xö–Ö …hmm% át81M“P8L$&Ÿ'Æì<¾=¾oç:l=ö},#ツBa¢Ñøkg§›i#‰‹ÅðùRHñ¦`³Å÷kKk+­­­!Ô†ÛßžíµNƒA6UT²®|=PRT(:zô—æÕ`IŠ dÈ3 có W:[Lcóï]]ÍÍͬ[WÎ¦Š jëêhii%jYØìvr²²ÈËËc̨2JG–b·÷ +ëÊËY¾b%§ƒì¬,Áõõ´¶¶â÷w€)Þrss7f ÙYY4·´ÐØØHeU5555;ƒKFF:éŒ3†ñãÆâé –eQßÐÀÚu먪ªNtÍC!bV ·ËEZz¥#FPRRL^n9ÙY_Ú'«×¬á½+IOO§°°Âü< p»\@üÌå+VÐÜÜBNN6v»úú›šiïè  áq»ñ¥¤0nÌÆŒMZZéi©‰/÷òõX¾b%.—‹¢Â ò)ÌÏÇëõÐØØÈò+©©©%''·ÛE}} Mtttþ¿½;mnëÊÖ<ÿ?ó€ƒà(’â kòNß̺·:ntG}Ÿþpq£ßߪ¬ÊÊ̶ÓéA²-‰â q&1gî€)‘’E§m Ôú9V p2¸ì½öÚØ¶ã8ÜZ_gc}R±H±X˜<Æx¶©Ñl²µ½Ãóý}ŽGEµqcµZ ×qh¶ZDqÄG÷ïsçöm' Y?áï_þçÏ$ IDAT~‰ãº n®,³¾¶†cÛ¯ý½òƒ€ƒÃCžïísk}õµ5Ê¥Ò?ýû*Ä´!®­dôŽÞ÷}úýišŒfìÞaÈ`0àðð'››l>ÝâäìŒv;{®jÕR™Ù“S ]§P(âå\ïqzÖà¬Ñ¤ÛíÒï÷1F]÷?@QUn.-áy¹ÉsÏ<ìòý£Çlïìp||L§Ó%NbL#{^¶e±·¿øx9•ået]Ã2Möö÷ùüï_R,˜©×q‡å¥¥×ˆl&(äôôŒã“>¼w—……yt]§ÑhÅqÙ–bC70ÌléÂ0LTõý[6×q팷Çù¾ïûlïìòàáwt»=–—–˜ŸÅ¶-ÔÑ D³ÙâÉæ&Û»»ì¢&¿ûøc ù:áùÞÍV‹|ÞccmõÂõAH·ÛeqažÛÜba~Û¶9<:âó¿É7ß>àÑãÇ †C>þð>µz•ÕÕn®¬Lê&þó¿ÿ‰§[Ûáûžç±¾zÛ¶Q˲(‹ä yfÎmÁì÷ûì<{ΣÇOøÛ³çœœ³¶v“;·?@U”Ÿ ¢(¢ÛëQ,æ¹±¸È·ná:q’ðÕ7ßðÍ·ØÜÚbgg—å¥%Â0¼0ÛñSÆM˜r®ËüÜ÷ïÝtiüêÛo…Íͧ<ÝÚbnn†?üþ÷X–…¦iœ5<üî{vvwi¶ZÌÍÍqçömn./¡½N—o¿ÿžv§Cœd3c®ëR«VñòÅbç'ê^£ú•0ŒŸ½½}=yÂññ1G''Ù2 KK7X]^&ŠcŠ…"š¦£iïw7T1ý$@ˆ©æû>GGÇloï°·¿Ïÿþëß÷ç €0Q5•r¹Ìòò Vo®°0¿€mYÙÁnqL«Ýf{g—v»Í·nñÁƵj Ûv²úRÖVoE1»Ïž±óì9¶Û—^O!Ÿgnn†å7¨×j 4]§\.³¾ºÊ ?àððˆ$I¸±¸È>`vf†¼ç‘¦)Q±0?ÏÆúíN—ÓÓS:qœ¼ð7W–IÓ×u']5ÇÁ0MtMãÙóçt»]|ßçôô Ë´(‹W~}Çfvv–•åeæfg)—KºAœÄ,/Ý IÎ ¾>¢×ïÑît(À•¶(š¦Éìì Ë7–˜ŸŸ£R.c: pcq4Miµš<üþ{zý>NÓ4°mû…Y¡66X[[åÆÂ¥R)Ûý`YÜI?ÀÐuŽŽ8=;{á±EáæÊò¤ÀÕql*å2æ%…§cI’àûƒQ³(ß÷yº½4Eayi‰µ›7Ñtn7 ±V“‡?ü@Š‚ëæ¸±8Ÿ=Î{Ü‹DL? bªAÈáÑ1GÇÇ|ÿèñ ïã("Šc~÷ñG|üÑG¬Þ¼Éï>þhRÅ1aÑn·yþ|8Ž©VÊ,ßXÄ˹0Úia™&s³³DQ̳çÏÙÛߣÓé^z=ž—cqa…ùyª• ù|~òµ›ËËt»]¾úæƒóssl¬­ãºÎd©#ŽcææfY»y“?æÙî.½^ï…Žž—#—s/œxk™ÙÒiJµRaÇÚÅ÷}Í&•rùg½¾YÝF7©×ë“Ç17±L‹o¾}Àp8¤ßïÓív±,ëJ»LÓ ^«±´tƒ™™:¥Röiš²8:‘ðÁÇ£Z–>Ý^ÇÍf(šÍ&;»»Y@[[åÞ½»TËåI¡fš¦ ,Ëä‹/¿¼ôñ—nÜ`éÆ7¾Þ$I‚ ˆ àùÞ>šª±¾¾ÆÆêjV0:7ËÑqö»ùç¿ü•/¾üš¦g£–9i©.Ä´’!¦še™Ykêù9æ™­Ï’…¿ÿž‡ßÿ€ifEkÙtñSÆa޶u£ˆV«Å—_}ÍÉÉ)ŽãLþ¸ÇIL¯×£Õj³½»C†£¹7§ë:¹\ot<ïx<ŠãÉLÈ‹m[”JELÓ$Šã¬%2?Þ&Žãli¡Û£ÑlÐjwèõz †CâQÓ¬í݆þ ‰£èo!­ª*–i’Ëå°,kôœ²z†¬…ó?ߦYQÌQ(²-;ÛNŠ’m}õ}TEaèûDqŒa  ùü…m«/þÔÿyªªb˜Y1¤¦iF€Ö×VY[½ÉÊÊ2ž—½.•r˲88<âàðÛv8<:¢Z)³¸0¹ÜO>žï* bªY–E¡P V­ò/¿ÿ”ûwï’ŽÎ'øþãÿåÙó=,˺t­9 ³z…Þ¨/ÄY£Á—_}Ńï¾CyiÈI’„8‰ ÃUQ&½Þ”®ëä¼sb|Ÿ— ¶¶m¿ ^z¬ìp@£Ñ`sk‹gÏ÷8:>¦Ùjáû>Ý^“Ó“l>ˆ£ˆ4ýeĸÃórØçšPEQôÂrË?Ë4ÍI_‹q0ˆ¢xrÖÄ`˜53 ƒÂ(@üÚuY_ÓÌNu5 ™zõµ5ÖVWX^ZšÜÖ²,*• §gg£‡GGÔjU‚—j1„˜6 ÄÔËú:(“†Eišbš&óss|xÿAðãÇÔªU>¸u Ó4²mœŠŠ¡èZVu_«Vùäã¹±¸ˆ¡¨ÚË!i’’¦YˆPPøðÞ½ßüy&IÖ¯âÙó=>ü޳Fƒ8‰Ñu••eÖuUQhwº|ûà‡ÇG×¶ÚÜ»#M’ K9¿I€u=Õu]Ó±,gÔÙó2–iRÈçét»´Z!¡¦%® bê)çÂÃùâ½ùù9>º|ý5ß>|ÈÍ•e†þ\ücwGÃ0²° ªT+þõàÓO—uq¼¤nü'ßÐ_¿ÕïÂ5rµ©tå£]Ïžïñßÿçÿ¢Ûírcq••en./3;;ƒëº´Z†Ã!~`™¿~€PEIùUÇm%EQÒÉ‹8ÙGú›†ˆñïŽ9:çÂÐu,Ó|a&æe¦iR(ä9>9uô ¯Õɤâý$B\Kã@°±¾Æî³ç€B£Ùbsó)Q173ƒ®k£ýÿ6¦a¦ N—n§ƒmY“ÂÆw…øt:=Í&­vÓ4¸¹²Â·6¨Öª LÓ$ BŒQ/ƒëºMÐ0 lÛ²mTUÅšÍ&­VÏËý&ʼn†aP*•¨”ËøAÀþÁ^Þc¦^¿pÛq½M’$8£6ãïëAnâúß`q-©ªJ¥Rf}mZµŠa4[-=yÂÁÁA¢ë:®cã86–idˆ§§1ßöS¸À÷}š­&­v‹þ`µxÞXçÞÝ;,ÌÍ‘Ïç³FHº†¦ª(¿tõà;Ä0 rž7ê*ªfÛU ÍæoV[`:ÕJ™jµÂp8d÷Ùs:Î¥·ŸûÅ1®ëÊiœâZqmºŽ¦ªÌÌÔY_]%M?Ù¤X(²zsǶQUB!ÏÒÒ Ù?8Èβ²õm×u1 #+fm ãxrXÕoi¼L£( QÑï÷G­Ÿä=UÓè÷ûÙ§gt;]‚ øM¯ñ·¢iÙB±P`~nŽ0ŠØ|º…¦ª$iÂl½>9°ìì¬ÁÓ­mÚ¯èݱ·0ù¹ÛvÖ/£\.cüÄi™Ùó´[mŽNNxòô)µj•J©<Úq“c02ô‡<{öœ§[;är.‹ ÌÎμ¶×„Ó@„¸¶Æ‡gÍÖkܽý77ÙÜÜdnf†A@\(¢ë*ÅBµµ5Â0bçÙsšíùbÏ˦£u]Ç÷}†Ã!Cß'*åòo 4M›¬³'IL³Õb{g‡|>Ç…LÓäðø˜íi6³]ב¢¨ºN©Xdey‰ÝÝgüðø1ý~/ }ºëº }ŸÍ­m¾ûáÎÍ ÷“¦)Û;;üù¯%ïy“†_^.÷“¶,n,.2 y¶¿ÏãÍMÊ¥ù¼ÇÂÜš6ÏÉég›[Û<~²ÉÝÛ·YYZbqAÚY‹é'B\kŠ¢P­Tù`cƒÓ³3†Ã¬3ã³çÏÑ j%;¨jcm•4Iˆâ˜^¿ÏÞÞ>qâyÙ²@E¦8NvĶmÙ¿ùÉ‹†aËå¨U«¬,/gçkìï„!»»Ï±‹ápÈY£Iœ$äó×·QÑø8õj¥ÌÝ;·1 ƒÍ­m:.ß}ÿÇ'§8¶=jUÞ¢óÒl̸4$MS:.{{‹yâ$anf†ø  àR.³´tƒµƒ› ý!QòèñcF³õ‡ÃÉ1ãËK‹¬,/1?7K±X|eÁ¥ÓB~ƒÅµW®”1M‹'›OÑuf+;<Ë4 ¼\ŽB>ÏÆÚ:Žã ë:O··9<<à‡G?Fqœb9×emm•µ›”K¥ßdËày¦‘m?]\XàÃû÷x²¹Éóý?ÙÄ„–Ë¥l‰eNve\gµj•?ü0;Ÿ#NØ}þœ¯¿ý– Ñ4 ×q©×ª(£sO€sÅ¥ÙŽ ß÷év»hºF.×ÏŽFƒ-–º®S,²Œà# …<;»»|ÿèq¶ f8ÄvlÇaéÆ"ÿå`õæMfggȹ®Ô@ˆ©'BL%ǶY\Xȶә&ÅBá…¶Ñ/ßÖÐ ÖVoò/ŸýžB!OµZÉMÒ²­œº®3—Ì!¶m³¿¿ÏÉéiÖé0Š'¢^«Q*•.LU«U¹ï.^.ke}Ù;LEQ(òÜ»s‡j¥ÂâBv&Çù$ëDiS*•X[½É0XY^Â0ŒÉöÁj¥ÂínáØ6ù|žV«Mš&X¦E¥RÆór¤)èšF¥R¦V©’{©ãáL½ÎG÷ïS.•X˜Ÿ§X( Ÿ»ŽB>ÏÆú:³³3,.,P­T°í‹S±²¼Ä¿þñ¬¯­Q(ä'»jÕ*÷îÞÁv²ŸU©X|¡Kd.—cmõ&ž—-ÁÔªÕKüR…‹ÙüÁÆ¥R{´ûbÜ`*†Ã/ïq||B¯ßÏαmjµišðtËå¬Ñ@Ó³î‘ãz’™zûwïâz.¥b‘j¥‚®ýôŸÆ¬¡”çy£¶Þ&–eb&Ý~~·‡›Ëáº.«7WØX_£^«áº®Ì>ˆkA~‹ÅT*ò|xïëk¨ªŠ®ëxžwém³~ wïÜff¦Žaèç–"²AQQ¼\Ž••effê ïÞ!â$!MÒI£ë:¸Ž‹íØ/Ì>¬®¬P*Ð5ÛÉŽÎ>¿Æ=îU1S¯óßþ¯ÿß÷©TÊä¼Ü ·¢(òylË"Ÿ÷¸sû6Åbá…µXÈŽ_œŸç“>šœ.™…)M×!·‚6F= ^˜××V©TÊFv€”mÛç–;êµÿõ_ÿHE8¶ƒíØØÖÅÁÝ0M~÷É',--Q*'!AQV–—(äó¨š6yŒó¯I¥\âÿò¾ïOŽÒ¾l묢(|tÿ>óssä½<¥bqÒ²ÚZ-;üìÖ­u? Š#@™,UŸðýx¾·‡i˜ÙÁc£ë¼ukZ­Š> 97‡e½ùÒ¦i”J%\Ç¡V«ñá½ûDqDÅYo]#çºYÛoÓ”™qmH€SÉ4MjµêÝv½~sÔ^Ú4Mßçøø„=bóé®ë²0?Oµòêe,!Ä›“!„˜Z“Žœ§g£( år9 AÀñÉ û‡ôº=nÜXäƒ[·þ©z!Ä$@!¦V’$DaÄÙÙ?<~Ìéiƒ$MPMÓFç‚hll¬óÁÆë««¯Üî+„¸ Bˆé¥d[5£(¦×ës|rB»Ó!NbÛ¦Z­°~s•õµ5V–—™¿l[‹âg‘!„˜Z¶eQ.—ùàVÖ`jܲ:It]ÇqlJ…âhÛjñm_®׊!ÄÔ÷Ì( Ü\Y~Û—#Ä{Eö2 !„âÊ$@!„âÊ$@!„âÊ$@!„âÊ$@!„âÊ$@!„âÊ$@!„âÊ$@!„âÊ$@!„âÊ$@!„âʦº•uÇÄILÇDQDš$$iéÛ¾2!„âTEEQUt]GÕ²“bUM{ÛWö³Mo€HS¢(" ||ˆ?…!QA* B!Ä;DQÐuÝ0°l˲1L SUAQÞöÕý,S Ò4%Žcâ($ð}‚À'‰ã,Õš>uOI!Ä{@QU%Ž"†é€$IHÓM7Цp&bêFÛ4M ý!ÃÁ€0 Ã˶ñ\ݰ0 eJÓœBˆë)MSÂ0$ }†Ãl ‹£ˆ( ±Õqßö%^Ùˆ”$Iˆ£ˆ ðý!ŠªbZ¶ãâ¸.†icš¦!„ï”4M ‚€00@QIÓlLóý!ª¦¡&I’0ME|S Ò4% CHDqD>W"_(¢é:º¦£ª*„B¼kÀÐu4ÕE7LÜœG§Ý¢Ón>$ CÒ)ªá›ž‘¤DQ€ïH’MÓ±l›œ—Û—&„B¼ž¢ jÚh¶Á |ú=$‰ñýQ&Ó ¦¦D6ýãã‡hºŽ—/`šÖÛ¾,!„âg1M /_@Óuüá ð§jbªD†A€¦i¸9c”â„BˆicnÎCÓ4‚ %Œ_Ëdûf¢ª*–eOu!„ï7M7°•žª‡!qK€øuŒvaÄ1Š¢b˜æÛ¾ !„âgÓ4 MÓP•8ާnÆÔ,a!„âÝ!B!„W&B!„W&B!„W&B!„W&B!„W&B!„W&B!„W&B!„W&B!„W&B!„W&B!„W6E‡iýzâ8¦ÓéÐn·9::âôô”r¹L¥R¡\.S.—QÕ³V† ‡CšÍ&GGG´Z-ƒišbš&žçQ¯×©T*¸®‹ã8oéÙ !„¿< @EñäÉþú׿òå—_rÿþýÉG¡P¸ †Ã!§§§|ÿý÷üå/áñãÇE¥R‰¥¥%>ûì3>þøcæææ$@!„¸VÞËÇ1¾ïÓëõ899áè舭­-677ùÇ?þÁƒð<ÙÙYz½Þ ç³GQD†ìîîòõ×_³¹¹ÉÞÞ¾ïcY†a†!‡‡‡|õÕW´Ûm>ýôSlÛÆ²,L9†\!Ä5ð^ˆ0 i4ìììðùçŸóÍ7ßp||ÌÉÉ Fƒ(ŠFç²_äû>N‡ðÿñt:–——ùì³Ï˜››CUUž={Æîî.<àË/¿`ff†r¹,B!ĵð^ß÷988`ss“ÝÝ]NOOQU•jµJÇDQ„®_þÒt:¶¶¶xúô)Ïž=Ãq–––øä“OXZZBÓ4fgg±,‹gÏž±··ÇÓ§Oyôè”ËåßøÙ !„¿¼÷2@ ¶¶¶ØÚÚÂq>ùäVVV(—Ëüçþ'þóŸqEQ.|ïÉÉ _ý5‡‡‡Ôj5VVVøýïÏÝ»wÉår(Š‚çy¸®Ëññ1ÃáF£Á_|çy¬¯¯¿…g,„Bü²ÞË ( Žã0??O½^çöíÛÔj5vwwùꫯ^¹ÔpvvÆÃ‡9;;cff† VWWYXX˜Üf\tyëÖ-ŽŽŽèv»|óÍ7ܽ{÷·zzB!Ä¯ê½ …BO?ý”[·naš&¶mS*•HÓôÒY‡óšÍ&Ožú€‡òÝwß±ººJš¦T* àÕj±¹¹ÉÇÙÙÙáîݻܻwÙÙÙ·|õB!Ä/CÄÕj5>ùäNNNøÓŸþD«Õ¢^¯“¦)·o߯q¶¶¶øæ›oøöÛoÙÝÝåßþíßøì³Ï˜››{Û—/„Bü"$@\‘çy,,,pçÎþøÇ?rzzJ£ÑàóÏ?g{{Ã0h·Û4›Mfff˜››ãÎ;ÌÏÏãyÞÛ¾|!„â!âŠÆ½ >üðCt]çÁƒ|ýõ×üío£×ëÏ癟Ÿç£>âÃ?œÔ?ÈöM!„×…ˆs Ã`mmÿ÷gaaùùyªÕê g]Œ·sÖëuEÁ²,LÓdvvvr\w±Xdaaû÷ïsûömÊå2¦i¾Åg&„Bü²$@œcš&Ÿ~ú)«««X–…mÛ¯HËuÝ7º½BqH!„B\™!„B\™!„B\™!„B\™!„B\™!„B\™!„B\™!„B\™!„B\™!„B\™!„B\™!„B\™!„B\™!„B\Ùç­ iš®“$ ?DÓt4}Šž‚B1Gq‘$ š®£i ¼íËzcS3¡(Y€Ðu$‰ñ‡C¢8zÛ—%„Bü,Qá‡$IŒ> Š"â§( †abÚ6IÓëvÿm_–Bñ³„O¯Û!‰cLÛÆ0L ¿EU0L˲‰ã˜n·ïoû²„BˆŸÅ÷ºÝ6qcY6†i¢¨Ó ¦¦€@Qt= IœF!þp@«ÙÀ0 tÝÈj$4 ¦(Á !„x¤)qÇ1Q†Ù i:–e£ëÓ51EBE7tLÛ&Š"¢(Äôú¸¹¹œ‡a9¨ª:U?!„×_š¦„QDèèõºô{=@×t 3[ž× E™š…é …MÓ1M‹4M‚€0 ƒ€]´¡ÏP—!„ï˜4%Œbâ8$ Ò4A7LLÓÄ4-4mºÂLY€€l)ô,t]G7†C( éu²u¤4IHÓôm_¦B1¡( Šª¢i†a&Haà¬IDATâØ.¦ma™6ê”í¾›º jªª’’¢ ¢Ê$4Ä) H€BñîP·"0²% ÓÆ0 tØÚYó© ( šn ª†i`»9™}BñΚÌB¨*ªª¡¨êÔ†˜æ¨ª ªŠ†Žñ¶/F!„xLWņB!Þ  „Bqe „Bqe „Bqe „Bqe „Bqe „Bqe „BqeSÝHê<é@)„bLã¹—‘!„B\ÙTÏ@ÄQDÇÄqDE$IL’$Èd„Bˆw‰¢dÇ/¨ª†¦ëhšŽ¦eÿžVSyåãåŠ(ŠŸ0ý!QE‘,g!„x§(Š‚®ëÙiœ–=:‘ÓBÕ´É×§ÍÔˆ4M‰¢8Š‚€0P°,˶‰B!Þ%YŬB!Þ“7ºd= #+¤LGoŒ§i bjú@Œ× @SU×Ê¢!„@× ×ESÕ,@„áTÍ@LM€Hâ˜8 QUÓ²döA!ÄÔÒuÓ²PU•8 Iâøm_Ò•LÍœ¦)I’G1Š¢b˜&Š2UùG!„˜P5 CUP•87Bœžˆ© ÀdϬ¢(¨ªö¶/G!„øÙEAQ²ƒi:]á¦l C!„ï B!„¸2 B!„¸2 B!„¸2 B!„¸2 B!„¸2 B!„¸2 B!„¸2 B!„¸2 B!„¸2 B!„¸²©: Cˆ_ÓOõ¡Wå7º’é5~ åµâú“!Þ[Éè„×Á`@·Ûe8âû>ae§â‘¢ª*š¦a&–eR(ð<UUQGƒäxÐLÓtt8λ3xž¿6àg]ß›<¿4M99=åäô˲pl›œë’ó<4U&:…¸Ž$@ˆ÷V’$„QD·×ãàð³³3:.ýÁ€0ŠHÓ]×1M/—£Pȳ¸°€mÛ躎ªi“cæ!DÕÑ`ù®„ˆìÛtTU½Òµÿþq€¸ì>Ò4åä䄇?<¢ÏS)—™©×°G„×”ñ^JÓ”n·ËÉé)íN‡A¿ašÔjµìh]RÒÆÃ¤¢*˜†¡ëhš6™}èõût»=¢("Š#¼œG±Ç0Œ·÷äFâ8¦ÛëÑëõ‰ãlV¥X,R*ßø>Â0¤Ûë1 ‰âMS)‹x¹Ü…Û¦IÎuq˲Ðuý RBˆ_žñÞÏ´;vvv騖E¡X V©÷ C†¾?y~f“(ŠÐ4ç†Î`0À݇ëº8¶=¹>Ó4±L Ë21-k²Œ1 hw:ÄqŒa(dK$QôãÏAÓT ÃÀu]lÛ=·ß÷ñ}Ÿ$IH’MÓ0 Çvp]ÃÐ/ìIÉÂâp0`8„!a’¦€BVÓb¸Nv/¿? Ýi`Y¤„a0z½U/—Ãu]ôÑÒŽïùï4}qwAgÓüQ½Qí¸óô쌃Ã#& ÓírptD!ïQ*•¨ÕjÌÍÌÇ''œ5èt³q”6†i™Ôª5j• ÅbáÒÑj·yºµªiTË%â8¡ÕnÓëvé‡X–É…EJ¥"Cß§ÛírpxÈáÑÑä¹v»]žïíQ*)•KÌÎÌ`[Ö…gGGGÒlµ&»0š­&¶íP.©”ËÌÍÎb['gg<ÝÚ¦ÏS.•(•J” cROÒévÙÚÙÁ÷ò^h÷zôûß'Ib,Ë"çºÌÍÎR«Õè÷ûôû}Íf“0 ‰¢Û²ÈårÔëuæggQÕšvnæhôs ‚€Ó³§§§´»º½>i’ (àyyÏcvvÓ4/}¶;žnmP.—!MiµÛt;Ã!ºa°´¸Àìì,¹Qˆâ}ò¦¿ñ//ê^m!Uˆwˆ¦©˜¦‰aš†AEœœžàº9ÇÆ4Œl«æ%[EA×4,Óœ¼ WU•8Ipl×uñFµ–i¢ª*QjtMö,ؼóŽÂˆf³IèûŒg0ÆË)cãq…av¿Q„¢d;D,ÓÄ0tôÑ»óó×—$ i’à¸97‡çåpã;%T5› ¿eš$I‚¢ªY‡\Žœ›Ë¶´Ž‚ïû´;4MÃu¢ÑVØÉõG½^â8ÂÐuÒ4Å2M4U¼>Ý^ã“S†£‡qÑ«mYèš–…µQ¬®ëX¦Iš¦x^n„¢(¢?Ðn·i¶Zôú}r®3¹Ï8ŽiµÛX–…¡ë£çôãlÌøõÏ\èšFÇ (£×ÆD7Œ+oâôò˜þF…\? Ò—þ^ò@BL]×ql w‡^¿Ï³½}Zí•J™r©D!ŸŸ¼«ÔF䘢(xž‡eYÄ£)õ¡ïµj•ùù¹É÷š†iš †C Ã$ïy˜•òd ?Žc:½n—v«Íéé)¦eR)—³éø08õúƒ9Ç¡\.ãU*†íØä=Ƕñ€|.Gœd³aÅ1óós,ÌÍaŒÒxWÉËLÓ¤R*e{œ`™&A¢ë: ósÔk5t]ÇÝÇUDqL¿?ÀËå¨TÊx£fSaqrrÊY£Áñé)û  …<ÅB¼—›4ÿ:9=åàð([ÒQ³m·¦eNf‚ àäô”³³3ý>i õzR©H:Z¾:>>æøät2³1;3ƒcÛfc†Ã!ƒ~Çu©”J”K%LÓÀ¶³×ÛuÝIˆbŠ%ü8ν6H¼.@\Î1•Æï®ó^Ž™zF«Åp8`0pv¾ÐëvÉå²wضecšÙzù¸N­Ÿßk'òù<µjwT÷0¦ë:9×Å4MÇÆ2MU%IœnÓ4éw{ôúýI@PTó’%•q 0ͬ3f¹TÂ2ÍÉ:žUÐ5-»>×Å×4Â(¢X(0S¯ÿä;fMÓÐFß“s]|ßG  à\*Q¯Õ^¸ý«vf\F՛ضM±P \.£›YÂÞÑÍVkRcP(¨”K@¶4E­v› iw:8ŽC½V›Ìxø£úF£‘5ó<ÊÅ"ÕjF߆!ýþ`4u–-‰¼âyŒû€Œ_oÛ2³Y¬ÑïÌ@ˆ)÷º1þ•ãý›,aŒSIrî#þÙ—)Ä[6þc_(XYÑ(µÛ4›M:.½^V«…ª(˜–I!_Èr‰R¡€eYW~Ç `è:Åb$IÑô—&R˜,‡´š-NÎΈã„~¿i˜¤Nzap²m›üèÝ{½ZÍÞÁkê$ļkí´_fè:…|>kHåyض±ª*¥b‘8ŠétÚ´šYÂl½Žã¸/¼îžçQ.—'5 Ãá8Îþ,%IB´Ûmº½7ŠEfêuq\–ZƳ œûº†Ì@!„ïš—Çò˜Äø#äÅYˆó!âÒ ñS»0. çÃÁùÏŸ  „BˆwÁe« !/.c¼.@\êU5ʹPáÅ`0þÚùY í’Û !„âí9?“0㥌ð¥—k!ÎßÇ ^71®¾Tx1DŒïhü¹Ë–.$<!„ïŽËVÎ×D\Æ·½Ôëj Î/S(/}í|1Æùe‹q]„P !„ïŽWµe8$ÎQžW®?zÉÄùY‡—gdB!„xû.kËpYƒÈ+5“zÝ ü¸|qþóã;yÉB–.„BˆwÛË-«_ //]¼²ò§üó¡àüòÄe¡áå!aB!„xû.;Ûêü¿_>,ó'ü٠ÿr0P/ù¼!„âÝvÙ®Šó!á²r…WzÓÁþUu Rï „BLŸô¥ÿÿÔç/ø¹¿Ì8!„ÓíŽíB!„B!„B!„B!„¸Îþ]*Ò¢øÎéIEND®B`‚././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gtk4/display-widgets/images/progressbar.png0000664000000000000000000002175515074674453025624 0ustar00rootroot‰PNG  IHDR©5¸ysBIT|dˆtEXtSoftwaregnome-screenshotï¿>&tEXtCreation Timedom 11 dic 2022 21:27:35ÁòT IDATxœíÝwxU߯ñïn›H€„4 E)B“.¢-(F‘GA¤‰ð(åPPŠ"h¤I±7•^BOh B$´º;ûþ±Ùe³l’Ͳü>^s%™ræLâÜœsff„B!„B!„B ºƒå9ºl!„}ôE|[nçWY|µ\&á!„sÐc=4ô_KÅžÜ2Ì6ÿ^mO…„§|5Ë@)*`ŠTšð°li¨Í¾Z —ÒTDqÇè ¾Z†ˆbe¾ù×b¹Ú¸sk­ µÅ÷j‹ùÒòÂ9¸p3,Œ_ çiQQb€ØÒò°lUX„ 7ÃùCˆ!œßÕûBëŽ0‡q²ìÎÙ}).<̯¦»(ÆÐp|€ÆgOŸ\‰^/ãB”'*Uþ}¡u£€#À ›bìÊX^)\DQESø*ŠèkÁW ñ™S'V« ’CFqWéáZí°z0H.†UmÁWóU«­[.§šw[Œ­¿?Öýú¼‡å— *ý±î×ç1\èpçæX¦ñŠi±Š Ë{9,Ç;üëÖ {äv+/„([ç±?7ÏmcCÁò^®[wµÅ²ëb,Ü ðQ©UÑ;ì!DP©U1Œ_ºqs¬C‡áœ×SøF²Bl¹ÏÃòÞWÀS¯èUr=VˆòM¯×«O wYŒS±—k­…‡å3,–cÆÉqÏö !Ê’ùym9æaþµÐ)_Ü€©e«Ã¼û"Ï­ñïa~^[{ÔĪ¢º-Ö¹·¸-]ÚBüK˜?jbmÔê¸GQÝË»JÝ &wÓ$Ù!Ä¿…»Ùd~·© ÖŸÀäᵚ0‰3gÏ V«©V¥ M6 ªß3Tñõ)ãÚÝ–Ç\¹R%Ô«ÃÀ¾OS#8èŽíK¥RQµJ‚éÚ±=íZ·r辄cÙ÷ZÃã¡fM8qê¶nçøÉSÌþß4ÜÝþ½wæ÷zôòµ:>ÂνûIøû4 çÍF­vüW›V¨Õ*ÒÒÓ9rô(‡þü“»÷2aÌkß—pŒÛhyÜ+ña8ί ¡’·7YYY¼1i)iiìÝGÛȈ2®ß`8æþO÷ÁÓÓ“œÜ\^6ŠK\¼ôÕýü¾¯á/=§§''OâÝ>b÷¾ýlܶÎíÛ9påWŸƒiP¿ÿ=‚J• 7w_ËÌdæœyüyô8?¬^vWë#Ý–Ròôô¤C»Ö|ñå7¤¤ ôPZG<„_Õª¬ß¼êÕýxoÊ[(ŠÂ·?®e[ì..^ºDHp0žz‚æM›˜ÊËÎÉañò•ì‹?ˆZ¥¦KÇöü¼îwz=Ú}Ÿ,¶üœÜ\¾Xó {÷Çs#;‹ûÃÃò|”éäÞ½/ž¯ø‘ÔÔsxzzÈë#‡SÉÛ»Øe–*xxPÅÇE§Ã¯jU®]»Æêo~àà‘#\ʸBåÊiÑ’¨¾O™ZcEÕ»$uÃÂ<°sİ~ÃSx”t¼ý£‡Ù²<*°{_jµšÝ:Ó²E3/û‚§ÎP­jþóÂs4¬`ÓßÈYÔ æØñLzgÓÞJ¥bÊ;39s6‰ Çv'maûSLVŽW«5|$d_Ó:[¶ïäë~ÆËË“ûjÔ=|¶ô V~õ-...4mÒ˜Óg™6sG0•5{Þ§lؼ*>>„× ãûŸ%''·ð>‹(ÿý¹óë¯W‡–Íšè0ï¾?E§~þ3çÎãòå«<Úµ3‘-[PÑÛ›J^ÞÅ.3?æŸ~ýoü…>YHJZƒú=Z¥=¸»y°7.žêþþD¶|E§ðãÚu|óýÏ%Ö»¤ß/zˆhnè&&§¥™æw¼Æ²6o‹åÀá? âò•+¬Xó5£ÆO$/?Ÿª¾>$%§ðÁ‡óÉËË·ùoä,ÓÿMxÀÎ&¥0iú &MŸÁ™³IøW«Æä coÿÿñR’–G)(ŠÂ™³É¬ß¼WWW7h`Z¦V«ywò[Ô« À?—2øcãfj„3ë·qqqaýæ­Ì_ø9߯ý•ûë×#-=}ñð«V•¦ÿ...üº~#Ÿ-Y~˾-Ë?“”DÜÁÃ4oúc_}€Ü¼ód‘õ¶•F£A£ÑƒN§#)5µØã5þËëååÉ‚YÿC­V³ê›ïøê»éܾÃ^Š`ĸÿ’œšFjÚ9*z{—ø7r&U«TaúÄÿ2qú{œMNÀ¯ZU¦Nµjw½>·1`z‘U=7t¸é{µZÍ Ï $ Àßô{Ðh4Ô­SÛôsbr2Š¢Ð´IcÔ.jôèiÁü…Ÿ“œšŠ=É)i4it¿iŸÊ†¾¬¾à?#ËòSR ÛÆ8DŸƒ Õõzf&õê…Q#$˜ƒGþâ?#_'$8ˆgúô¤}›Èb—™[¹hžžždçä°bõ׬[¿‘5ßýÈ[¯àø‰“üòûNþ}š«×¯¡×ë¹~-³ØzÅòxóòòÈÉÉ! ºju‰ÇkÜV­vA¥6|lV½0C`©\T¦åuÃÂHNMãZæu.]¾\âßÈÙ¸¸¸âîænúÙÍÕ 77·2©«´Æ% zuÖoÞ Àß§Ï ÕZ~†®íb–®ÀÅÅ… ÿáä©ÓhµZìGíš5l:^{Øò7r&gÏRû¾šL?ßʆVÆÔ‰ã™6c–!øï2¹ÏÃf¶Ätáåã^{…¥«¿"þàaâ"¼nx† €ê¦uß5ŒO/ãÈÑãèt:ZµhΖ;­–gùóÁ©VÕ—Í;vòÝÏ¿PÝ:¡¡èõ Š^¡Fp»öÆ‘_Õª¼ý „sêLb‘ËÌ÷ñÃ/¿†AÈ @^ˆêG›V€žáuxæ‰^ü¶a3›¶n§ùƒMˆhÑŒ3‰I%ÖÛšm±»P«ÕT硦òTŸÇ ‚ãæ¶Å¯ªÐDXÛŸõ¦ˆ-#gñýÊ%f?êæ[¹³ß}»Ð¼»ÅÚsæOÏŸiÑLž€7ñwÂ_³ïV%ï%¿oØLÌ’å¼üÂ`ºuîPÖÕ÷€:á Ç{€L Ã;^²1|–©ñsMϸ˜È£õeL§ÓúyoÜjÖ )‹êa3û»-ÎÕ¢+·6lÞÆ†-Û¨W'”¤ä4þ:~œ5¤~:ò;NMÆ<ÊX¥ŠÞäçkÙ¸u;>•*Ó£[¢ú>‰ü~…³“«-e,²e "[¶(ëjQjòH¾Â.2æ!„°‹Œy!ì"—j…v‘ðBØEL…v¹S‰!îeÒmBØÅî–GjÒGÖCQÎØé[1o[>ùº’×-Kß Ì.y%!îA*• ïJöú˜ÝÝ–òBˆ¢éõz2¯]µ{{óBØÅîðÑÞ 7GVEq7Ýn·Åî1ÞzÑûA»÷{ý;_F-DY“n‹Â.B»Hx!ì"á!„°‹„‡Â.B»Hx!ì"á!„°‹„‡Â.B»8ô¥O‰§8Ÿ–Rªmª…P+,Ü‘ÕBÜ ÄS èõ í»>ŽZm[ƒFQŽÿOâ© !ʇu[Χ¥P¿Q3›ƒ@­VS¿Q³R·V„eϡݖÒ‡-Û\ºt‰…K–±gß~222ð­â˃›0fä«TªX‘衯ðDïžôz¬ÇíT»ÔróòÐ+ *TpÊò„¸œöE×yyyŒû Âë1{Æ»T®\™‹ÿáÀ¡Ãx{y•iÝ–­XIrj Ó&OrÊò„¸œ6<Ž'œ 55•‹?ÃÅÅð©CU|} ¯W·Œk&„'¾T«ÕéÈÍËã\úùb׋?È /§c÷Çxö…—8tøOÓ2EQX¶r}=G—Çz1f›œKO`Ê´w˜4ušiݼ¼<º÷~’|jš—MÛÎÝHMK3Í[±z KV|Á†M[hÓ©+ïÏù€üü|æ-ø”>}н÷“¼÷þl²²rX´tƒ^‚NgøÐ׬¬z=ݵ¿ýVdyB8;§ †÷7 ,´6/¿6Šå«VsáâE«ë¥ž;ǸѯñÝê•4lx?oNù?òóóX´t9›¶l彩o³l᧸»¹1|ÔXòóóiצ5qñMå§NX(wï^dyB8;§ ww>[ð1ýž~’/¿þ–>}0iê4Nž:Uh½ž=Jƒðp|}}5€K¤¤¦’——Ǫ/¿bÂØÑ„…Ö&8(ˆ)oNàÆlÝEdDK®]¿Î™³gؽgƒ£ðÏ¥Ë$§¤°/î­#[•X×YYü´ö†<ÿ¾¾>øûù1tH4[wÄàææÆø±cY´d);wíæ×ß×óæ¸×üâîrÚððÒhxv@~üz ï¾=… /òâËÃo £À€4 YYÙ¤žKG«Õ^¯ži¹F£¡aÃûIL:‹——ÍxÀÔúصg/:t 2â!vîÞÀ¾¸xZ·Š(±žIÉÉ(ŠÂ„ÉSx¢ß@žè77§¼MVV¦ihL×Îxý͉Œ1ŒjÕªÞίFˆ2ç´¦æ\]]éоíÚ´fÀàh6mÞJݰ0«ëªT†wèæçå¢( :®Ðå`w77<<< ]—ñ´k z…à Ú·k˺ßþ {×Τ;ǃM—X?o¯Š|þéªøú¹^ppŠ¢àá.—dEùçÔ-K...T«Z7w·×   cFŠ¢p<áuj× áð0»öì¥Md¤a^d$Gþú“í;wñPóf¸ºZÏW­Vkú>0À/†±;‹¬ObR+V®æµa/óÁÜÉÌÌ,´Ü¼Ô€€€êøU«Ê𝾡mëÖ†í¼¼hܰ‹–.£Mãþþ~8t„ôôódggãêêJÔÀþÌÿl{ãâP…ó.p,!0„ÖôÿÍdÐÀþ ì×—õ뺪cYžåCÃCQ‡mS©R%æ~4¨è!¼4|þuŒùsfs_6•=fä«D¶Šà‰“‰Š~‘ë×2™ûÁ T*•iömÚpérM74ÍëЮ-ééç‰lÙÒj¹vëJ“F Íĩӈ~vƒ£0çÃytîÑ“a#Çp€•_~EVV6û>Àë£F°aó&öÇ(²^êÏ0M<• "D9ã°nËù´”R}ø1€Z­¦~£f¥n­!ÊžCÇ<òóóÙ¼m;Ãþ3•Ê…={÷ÝVy/¿ô"oŒsäºBÜkœþE×»÷îÃÛÛ‹ðzu‰x¨9›·n£}Û6…ÖYóõ·üøóÏ\ʸL£F 7ê56lÞÂ’_°iË6úô|œq£G=ôžèÝ“^õ`âÛÓÐxxðÖ„7Le-_¹Š¿Ž%0cúÛ…Ö]±zÍ-å]¹zO†·Æ»¹ýªÕüù×Qf¾S¸‹=ôÚµmÍö;9›|–ÚµjóÆèQ8t˜^Ë… hÞ¼oŽ‹`P^±z ¿¬ûŒËWhÒ¸ãF½F`@:ŽÏ/á÷ɺ‘EëV…_™ŸŸÏ§ ³qËVrrsy¸m[F†§§¼h[Ü>§oyü±q#íÚÞ#ÛºU+¶Åî$??ß´ÜxrMyëMV.]L÷.]ð©\™gô'úÙAtéÔØMë7zä-ewë܉í»vzåå¶ØtëÜñ–u­•×¥cGvìÚUhû±;éÔña«Ç²?.ž7ßË7«VÈóC_æü…óÌšñ.KÆ’šÆ‚…‹Më/ZºœM[¶òÞÔ·Y¶ðSÜÝÜ>j¬éøÄ,d×Þ}¼ÿît–-Š¡‚¦p(ÌúècÎ&§°$æ–/Š!--ù11%ÿÒ…°S‡Gvv6;vî6…GdDK²²²Øþå]ºb%ãÇŽ¦~x=üªU£[—Nh4›ÊŒh‰V«åÏ£G¸”‘Á™ÓgŠ|Áµ¥Ö­Z’““ËÑcǸ|ù 'ÿ¦]ÁK³-uïÖ•ºuêPÅ×—¨~ýÐëõDõëGP` 5k„ÐóÑî>|0 ~®úò+&ŒMXhm‚ƒ‚˜òænܸÁöXÃØÏ7ßÿÀÇ¡nXŒ1Ü´¯YYü´ö†<ÿ¾¾>øûù1tH4[wÄÚtlB”Ä©»-Ûcw¡RéiP/œììl<5ÂBk³yëv"#"H;—Nvv6 êÛwˆ››Û·cGì.š4jÄŽ;iÓ&’ lkÖ{xxжu+vìÜE£†÷³c×.Z¶hŽ—§g‰ÛÖªu9¹¹¦yµkßGVv6©çÒÑjµ…l5 ÞObÒYj×¾¢^·®i¹ù‹‡“’“Q… “§ *X¢ÕiÉÊÊ´éØ„(‰S‡ÇúM›ÈÊÊ¡ëã½ Í¿xñÆMfæuÀ06àââb×>ºvéÄœç1ì?/±u{,OôêYªí»tì@Ì⥼üÒ‹lÛKç"º,–¬½a\e67?/EQÐét….g_Ï™Ÿ—‡¢((Šbõr··WE>ÿtU|}KuLBØÂi»-™™™ìÞ»f¿Ïî­›LÓwkVrõÚ5â"((EQ8–Pd9Z­¶Øý´hÚ”k×39qò$ÇN”xuŲ¼VœOOçÌÙ³8t¸È.Ki‡„pðÈÓÿ¿ÿô½ÃZBÜ-ž^Þc€=@&dLù“P &‡ ˜× %5é4ÛÖ¯-Õv~A× uT5ÊÄÖ;hѬ™‡¸§8,<<<<®Š_`Rmg¼zPžmØ´™'{—î*åC/Õzxx”û (­ä”4Nþ}ŠvmÚ”¼²ÿ"N}ŸGyP#$ˆ›7”u5„¸ëœöR­¹Ix!ì"á!„°‹„‡Â.B»Hx!ì"á!„°‹„‡Â.B»Hx!ì"á!„°‹„‡Â.B»Hx!ìâÐGòO%p>-¥TÛT ¡V˜}ï]B”‡…Gâ©ôz…ö]/õg˜&žJ¢œqX·å|ZJ©>ü ¯=¨ß¨Y©[+Bˆ²çÐ1Ò‡-ÛLš:Vw¢ÕÈìЙ^O÷ãÝ÷gqåÊÓ:¿Àò•«lÞ_ôÐWøé—_‹\ž›—GNNŽÝËK2iê4æ~<ß®mEaÖGóx¤gú Ì™ÄÄÛ®örúÓ'ûôbã¯?óÛOß3mò$ŽO`òÔwLËnÛ¦Ðû\oײ+ygæûv/¿“~þõWââ²jéb>™7—!!eZqosúÏ0uws3½Òà&óÚ« 9šYYxyzòòK/–q ¤î§jÕªe]!œ?<,U¨àJ¥ÂÕÕPõ衯ðDïžôz¬:Ž˜ÅKøcÃF²³³éо=ñ0gæ B‚ oS‹?È?ÿ™ÄDB‚‚x}ÔHhÒˆ«×°d…á•›¶l£OÏÇ7z¤ißE-W…«×ð˺ßȸ|…&1nÔk”êØòóóùtáb6nÙJNn.·mËÈáÃðô¬Àÿ>˜Ík`Ýúõ„ÖªE·®‹­¯wR¹ ½^OÚ¹s|³ˆ'zõÄ£ˆwÊÎYÈþø¼ÿÞt¼½¼X¶r5É)©…ÖI=wŽq£_#À¿:1Ÿ/áÍ)ÿÇ_­æÙýÉÎÊ&95…i“'ÝRvQË-]Nì®]¼7õm*Tð`Þ'1 5–/W,ÅÍÍÍæcœõÑÇüóÏ%–Ä|B¾6ŸiïÎ`~L ãFdÂëcðòôäêÕkLüï¦mŠ«¯w’Óy¬ùú[Ó€éSþU/â_×ÜÜ\¾ýþþ;n uà`ôˆá·¬×ó±Giޝ¯ƒ£p)#ƒ”ÔT+%–,//U_~Å„±£ ­MpPSÞœÀ7Ø»ËærndeñÓÚ_òüsøúúàïçÇÐ!ÑlÝkW½„¸Óœ¾åñÌ“}ñÊË(ŠBTôTjk¯×5H;w¢^·®i^Ñk ÑhÈÊʶ«~©çÒÑjµ…m5 ÞObÒY›ËIJNFQ&Lž‚ª ÖZ–¬¬L»ê%Äæôááââ‚{AåÙý™óýŸy/OÏ[ÖÕjµ(Š‚¢(¥ºl¬Réí®_~^.Š¢ Óé í³´¯ÑôöªÀçŸ. Š¯¯Ýõânqún‹¹tÃã_}ûÕåAÁÁ<|ä¶ö£Õjm^bØç‘›ûT…ã '¨S»¶Íû ðÇK£aGìÎRÖ¶äú q'”«ðpww'ªï3¬þòk²²n½1ÊK£á±î0cÖlŽ;ÆåËWX²ü‹RíÃßß‡Žž~žìì[»2–˽4zöèÁÌYs8vü8—/3gÞÇøúøÐò¡V÷‘“›ÇÕk× Mjµš¨ý™ÿÙ"öÆÅ¡( ç/\àXBÂmÕWˆ;Å¡á¡(ÊߦwOÃÛè¿ùÞzëcìÈ4oÚ”1ÞbЋ/‘›—€º˜±svëJ“F lÁ ãAIDATÍÄ©ÓmZ>fä«D¶Šà‰“‰Š~‘ë×2™ûÁ T*ëûüá§Ÿy¤gŸBÓ… ‰~vƒ£0çÃytîÑ“a#Çpâ¶ê+ÄbíÿnuÁä ¸Lš‚Éð"²ndÎ6ßèôÉc¨T”êùãƒqz=„Ömp‡Q´K<þä3lùc]‘—w…¸—yzyö™@]0åLZ@)˜L6`\3”Ô¤Ól[¿¶TÛù\3ÔQոʼn“' ”àÂÁ× Å/°F©¶+íU‰’$&%‘””Ló¦òOF bÕ¿¿ÃÊBØ–×2­Txxx84ì‘y=“%+V2yÚ;øûUãÉÞ½éÓóñ2­“NÎò|¶éÞ…’ÂCoñ½ÞÊŽœJ£†÷³$fAYWCˆòFáæ9nTlˆ7²i-8Ì'!Ä¿Cqçw‘çº-—EŒ‰¤˜M:»«)„p6: Ÿß6õ0J Å쫱@NÞuB”ŠùymÅžçÖÆ<,›.æc: ×|µž^Þ#÷‚É­ ,nÞ'bÛ]YBˆ;ͼç`<‡ó¼‚I[0™ˆåùK÷Å–Sóà0î8¨P0Ä•›¢¢œÝú.Ä¿˜1Lÿøs38r &cxX «Š ó´±–XÆÖfË]–‡ÎÈò<Öq3<Œ“ñNRóñb/×ò(*<̃Á|¾yx¨ðÂYXëAo=·%<¬*jÌCeö½q‡* ‡‚q™ykÄÅÊzBˆ²eÞ‚0†ƒ±û’o1YŽ}˜—QHq-ãH«ŠÂb,È8ÏZwE‚Cçb­'a>b-8nyÎ\qcæ]•Å2óÁó®ŠqDK…p.EÝva"æ¦æ¡Qê1ãŽÔV 2†‡ykòÕ!­!œƒµÛ.¬ÝøYªÅŠkyÀÍ.‹ù|cá–Ýé®áü,oC· ËîJ‘ƒ¦%ìæ`Þ%±–á!A"„s°öœšù÷–½–`Û n j+ó%4„p~Ö®ž˜„µá‰"Ùz¢5Ž!ãB”Oz‹¯%Í¿…½'½´4„(ÿlþì!„B!„Bˆ{Åÿ Mã¸`ìÖIEND®B`‚././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gtk4/display-widgets/images/spinner.png0000664000000000000000000001513315074674453024742 0ustar00rootroot‰PNG  IHDRï†5‹Ý+sBIT|dˆtEXtSoftwaregnome-screenshotï¿>&tEXtCreation Timedom 11 dic 2022 22:40:18® Ñï»IDATxœíw|å™Ç¿Svµ«Þ«å"Y6ÍvŒml ´8T‡’pI(!äB.´˜b ±ƒ $98åhL'˜:Æ]¸€%˶ä&«[Ûgî-^­WÒîJHZô|õy?³;3û¼ïÌê·ÏóÖAAAAAB(ߢ½þ¶-ÉŠÙÍë>Ñ)ÛÈc"^Aðc]´fÄ6.X¤0Ã߇¿V) |1ÛpG º;wK<âô´jØ6šhµx "ßa|m¤ˆ(û÷=¢Ç˜y4ïªF¼V#ö‹ç?ûÅÜøuÒ`{p,ž7Ò«F Tc¿xÃEl‰Á¶ Ô8Z#UÔzowasä¨*K YCI´3{÷Ÿ—7È%†(Ö°>ÚJ#ú $@&ôŠÃédñkoòÉçKÙµ§‘T»Qååœ}æ,&vXLŸ¿âê9¨ŠÂãÞOJŠuJ;¿»þfjëêP…¼Ü\ÊJJ8ñ„c9樃\:¡'ïpp¼†apç¢û¨^»ŽŒŒ _ÅžÆ&¾\¿3fÓ=°Z­Œ,ª(è}ÈÞ·£gLGUvîäËõëY³v-þ×_ýÛÁ.šÐ }ð¼Cõß°ÿ¨©­¥zí:9hwÜr#J sÌéraµXˆå¨ªÂÝóo Û3Ô<ÿqÙE¤¦¦°iófî¼û/|¾l9ï~ø!3=f0 8d8ëÜÙ|Ð8n¸êJ23ýƒ Û::Xøç¿²výW,~úïZ ›{ ±©—ÛÇë l))¡sιø—œüÃÐÞÞÎò«IKOã¬ÊÉ3OèrŽÅb則þ+ôþ¨éÓ°Ûl|ºt9†ipÊÌ8÷§?éò™ÞÎqº\<ùÌ?øbùJö9:9düx.½è|Š ºØ(ÈËcÉûRTTÀ]·ÞÔëuWUV2û¼Ÿsï²ä…ÄK~G1[ŠÏ—­@UUN;i&GL=œÿýû“lÜ\K~^.—_r!‡4ðG7/¼ü~ò{öîeDYçžýc¦Lžÿö-S>¢Œ _mäæ;pûMsP…[ïXHmÝVF”–xyïò1¿û©ª²«ÕÊæš-üúªßóؓϰuëö&j½üÚ›lÚ\Ë„ÃaïÞ&þöðc,]¶²Ç%ÆÞûàc–¯\CyY)íí<ûâˬXU×9º÷¿xãíw?n,G>™•kª¹óO÷bøŒ}ô)Ï/~•´´TF•—xÝ|ŸÓ§L`[CC\ù½ÿá'¬ª^ˈ²Rš[Zxâ™çùÝœ¹¸=òr²Ùºm;wßw?n·Lxè±'yê¹Ð4É'PS»…Û.bý†ƒþýG¦?\-%Å…ÔmÝÎÍópóüÔÖm¥0?Ÿ[®¿&qÛ "ž·òrr˜{ÝU<úÄÓÔnÝÊâ×ßäå7Þâû3Žà²Ù¿…N9ÙYÜ{×íhšÆÇŸ/åî¿<À›KÞaúÔûµ––Êý‹þˆ®ë¼øòk<þìó¬]¿)ß›Ó9µ[·²bu5S&Oâšß\ø#„O—.£açÎ'PU•;o¹‰qc+âºv»ÝŽÝnÇápâóùØZ_S~ii©<°è¨ªÊÿýãEž{ñef{ ¿¾ìb®¼î¶Õ7Pß°ƒŒôtÞ~÷}ÊG”±èŽÛÐ4%ïÀýÿó/½ö‡4.®2Ûäåæ2î ÌuÛ¶PŸÇ¼¹s(ÌÏðòô¡Áª?IÄ„CfÑ]·±ºz-|ü)Ÿ}±œ>[Š¢ª\õ—`Ñ-¨šŠ‰ÉS&£( õ;vpÂß«ª†¦k˜˜T« µ­=æs¶×7°bÕÎ:ov—|Ú;:Bvìv;UcÇôú}™¿ n·§ÓIqQª¦ÆœŸªj(ªÙˆq•þ ESBÇ«*+ÙVß@[G;{››1 ƒÉ'„îß÷œÎýÿóÛêë‡äÿ˜¦éX-û{ ,º‹Å2(eÏŠ¢0yÒ&OšÀÌãå–;°vÃWQÏuº\]¾àÞеÞk/‘礧§0eò$.þÅ9]Žõ‡¨^·Ó4U>2áüTõÀëÒ®Ãéôß+Ÿá ís¹Ü(ŠÒ¥]a¨ÐÜÒÊ-w,`{}C(ÒØÞÐÀ­w,dÞÜ9ädìb2Rçí!yÜ6×lé²Ïëõ/5”•ª¯8:÷u‚ kª×þé˺¯WF»‡qž3²¬UUÙ¸ñ2Ó3(+. %‹néÞFwõ­°};vìæ‘ÇŸFUU~ö“3Ïö™P^VÀò•kBuà•«×`š&£GF©Ÿrº}á=!áΛ;‡ysç0¢´”í ܾ`Qâ¶DAHR›‡VD3øÈý©óör?„EZ›ûÈÿ=ü·Á.‚0L‘)‚¤HW’©ó B’"]E‚¤ˆx!I‘+AHRúÐ`%ò„ÁDÂfAHRö¼õ[kû³‚ ÄIÂâ~ÌLÚZšiÚ»Ǿ}ýV(Aø.cOK#7¯Ììœ>ÙéÓðÈÝ;êiijÄšb##+»O„á‚×ãagýVœŽN Kʶ“°xÛZšiij$5=#áÌa8¢[,è -MØì© ÛI¸Áªiïn¬)¶„3„áŽ5ÅFÓÞÝ >añ:öíCµIW‘ $)"^AHRD¼‚¤ˆx!Iñ B’"â„$E ‹“––ž}éV¹ŽÖÖ6²²29xÜ8.¹àÒÓÒp{<˜¦IŠ5öõgþ½qÕ ·pìQ3øñéýó8–þ¶'ÄŽˆ7<óþ™Š1£¸ñšÿ$##¦¦Ö½‘T»€_y»vqÕ¯/”ü{cÚáߣbô¨~+SÛbGÄ5µ[عk7wÏ¿5ôøÊìÌL*FLšüÏûéOúµLýmOˆox ·ÇÃîÆFŠ 8¾øõ·xá•×øì‹œtÂq\:û| Ãàå×ßâ½>¡­­ñãÆrÙ…çSŸÀœ[çsÜÑ3øtérê¶m§¬´„ËfŸGå˜1qå‹­9·Îç¤ÇÌ㎠½Ÿ1õp–®XŶúJ ¹töù4nlÌÇã±gO¿°˜?]ŠÓåbúÔÃY·á+nºîwÝ^“i°ŠƒªÊ F–—qó yéµ7ÙÛÔÜåøY³Náì3fqÔô©<÷ØC\:û|ž[ü*Ÿ-[ÎuWþš…ónÆ¢[¸õ®?…žõ ðÞ‡Ÿò‹sþûÌgüØ n[pû:;ãÊ?[á¬þr¿¼èXôGªÆV°è¯ëR¶ÞŽÇcï‰ç^`uõZæ\ýλEQر+ññ½ÃoX-î¸ùfôCÞøç;\qõïùó²eÛ¶n?ãñxxõrùÅ0²¼Œ¢Â~{ù%8N–­Z:ïÔOà ª±äæd3û¼Ÿ“•‘Á'Ÿ‘Pþ±Ø çØ£gP1z$Y™üäôÓhnmí"¨ÞŽÇjÏíöðÏ%ïñ«K.dty9ùy\ü‹sºµ#ôŒˆ7Nì6gÍ:…ÿ¾w!×üæWìmjæ†?ÜÙ­€wíiÄëó1fÔþF””ªÆVPß°#êgTUe\U%;vîêsþ=ÙŠFA~)))8®„Ž÷tþ®={ðcFí¯£G{Ƭ"ÞÑ4éS§0ïÆß“Ÿ—ËgK—G=Ïè:2Œ.VÅ¢[°Z»Ÿ•¥)*Öº›bÍ?[‘(½(ª·ãÝïóy1MS/ìD¼}DUUrs²±„Môù|¡×ÅE…€É†›Bû ä¦v #ËF„öu:œ]ì~S»…ò²ÞWYˆ–¢¶¾mŠ ÷âëM½ž+ôŽˆ76~SÃ#O>ÚµëÙ½§‘»vóüâWÙ\»…£Ž˜ @^n.ë¿ÞĞƽ¸\.ì6?8özô 6×ÖÒÒÖÆ£O=Mff“&²ýüâWX¶j mmí<÷Ò+8œNfL;<îücµ5Øm6ŽÿþÑ<øèã|SSKk[;ÿxùµÁ.VÒ"]Eq‘îÁôè“O³go))V*Gæ¶®¥´¤€ãŽ>’Ukª¹êÆ[8ôàƒ¸áª+¹ä‚syòÙXpßýø¼>&z(s¯ûJXü9ñЃyâ™çinie|Uónü=º®Ç¬¶‹¿ð<{êî¼ç/¨ªÆ1GM@UÄÄK´Ú‹H:` ${ ¥éÀôŸ}x,:×?Dö•[Ask+¿üíµ<õðX‡áÊ,í­-L9òØ«¥@Ð 8ÉH^À¤òs' *[ê¶R\X0,…ÛW†F,% êvP¿s‡4ž–ÖVžzöEÎ8í”Á.VR"â”}^xùuî{à!rss8yæ œx±ƒ]¬¤D꼂0ˆHW†!"^AHRD¼‚¤$,^{Z^§?Ë"à ¯Çƒ=†¥‹º#añææâv9{?Q„¨¸]Nró_€ ᮢÌ윎ÎÐ#>å¹E‚^·ËIvn~ŸžÑÛ§~ÞÂ’2löTšöµ¥/¦aØ`OK£¸läà>\ü¸¯…!~¤µù;ŒÏç;`ể ü`š&--­|S[CmͶnßFk[cFâÈÓ©=š”””Á.¦Ðψx“·ÛMݶm,]¶œ5Õ_²}{=-m­8NÜn7†aðÅŠ\|ÁLŸ6µwƒBR!âMB Ã`oSŸ/[ÎÇŸ|Ɔ¯¾boSS—åw‚lØð5ÿúècŽ˜:¥Ëä!ùñ&^¯—ú;x{É»,yï=¶m¯ïqA7·ÇCcc#>ŸoȬ¦!ôòm&>Ÿmõ ¼¸x1o¼õv ©IµÛ)+-á~‘o4I0M“=¼òÚk,~õu<1 MµZ­ŒWÅÏ^Ÿ/ ^0M¯×+ÏJÄóq:::Ø´y3Nçs§gLÊ´)‡“šjKÈvP¼†ÏÀÄÄðùðºfÁÔMñ¾CïçëMßàv¹CIAh³Ù˜6m ¹9‰Ïè2MÛaš˜\QU<ºß“…GÄ;ÄinnÆ0 4M‰·¤¨üÜÜ„'(Š‚Ï4ñz}~ûªŠašø\nUá&"Þ!ŽÃéÄçõ…Z€MÓÓ¤° ›ÍÞ7㦉ÛãÆ0LtMCQ Ó2•0 ñq¬V+ª¦¡kú`MÓDïÏð¼^¯ª¡ª ª¢¡ë*†! VCï'Õn'ÅjE·X(üû]N'ím Ûõw™ø|^¼^/þEùýØíiXS$lêHWÑ';;‹ììlt]G×5,º‹n¡­½ƒíõ;îÒ1 —Ëž}x½^ ÃÄ4Ágx}žP–0tñqrsr1¢‹®£©š¦¡ë:.§“Í55457'd×ívÓÒÚŠËí„Î^'^¯]Ó¥Á* ñq²³²[1EQÂÕH±ZQU•ú†–­\wã’Ï磵µ–ÖV¼>ÿÀ ·ÇƒÏð¡ `±è¨ªük uäâØív&MœHNNº®¡**Šª¢ë:§‹Ï?_ÆÆMßÄlÏ0 š›[ØÞЀÓéÀðyñzŸ—˃Óå`çÎÔ7ìÄåq¡kº¦ãöx0MÐTUÕ(È/ä«bEÄ›(ŠÂ¨òrf<|ôÞÀ$]ÓQUQÙ¹sŽN55µäççc³YÉÊÌÂíöÐéèÓ¤ÓáÀ–bCÓU‚NÚgX-V<^/#GŽÂn·É˜æ$AÄ›DüèÔ“innfÃW_…¬éz` ŸŠËí¢µ­¶öl6+º¦“š–Šiú§ùÙ¬)¦ ^ðâU@×ü‹Ú•–“—›†) }D¼IDZZ§Ï:UUù¦¦—Û¢€¦ihš˜¼ bšŠâŸìóèššRèñxÐTEÑQUEW)).bdy96›U¼n! VIFYi)³N=™É“&‘›ÅbAUýVÃð¡ª*¦iâv»»|Ökøðú¼˜€i‚Ýf£¼¬”Q#G’––*ÝCIF¬ž7²S†ß "e¥¥œ4óJKŠX·ákvïÚ‰é_ÞÕ4QTEQüb4MPTEÁãñ`µZIMµ“—“CIi ………ØSRD¸ƒK¤žb6×›x͈×f”Œ„A //Ó§S>bu[·Ó°sìÛ×éŸUÃ0ðz½hºFªÍNJJ 999RXP@Vf¦¬çŠ¢ Z¢…!®úŠ)ÂíM¼FØ6hЇ„ÎCUUQU‹Å2ØEâ#\WáÂíQgÑÄéºÃëº>ü?½©iéWÖ@²liø[°U@úÁOxäÔpRpBu¸€#õw@øKƒU¸pƒ¯l°Î~+H7”  2äüØ/\g ÅMÀQéN¼ájö‹ô®„×Ï+шԑýâ &]½o¸€£Š¸·Öæhâ føþpñ*ˆx!H´ÖC×й'ñF¥»:¯ö:˜¡BWQ…{c-Êy‚0Ü ÷ AqÃgODЬû†ÛèBOž7ØÒ¥ÐUÀACÁ}ÑÂe® t%Z$^Ž&Üà¹Qé©Î+ÇÂ+ßá¡r°,U‚Еîº]ÃEÞ`.Ú¸ë¼ÁŒÔ(†‚â ÷¶‘^W¼¯ ø‰ÖímàS\5zò¼°?dß4&K¸,½9 2R°‘ár·V½‰-\á!q4ÁFŠW„,~¢Í9é§WáBl‹¥e¿ˆVz'Zëq¸@£UO»%V¡uW•ú­ $†±ímÿ$*:ñ´‚Ðwbž»+‚ ‚ ‚ ÉÿiôÖpŽ%GIEND®B`‚././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gtk4/display-widgets/images/spinner_ext.png0000664000000000000000000002266015074674453025625 0ustar00rootroot‰PNG  IHDRïãm²CÂsBIT|dˆtEXtSoftwaregnome-screenshotï¿>&tEXtCreation Timedom 11 dic 2022 22:52:38 URV IDATxœíÝw|SUÇñOVÛ$]é‚¶”UZödº@† ¢(CÁ­8*¸PAQAœ¸@E!"{‰L¡ÐM÷NgòüÑ&¤!]é"ô÷öu^ionÎ=¹õË9÷äÞB!„B!„⢨Çúêºn!\•¹‚Ÿk¥6SØ=Ú?'ᢔǡ5Û=Öˆ3³¦íï¶?+i!SÙ£mˆí]QÀ+T“ðÚ÷´J›GG¡UÕ¤!B\ÄJÊíClr°Üö±RêjnÜQ華ûYi·\z^!J©8VË£‰ÒœTØ*\ž×¾Wµ¨Šsáµ ±¦u ÑQ>´–RBù@ÛöÆU£«êyíƒk[Tœ ®ð/@[º…h*Š# $ieËT”¸„Ҝ٣-¹«0ÀÕ ˜}pÕeV>@ëõë~½;"<| ¼1ËL³å(0c&ëÄÉ“¿^3d؇Ài “sd±Ý+LT¡²)(LkÛËZJÐáÌ©Rb!DÕ2[µ¸8 $Q\K±NW8|®,¼¶³É–!²%´n€/ÐõÌ©_`6Ëñ­5¡Pµj1 øÈ 9`ËPÚ~6º|UMùYd%¥Pê²Gw kÔÉã+à]'oFˆ&Æ YmÂ#'PàJ'¶ŠËm'¶ö¾Õù8ÇvØléu_ûËí\!œ§ïß×þr;¥½nœ›K²|bS©ŠÂkÿY®ýñnPDDøµµm¼M]YŽ‚8—-KGi.Åy*›m¶:[*×¾ ¥Â sc-D“¤P*¼(?ÒpîX·„ÒÌ™)"G9Õùœ×þ³]5 3›Ì ùpss£eX ” jú‚ÝoýûöA©TŸ˜È?‡sàÐ!¶nßÉ“3i즉 Ô¢ç½Pÿ7¬;§¢¢8xè_:uˆäåçžFQöáX~An ÕÙJ¥‚7_zÞfÉ…¶ßJÛóà=·£Óé8qò$¯¼ùÛwífÖ-\=h`c6ð‚1fÂ:vˆä©éãí]zraVN¯¿õ.‡å‡Ÿ4h{dØ\‰”´t )*.. ,x¸»[×ǽ\{ÍUdgg³{Ï~ôžzÆ\7œk¯¾²Ü:Ÿ-yÏú{¿>—¡õð`ێݘÌ&†]}%Æ-÷šªÖÉ/(àó¯¾cçî½äóèÔ¾=wß>‰fåêô÷gÝÆ-4kÈ«Ï?SåûŽgÊÄ[x{ÑbÖ­ßd ou¶wyïKñp÷`û®=(•JF ½šÞ—^ÂGŸ|Îñ“Qøûqß“éÜ¡=P:ºYùã¶üõ7É©©´ eÂ7Ыg·šÿÁêYX‹PŽ=γ/ÏeÎ3³P(<ÿòëD‰¦EHHƒ·Çù|̉o‹››'OæéO°ü󯈎Ž=ïB­׬åÄÉ(ºvéDjj︜»öVz‹±?6oe÷Þ„…†Ã׫~dϾƒ5Zç·ßã—ß×Ó>²½/éÉÞyå·1•˜¬ulúsßþðz½ŽVaaç¿Ï þž}zõ &>¾FÛÛ¸å/ö[ATt4?ü¼–ù•}{sÏ”[­C'ƒ¯o¿:•JÅÖí;xóE¬]·ž>—^RaÝz½Ž…ó^C­V³êÇ5|úõ·:|„^=ºUk¨èhöì?H¯žÝ™ùÐT t„°mÇ.â­=R©ä•çž!²]Û½w­V‹V«Åḩ¤¤„踸jmO¯×±hÞk(•J¾ün߬ú‘« ä{îàáÇŸ"&.ž¸ø¼<=ù}ÃFÂZ„2ïåÿ¡R©X·q3 —~Ì÷k~¡S‡Èµ¹¾ùûùñÒ짘ýÒ«œ‰‰ 0ÀŸgÏ"(  ÁÛS‹ «Zü“áBºvîȼWÿÇþƒ‡Ø¼uïÜÍŸï@¡T2ýÁûШ5(UJ̘éÝ«' …‚¸„Äóö‘íïJ¥ •Z…3‘ádfeW{ظxöì;À˜‰SÊm';'ÇZV«%¢]›*ÿ^æ²ÿ, ÉÏϧy³@”*eµ·§TªP(Ko^ú†B¥°>NL\ÞÌåå–5GW,Ø^=d9§Y[Vt€'Ðç¿cÿÎo¨F^È&Þu?Þž^|°àÆnŠpQíÚwžìr€*ÂEIx…pQ2a%„‹ªÅ„•ÄWˆÆ$Ãf!\”Ó=o\tT]¶CQCN‡·ÏÀ«ë²Bˆ’Ó#/"EEE;~‚-[ÿâÐáÃ$§$£V»Ñ±}$×¹†Ý»áîva}cƒpž„÷"‘”œÌ/¿ýΖ­ÛÈÎÎĘ_@~~D>ÍÆ-2lèn3¡paQ÷dÂê"œ’ÂÚß×±s×nÌf3j••R”ÞÔJï³µzÍÏ|òù—$$&6fsE‘ž×ŲoÿAŽ;†F­ÆÃ׃®ú1x@šϪÕkøcã&²²³Ù°qaa-ÓhʾB¸& ¯‹‹OL$ál"jµ èOÿËûZƒÁ#S§À—_KNNûö WîtêØ±‘[/jC†Í..+3‹Üœ\<ÜÜéÔ±#]:u:¯GÕé<Ô¿?—^Rú&g¢c¬wü®KÂëâJÊŽiµzAxyy:\/4$Øz£ðŒôt2Ò3¬¢~ȰÙÅ©Õ*ÜÜÝ@¡@£QƒÂÑ AK¿ö¤yóæøúú¢Q«Ñéµ ÜRQ×$¼.N§Õàï1ÏHII ùFc…Ÿåz ­[µD©TÒ¾ý…õ%^¢æ$¼.Î×Ç›?Ζ$“‘•EJj^^^¿'H¯×[{…ë“ðº8ƒÁ@P` ™YÙ( âhÞ¼ZëzŽÂ,\›„×Å)•JB[´ °°ˆä”T” ™YY˜L%hµ:<ÜÝñðpG«Õ¢R©»¹¢Ix/z­–ð¶mÐé´¤•Í"—” P€R¥D©TÛ}—¸Hx/Z­–Ö­ZÑ,(ˆììŠKJP©T¨”JT* îÅHÂ{Q*•èõzôz}c7E4™ÅÂEIx…pQ^!\”„W%áÂEIx…pQ^!\”„W%áÂEIx…pQrz¤ž}që6l@¡P@ß>½yàž»ðõõm´vM˜r'Ç^ÃäIëeýÚÊÉÉá½–°ÿÀAÎ&'Ó2¬wN¾Á4Èö/6^'3šgâ’NŸŽæÍïðÜ‹/óÎü7­Mƒô§}dõïQÓõk#3+‹;ï{€Ëz]ÂsOÏBïéÉ?ÿþ‹ŸŸ¡A¶1’ð:ÉM£±^н[f<ò<:ܼ<ô:]£´éþ{îª×õkã˯¾¡SÇö<ùØ ë²Vaa ¶ý‹‘„·Žxx¸£P(P«KwiQQ,ýˆ ›6“_PÀàxôÁÐéJïnqǽS8 nÝÆ™˜3´i݆'¦Oc߃üøÓ’’’èÕëž~|&¾¾¾±hÉR¶nÛFRr*Í‚¹còm :ÄÚ†;îÊ ×bôÈÖ߯<ÍþEÔéÓ´ á±iÒ½[§Ö/))añGËø}ýŒF#W ÄÞýûxëõ¹„†sÇ}SéÑ­+Ózð¼ý³fí¯ÌyþÙúû4A2aUKf³™¸øxÞ_ü!7Œe½ùÛ¼wÞãLL,˿ϧ.&>>ž…‹—{íî={yú‰™|÷儆sû½÷s6é,óæ¾Â²¥‹‰‹gÑÒÐh4´ eîKsørùGŒ>Œ9¯ÎåLLL¥íÛ±s³fLcÕŠ/èܹO?ÿEEEN­¿pñR¶ïÜů¾Äò¥ P*ˆ‰Îû;:æÏÏÏ'5- ƒ¯ÿ{ùUFÞp7Ü2‘_[ý-Î#áuÒWß®¤ï૸üŠ«¹q­tëڅǧ? @n^«×üÌÝ·OÆ`ð%(0{テÍ[ÿ*Wǰ¡Cˆh×?ƒI·Ü‚ÙlfÒ-·L˰Œ>Œƒÿ±®ã˜ëiÛ¦ ¡!!L™4‘àæ>r´Òv:„ö‘ ¾L™4Ô´4bãâj¼~AA+¿ÿ§ŸADx8ÁÍ›3ýáò=쯼Äí·N:¯Îä”4,ü€~}ûòåò˜öÐT–,[ÎÆÍV¾£E…dØì¤qcÇððÔû1™LLºãnÊsw«ˆŽ‰Ád2ñäsÏ£ tyqI1yy9Ö׺u+ò ¬ËÚ´iEžÑhý=##ƒß×ÿÁC‡ÈÌÌ$-=‚üüj·9¸ys´Z-yyƪW¶[?>!“‰öÖç«{/F\;”!W_ Àà3úë7näÊÁ«ýÄ9^'©T*ÜʆȷMÏÂÅK?î&ô:žúÒÿY?þ`~†êͦ: ‚Âfi^^>wM}ˆ«âîÛ'Ô¬ÓŸUãv+f§Ö/..Æd2a2™j|'Jo//ÜÝÜð÷÷+·¼uË0Ž;^£ºÄ92l®#®Š»»߬\@pó ôZ-[ÿÚVgÛ8zü™™Ã­wÝCAa!J¥“ÉD|B"É))_Û­k^›ók~ý›'Mæ“/VðêœoÛ¦!ßÂEÅÑÀKYVÔ€¦¬hËŠðúäåæÌo¨FŠ SjZ×Ǧß×VøýH¢j:½ç `äƲRTVŠSY±’žW8íø‰´ –à6™mÕv::šèèzõìAJZ‹Ȥñã»YM–„WT[NvË>û‚çæ¼LP`c¯¿ž1£®kìf5Y^Qm]:wbÙâEÝ QFŽy…pQ^!\”„W%áÂEIx…pQµžmÎÊH'-5 cnn]´Gˆ‹žV¯ÇÏ?oßÚÝ¿«VáMJˆÃhÌ#¤Ek| ~U¿@Afz qÑäó uº§Ã›•‘ŽÑ˜G‡.=œÞ¸M‘ÁƒGí'+#Ýézœ>æMKM"8´¥Ó¢© mIZj’Ó¯w:¼ÆÜ\* Q >¿ZÍÉl³.JÂ+„‹’ð á¢$¼B¸( ¯.JÂ+„‹jðþðÃDFF²páÂrË÷íÛÇ!C0 0€Í›7WPƒÂ^½†wÏž=\qÅ<úè£å¿bãøñã\uÕUŒ1‚}ûö1räH†Îþýûë³IB\4ê5¼ü17Ýt'Nœ C‡åž{ûí·5jÓ§O§uëÖ<õÔSŒ9’·Þz«>›$ÄE£^ïae?L¶õí·ß²|ùòrËÆÏ]w5Ü> áÊeÂÊh4’’’Bxxx¹å‘‘‘dff’ÝÍÂ¥4Jxðññ)·Üß߀ÔÔÔo“®¦QÂ[QH333 jð6 áj%¼ÞÞÞxyyqâĉrË£¢¢ð÷÷G§Ó5F³„p)v’ÆèÑ£Y±bE¹e+W®äÆol¤ áZífΜIÿþýyýõ×™4ikÖ¬á»ï¾cûöíÕ$!\J£õ¼={ödíÚµ¬^½šÎ;³bÅ Ö­[GÇŽ«IB¸”ëy×­[wÞ²Áƒ³uëÖ†j‚¹0A%áÂEIx…pQ^!\”„W%áÂEIx…pQN‡W«×“™žV—m¢IÉLOC«×;ýz§ÃëçDB\´Ó¢©Kˆ‹ÆÏßù+蜯·¯­VÇÑCû¥¢2ÓÓ8zh?Z­®VßÑ[«Ó#ƒ‚CÉÊH'>ö4'ý[›ª„h2.ˆ/׆Ò¸¶BÔœÌ6 á¢$¼B¸( ¯.JÂ+„‹ª“‹ñÍfs]T#D“¡P(j]G­Âk6›ÉÉÎ"'3ƒü|cÕ/Bàá¡ÅÓÇO/ïZ…ØéðšÍf2ÒR0æå„ÎÓËéFÑ”äåd“’œDqQ!¾~N×ãtx³³31æåѲMxÕ+ !¬tž^´ôô":ê$*M¦Óõ8=a•“™I@ |³Î  "'³Â[o”¡²µ óô¢ sEòQ‘.JÂ+„‹’ð á¢$¼B¸( ¯.JÂ+„‹j´¯ø¼˜åìÙ³‡˜Ø8òŒF´Z-ÁÍ›ÑÿòËñpw§¤¤³ÙŒZ]ûÝ_U]Žžÿzå*"Û…Ó³{÷Zo_4 o+))áç_ÖÀˆk‡âîáA^n.ñ‰‰¸»¹°wÿ2³²¸æÊ+j½½ªêrô|›V­pþ´ÒZwë–aœŽŽ!##?ƒ/ûõ#>1‘#G‘››KHHƒ @«õ Ädb×®ÝüEII1­[µ¢_Ÿ>h4š ÛÛ"4´öxÓ%á­cÍ‚ñóóã‡5?ÓµKg"ÃÃÑÛÜX»G·nŸ7”õñöfØkP«Õüwê·l!((_ë:mßN¿>}¸¼o|¼½iê°®ª¶åH\|ƒôG§Ó±mû¾ûáGºuéˆk‡b2™ømývîÙÍàJÛò÷ßäææqã˜ë1•”°qó¶ïÚUîûöŠº%³ÍuL¥R1fÔutëÒ™þ9Äç_}Íú›HMM­ôu;uÄÏ`ÀÛË‹KºwÇËË‹¤¤ärë\ÖëÚGFàïçW'“]¶"Ûµ#ÀßVK®]èÑ­+^^^øøøÐ¾}$ ‰g(,,äÈÑc\zIO´èõz.ëÕ‹¨Óg¬½BzÞzá¦ÑУ[7ºué™èh:ĪÕ?1vô(üýý¾ÆhÌç¿S'I<›D¾ÑˆÑh¤¸¸¸Ü:jUÃü¹ †Ò[ùÚnßàëKQQ™™™˜Íf~[¿Ë¥ä&“Éú|C··©’½[”J%mZ·¦UË–|½r§¢N; oQQ߯^MÛ6m¸´gôžžüòÛoÐâŠÙÞïÁÝÝ€±×F§Õ6Nƒ„ ›‚R©D¯Ó¡TÛÝ&“ÉúsrJ ùôí}ƒ7†šÜŶ.gž¯)OOOÜ4Μ‘ïªjLÞ:v6)™¿þÞNl\ÙÙÙdfe±{ß>’SRoÛ½^OBb999¡Óé(,,äßÃGJ‡Ï'O’šZ½ï²¯«¦Ï;C©TÒ½[WvîÞEl|·Y¥R¡Õ{¡PªHI>KAÌ™ª_$„ÀÝÃ­Þ ­•Jåt=µ /€R鉻‡“ÉŒ³Ó ¢)P @©T R©¬ÅYN‡W¡(m€åÑl–à Q ……BR©D¡¨É•ÛåÕê’@ ®ΩMh-êäzÞºhˆ¢fä$ !\Tô¼2l¢f}Øl6›ÉJO'=-c^n­#DS Õé1øâm04΄•Ùl&%)Üìlš…„áíãët#„hJ²238CaQ>AÁN×ãtx3ÓÓÈÍÎ&¢cW§7.DSäíã‹·/'ŽüƒFãît=NOX¥§¥Ð,$Ìé ÑÔ5 #=-Åé×;Ýóæçåâåí#“UB8ÉËÛ‡ÓÿuúõòQ‘.JÂ+„‹’ð á¢jy’†ï ÑX¤çÂEÕò «ºj†¢¦ä[ëIjj*K>ú˜¿wî"-- ƒŸžÝº3sÚ#øx{SPXˆÙdÂÃã^¶ï¨þ[n›Âˆ¡C˜rÛ­õ²MѰ$¼õ °°§Ï¤cûHÞ~c.¾¾¾$%%³ïÀ¼Ên8¶ìÓψ‰å垯—68ªðÀthß¾^¶'ž„·9vŒØØX¾Xö‘õ6'~ÚG6j»¸÷žFݾ¨[2Û\ŠKŠ)(,$!1¡¡ç=ÿé+øø“OذqcG扙Ó0™L|úÅ ~úe-éétëÚ•Y3¦ܼ9Sî¾—×e݆üwê­[·â‰éÓèÔ±CµêŸr÷½Œs=×_7ÒZß زu+§££iÛº5³fÎdß|¿ú'’’’¸´×%<3ëq ¾¥ž±hÉRÖÿ±‰‚‚®8i?ˆN§µÖy˸›Xó˯>r„¹/Ï¡Ïe—ÖÏŽnâd¶¹téÔ‰vám¹çÁGøäó/IJN.÷üäI¸sÊm ¹úJ¶oþƒ'fN`ɲålØ´‘¹/½Èg-ÅM£áþ‡§QTTd}íê_ÖòðCSùöËÏèÚ¹3NŸIvvvµêwdçž=<3ë ¾ÿz¡¡!L¾ûÏ&òö¯ñéGKˆ‹gÑâ¥Öõß|ûÎDÇòé‡Kø|Ù‡ÄÆÇóÞû‹ËÕ9oÁ†ÂÒEïѽ«|{}©UxÍf)ŽŠ›Æ¥‹2~ÜM¬øæ[FÝx3Ï<ÿ?ŽøÏºeÅò{AA!_¬øš'{Œð¶m á…gž&77—Í[·Y_sóرtëÜ…ÿ¦=ô _~_ÿÇym°¯ßÑ2Ì0bèP"ÚµÃàk`Òø ˜Ífn?àæÁ„µcÔˆáì?øf3äääòÃOk¸ûŽÛñõõ%0 û﹋þY®Î{+ëÔz–„IDAT† §]x8îîþ÷¸KmÈ1o=ÑëtLž8‰7ãÏmÛøòëo¸ó¾©|¼ø}"Ûµ;oý¸øŠ‹‹éyî¸X«ÕÒ¥KgNŸq|Ol¥RI×.]ˆŽ‰©“6·iÝ €ü‚ürËòòò8‹ÉdbÖìÙ((½ˆ¼¸¤˜<»1x¸;™›¨>9æ­gjµŠ+ dPÿ~ÜrÛíü±q‘íÂmÖ(݇…E˜L&JJŠQ*5ÖgÝÔÜÝÝ8·¯ÍØîw•RYöqPE ûåf»eç~W8؆%¤`ÆK¯`ù’ð3*ÙŽý6D}cÞ¢R©ðGãv.˜ÅÅÅÖŸ-[û´.3™L9vŒvmÚZ—å”õ‚‡¥M›Ö·i[]nÞ ½NÇŸ[·Õi½Â9ÞzpèßÃÌ{ç]vìÚM|B1±±|¸üŽ;Æ5W^@PP{$1ñ,F£½NÇè‘#xíÍ·8|ô(iééÌç]ü|}éÓûÜlí‡Ë–³eë6222Xºl9¹yy\5xÐym°¯¿.¨Õjn8ž÷/açîݘL&Î&%qøØ±:©_ÔŒóÖoo/æ¿ó.‰g“pww§S‡ö,Zð­Z¶`ĵCضýoÆO¹Kzö`þk¯2sÚ#¼÷Ábz6ÅÅÅô½ô2Ì£ÜMÊz÷êÅ»ï@Jj*]»tbñ» Ðh4çµÁQýuáÎÉ·ááîμ¥ïÍÏ``òÄ t’“?œ£[×)ËŠДmYÑž@Ÿ=o™ß©»|~×n¿ç>Æ^?šÑeŸÓ ×wøÀnz]>h°ÈòcY)*+Å€©¬XɰY%³Í.Iö»žW—%V.dùÒ» â"=¯.ªÖßU$„hÕíyíSjr¸–ÂöyªV¯XUx°jðÐéÉÉʬvë„åådeâ¡Ó[~5áøÄó U^GÁµÉgjÜ`!D©ä³ øøÀA¾lV«0ÀÕ6[þE0Ù”½·:OO¢N•XˆÈÉÊ$êÄQtžžè½}J(Ÿ/ë·2UMX™l-–&•J…·¯?j•ÉI Äœ>éä[¢iñÐéðöñCçåe¹Ç™5W”n¥v^û®ÛöX·„Òó,‹½}|ÜÊŠ¦¬.çÎvþ+¿…¸¸ØŽ\-* ËJqY± °}þÎ>WÕóÚײá=€GY±X͹+Ï…°°ÒÚùq.¸ùeÅ^Gv¨¢ðÚ¦ÝÑ¿–Þ›çUHÏ+„#ö9*á\x-Årõíño…½.TÞóV^Û`Ú.· ¯ ¯ŽF°–Ëýª^‡*:æUØülÙ ‚ò¡´Ùûc_Û:Ê©¬çµÌt)(`KE–eކË\!Ês4’µ=vÜó.À·UÙ1¯íÐXa÷œíÁ·íPÙr,“UB”WÑÇ®¶!¶°² my-R:¨È^ÛÞ־וÞWˆRŽ>v=ïÄ'»ß«”JË%´BTÍÑì±m@žV¨ºA«è8VŽo…pŽÙåçq6tÒÓ Q{Õ¾vW!„B!„hJþžK{íHˆ9ªIEND®B`‚././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gtk4/display-widgets/label.rst0000664000000000000000000000603015074674453023116 0ustar00rootroot.. currentmodule:: gi.repository Label ===== Labels are the main method of placing non-editable text in windows, for instance to place a title next to a :class:`Gtk.Entry` widget. You can specify the text in the constructor, or later with the :attr:`Gtk.Label.props.label` property. The width of the label will be adjusted automatically. You can produce multi-line labels by putting line breaks (``\n``) in the label string. Labels can be made selectable with :attr:`Gtk.Label.props.selectable`. Selectable labels allow the user to copy the label contents to the clipboard. Only labels that contain useful-to-copy information — such as error messages — should be made selectable. The label text can be justified using the :attr:`Gtk.Label.props.justify` prop. The widget is also capable of word-wrapping, which can be activated with :attr:`Gtk.Label.props.wrap`. You can configure this wrapping by changing :attr:`Gtk.Label.props.wrap_mode`, in can be :attr:`Pango.WrapMode.WORD`, :attr:`Pango.WrapMode.CHAR` or :attr:`Pango.WrapMode.WORD_CHAR`. :class:`Gtk.Label` support some simple formatting, for instance allowing you to make some text bold, colored, or larger. You can do this by enabling markup setting :attr:`Gtk.Label.props.use_markup` to ``True``, then you can use markup with :attr:`Gtk.Label.props.label` using the Pango Markup syntax [#pango]_. For instance, ``bold text and strikethrough text``. In addition, :class:`Gtk.Label` supports clickable hyperlinks. The markup for links is borrowed from HTML, using the a with href and title attributes. GTK renders links similar to the way they appear in web browsers, with colored, underlined text. The title attribute is displayed as a tooltip on the link. :meth:`Gtk.Label.set_markup` method can be used to set the text and enable markup at the same time. .. code-block:: python label.set_markup("Go to GTK+ website for more") Labels may contain *mnemonics*. Mnemonics are underlined characters in the label, used for keyboard navigation. Mnemonics are created by providing a string with an underscore before the mnemonic character, such as "_File", to the functions :meth:`Gtk.Label.new_with_mnemonic` or :meth:`Gtk.Label.set_text_with_mnemonic`. Mnemonics automatically activate any activatable widget the label is inside, such as a :class:`Gtk.Button`; if the label is not inside the mnemonic's target widget, you have to tell the label about the target using :attr:`Gtk.Label.props.mnemonic_widget`. You can also change the alignment of the label text inside its size allocation. For example if you use :attr:`Gtk.Widget.props.hexpand` in a label, the label may take more space than its inner text. You can change this alignment using :attr:`Gtk.Label.props.xalign` for horizontal alignment and :attr:`Gtk.Label.props.yalign` for vertical. Example ------- .. image:: images/label.png .. literalinclude:: examples/label.py :linenos: .. [#pango] Pango Markup Syntax, https://docs.gtk.org/Pango/pango_markup.html ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gtk4/display-widgets/picture.rst0000664000000000000000000000210415074674453023510 0ustar00rootroot.. currentmodule:: gi.repository Picture ======= :class:`Gtk.Picture` displays an image at its natural size. Many convenience functions are provided to make pictures simple to use. For example, if you want to load an image from a file you can use :meth:`Gtk.Picture.new_for_filename`. You can influence how the image is displayed inside the :class:`Gtk.Picture` by changing :attr:`Gtk.Picture.props.content_fit`. See :class:`Gtk.ContentFit` for details. Also :attr:`Gtk.Widget.props.halign` and :attr:`Gtk.Widget.props.valign` can be used to set whether the picture will fill all available space or is displayed at its original size. Sometimes an application will want to avoid depending on external data files, such as image files. See the documentation of :class:`Gio.Resource` inside GIO, for details. In this case, :meth:`Gtk.Picture.new_for_resource` and :meth:`Gtk.Picture.set_resource`, should be used. .. note:: This example requires a GTK version higher o equal to ``4.8``. Example ------- .. image:: images/picture.png .. literalinclude:: examples/picture.py :linenos: ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gtk4/display-widgets/progressbar.rst0000664000000000000000000000341715074674453024376 0ustar00rootroot.. currentmodule:: gi.repository ProgressBar =========== The :class:`Gtk.ProgressBar` is typically used to display the progress of a long running operation. It provides a visual clue that processing is underway. The :class:`Gtk.ProgressBar` can be used in two different modes: *percentage mode* and *activity mode*. When an application can determine how much work needs to take place (e.g. read a fixed number of bytes from a file) and can monitor its progress, it can use the :class:`Gtk.ProgressBar` in *percentage mode* and the user sees a growing bar indicating the percentage of the work that has been completed. In this mode, the application is required to set :attr:`Gtk.ProgressBar.props.fraction` periodically to update the progress bar, setting a float between 0 and 1 to provide the new percentage value. When an application has no accurate way of knowing the amount of work to do, it can use *activity mode*, which shows activity by a block moving back and forth within the progress area. In this mode, the application is required to call :meth:`Gtk.ProgressBar.pulse` periodically to update the progress bar. You can also choose the step size, with the :attr:`Gtk.ProgressBar.props.pulse_step` property. By default, :class:`Gtk.ProgressBar` is horizontal and left-to-right, but you can change it to a vertical progress bar by changing the value of :attr:`Gtk.ProgressBar.props.orientation `. Changing the direction the progress bar grows can be done using :attr:`Gtk.ProgressBar.props.inverted`. :class:`Gtk.ProgressBar` can also contain text which can be set with :attr:`Gtk.ProgressBar.props.text` and :attr:`Gtk.ProgressBar.props.show_text`. Example ------- .. image:: images/progressbar.png .. literalinclude:: examples/progressbar.py :linenos: ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gtk4/display-widgets/spinner.rst0000664000000000000000000000155015074674453023517 0ustar00rootroot.. currentmodule:: gi.repository Spinner ======= The :class:`Gtk.Spinner` displays an icon-size spinning animation. It is often used as an alternative to a :class:`Gtk.ProgressBar` for displaying indefinite activity, instead of actual progress. To start the animation, use :meth:`Gtk.Spinner.start`, to stop it use :meth:`Gtk.Spinner.stop`. Example ------- .. image:: images/spinner.png .. literalinclude:: examples/spinner.py :linenos: Extended example ---------------- An extended example that uses a timeout function to start and stop the spinning animation. The :func:`on_timeout` function is called at regular intervals until it returns ``False``, at which point the timeout is automatically destroyed and the function will not be called again. Example ^^^^^^^ .. image:: images/spinner_ext.png .. literalinclude:: examples/spinner_ext.py :linenos: ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gtk4/display-widgets.rst0000664000000000000000000000050715074674453022042 0ustar00rootrootDisplay Widgets =============== Learn how to use the most basic elements to display things, like text, images, icons or ongoing progress. .. toctree:: :maxdepth: 1 :caption: Contents display-widgets/label display-widgets/image display-widgets/picture display-widgets/progressbar display-widgets/spinner ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gtk4/drag-and-drop.rst0000664000000000000000000000610715074674453021352 0ustar00rootroot.. currentmodule:: gi.repository Drag and Drop ============= .. seealso:: `Drag-and-Drop`_ in the GTK documentation. GTK drag-and-drop works with drag sources and drop targets. These are event controllers that can be set to any widget using :meth:`Gtk.Widget.add_controller`. The data begin moved in the operation is provided through a :class:`Gdk.ContentProvider`. Drag sources ------------ :class:`Gtk.DragSource` is the event controller that allows a widget to be used as a drag source. You can set up everything needed for the drag-and-drop operation ahead of time or do it on the fly using the signals provided by :class:`Gtk.DragSource`. You can use :meth:`Gtk.DragSource.set_content` to set the :class:`Gdk.ContentProvider` that will be sent to drop targets. A content provider is usually created using :meth:`Gdk.ContentProvider.new_for_value` where you only pass the value to send. To pass different values for multiple possible targets you can use :meth:`Gdk.ContentProvider.new_union` were you can pass a list of :class:`Gdk.ContentProviders `. :class:`Gtk.DragSource` provides signals for the different stages of the drag event. The :func:`prepare ` signal is emitted when a drag is about to be initiated, here you should return the :class:`Gdk.ContentProvider` that will be sent, otherwise the one set with :meth:`Gtk.DragSource.set_content` will be used. The :func:`drag-begin ` signal is emitted when the drag is started, here you can do things like changing the icon attached to the cursor when dragging using :meth:`Gtk.DragSource.set_icon`. Also the :func:`drag-end ` signal is provided, you can use it to undo things done in the previous signals. Finally :func:`drag-cancel ` allows you to do things when the operation has been cancelled. Drop targets ------------ :class:`Gtk.DropTarget` is the event controller to receive drag-and-drop operations in a widget. When creating a new drop target with :meth:`Gtk.DropTarget.new` you should provide the data type and :class:`Gdk.DragAction` that your target accepts. If you want to support multiple data types you can pass :attr:`GObject.TYPE_NONE` and then use :meth:`Gtk.DropTarget.set_gtypes` where you can pass a list of types, be aware that the order of the list establish the priorities. :class:`Gtk.DropTarget` provides multiple signals for the process. These are :func:`accept `, :func:`drop `, :func:`enter `, :func:`leave `, and :func:`motion `. Generally connecting to :func:`drop ` is only needed, this signal will receive the value sended by the :class:`Gtk.DragSource`. For more complex use cases checkout :class:`Gtk.DropTargetAsync`. Example ------- .. image:: images/drag_and_drop.png .. literalinclude:: examples/drag_and_drop.py :linenos: .. _Drag-and-Drop: https://docs.gtk.org/gtk4/drag-and-drop.html ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gtk4/examples/application.py0000664000000000000000000001245215074674453022674 0ustar00rootrootimport sys import gi gi.require_version('Gtk', '4.0') from gi.repository import GLib, Gio, Gtk # This would typically be its own file MENU_XML = """

Change label
win.change_label String 1 String 1 win.change_label String 2 String 2 win.change_label String 3 String 3
Window
win.maximize Maximize
app.about _About app.quit _Quit <Primary>q
""" class AppWindow(Gtk.ApplicationWindow): def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) self.set_default_size(200, 200) # By default the title bar will be hide, let's show it self.props.show_menubar = True # This will be in the windows group and have the 'win' prefix max_action = Gio.SimpleAction.new_stateful( 'maximize', None, GLib.Variant.new_boolean(False) ) max_action.connect('change-state', self.on_maximize_toggle) self.add_action(max_action) # Keep it in sync with the actual state self.connect( 'notify::maximized', lambda obj, _pspec: max_action.set_state( GLib.Variant.new_boolean(obj.props.maximized) ), ) lbl_variant = GLib.Variant.new_string('String 1') lbl_action = Gio.SimpleAction.new_stateful( 'change_label', lbl_variant.get_type(), lbl_variant ) lbl_action.connect('change-state', self.on_change_label_state) self.add_action(lbl_action) self.label = Gtk.Label(label=lbl_variant.get_string()) self.set_child(self.label) def on_change_label_state(self, action, value): action.set_state(value) self.label.set_text(value.get_string()) def on_maximize_toggle(self, action, value): action.set_state(value) if value.get_boolean(): self.maximize() else: self.unmaximize() class Application(Gtk.Application): def __init__(self, *args, **kwargs): super().__init__( *args, application_id='org.example.App', flags=Gio.ApplicationFlags.HANDLES_COMMAND_LINE, **kwargs ) self.window = None self.add_main_option( 'test', ord('t'), GLib.OptionFlags.NONE, GLib.OptionArg.NONE, 'Command line test', None, ) def do_startup(self): Gtk.Application.do_startup(self) action = Gio.SimpleAction.new('about', None) action.connect('activate', self.on_about) self.add_action(action) action = Gio.SimpleAction.new('quit', None) action.connect('activate', self.on_quit) self.add_action(action) builder = Gtk.Builder.new_from_string(MENU_XML, -1) self.set_menubar(builder.get_object('menubar')) def do_activate(self): # We only allow a single window and raise any existing ones if not self.window: # Windows are associated with the application # when the last one is closed the application shuts down self.window = AppWindow(application=self, title='Main Window') self.window.present() def do_command_line(self, command_line): options = command_line.get_options_dict() # convert GVariantDict -> GVariant -> dict options = options.end().unpack() if 'test' in options: # This is printed on the main instance print('Test argument recieved: %s' % options['test']) self.activate() return 0 def on_about(self, _action, _param): about_dialog = Gtk.AboutDialog(transient_for=self.window, modal=True) about_dialog.present() def on_quit(self, _action, _param): self.quit() if __name__ == '__main__': app = Application() app.run(sys.argv) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gtk4/examples/clipboard.py0000664000000000000000000000524715074674453022334 0ustar00rootrootimport gi gi.require_version('Gdk', '4.0') gi.require_version('Gtk', '4.0') from gi.repository import Gdk, Gtk class ClipboardWindow(Gtk.ApplicationWindow): def __init__(self, *args, **kargs): super().__init__(*args, **kargs, title='Clipboard Example') box = Gtk.Box(spacing=12, orientation=Gtk.Orientation.VERTICAL) self.set_child(box) self.clipboard = Gdk.Display.get_default().get_clipboard() text_box = Gtk.Box(spacing=6, homogeneous=True) box.append(text_box) self.entry = Gtk.Entry(text='Some text you can copy') button_copy_text = Gtk.Button(label='Copy Text') button_copy_text.connect('clicked', self.copy_text) button_paste_text = Gtk.Button(label='Paste Text') button_paste_text.connect('clicked', self.paste_text) text_box.append(self.entry) text_box.append(button_copy_text) text_box.append(button_paste_text) image_box = Gtk.Box(spacing=6) box.append(image_box) self.picture = Gtk.Picture.new_for_filename( '../images/application.png' ) self.picture.props.hexpand = True button_copy_image = Gtk.Button( label='Copy Image', valign=Gtk.Align.CENTER ) button_copy_image.connect('clicked', self.copy_image) button_paste_image = Gtk.Button( label='Paste Image', valign=Gtk.Align.CENTER ) button_paste_image.connect('clicked', self.paste_image) image_box.append(self.picture) image_box.append(button_copy_image) image_box.append(button_paste_image) def copy_text(self, _button): self.clipboard.set(self.entry.get_text()) def paste_text(self, _button): self.clipboard.read_text_async(None, self.on_paste_text) def on_paste_text(self, _clipboard, result): text = self.clipboard.read_text_finish(result) if text is not None: self.entry.set_text(text) def copy_image(self, _button): texture = self.picture.get_paintable() gbytes = texture.save_to_png_bytes() content = Gdk.ContentProvider.new_for_bytes('image/png', gbytes) self.clipboard.set_content(content) def paste_image(self, _button): self.clipboard.read_texture_async(None, self.on_paste_image) def on_paste_image(self, _clipboard, result): texture = self.clipboard.read_texture_finish(result) if texture is not None: self.picture.set_paintable(texture) def on_activate(app): win = ClipboardWindow(application=app) win.present() app = Gtk.Application(application_id='com.example.App') app.connect('activate', on_activate) app.run(None) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gtk4/examples/drag_and_drop.py0000664000000000000000000000742315074674453023156 0ustar00rootrootimport gi gi.require_version('Gdk', '4.0') gi.require_version('Gtk', '4.0') from gi.repository import Gdk, GObject, Gtk class DragDropWindow(Gtk.ApplicationWindow): def __init__(self, *args, **kargs): super().__init__(*args, **kargs, title='Drag and Drop Example') self.set_default_size(500, 400) views_box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) views_box.props.vexpand = True self.set_child(views_box) flow_box = Gtk.FlowBox() views_box.append(flow_box) flow_box.props.selection_mode = Gtk.SelectionMode.NONE flow_box.append(SourceFlowBoxChild('Item 1', 'image-missing')) flow_box.append(SourceFlowBoxChild('Item 2', 'help-about')) flow_box.append(SourceFlowBoxChild('Item 3', 'edit-copy')) views_box.append(Gtk.Separator()) self.target_view = TargetView(vexpand=True) views_box.append(self.target_view) class SourceFlowBoxChild(Gtk.FlowBoxChild): def __init__(self, name, icon_name): super().__init__() self.name = name self.icon_name = icon_name box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6) self.set_child(box) icon = Gtk.Image(icon_name=self.icon_name) label = Gtk.Label(label=self.name) box.append(icon) box.append(label) drag_controller = Gtk.DragSource() drag_controller.connect('prepare', self.on_drag_prepare) drag_controller.connect('drag-begin', self.on_drag_begin) self.add_controller(drag_controller) def on_drag_prepare(self, _ctrl, _x, _y): item = Gdk.ContentProvider.new_for_value(self) string = Gdk.ContentProvider.new_for_value(self.name) return Gdk.ContentProvider.new_union([item, string]) def on_drag_begin(self, ctrl, _drag): icon = Gtk.WidgetPaintable.new(self) ctrl.set_icon(icon, 0, 0) class TargetView(Gtk.Box): def __init__(self, **kargs): super().__init__(**kargs) self.stack = Gtk.Stack(hexpand=True) self.append(self.stack) empty_label = Gtk.Label(label='Drag some item, text, or files here.') self.stack.add_named(empty_label, 'empty') self.stack.set_visible_child_name('empty') box = Gtk.Box( orientation=Gtk.Orientation.VERTICAL, vexpand=True, valign=Gtk.Align.CENTER, ) self.stack.add_named(box, 'item') self.icon = Gtk.Image() box.append(self.icon) self.label = Gtk.Label() box.append(self.label) self.text = Gtk.Label() self.stack.add_named(self.text, 'other') drop_controller = Gtk.DropTarget.new( type=GObject.TYPE_NONE, actions=Gdk.DragAction.COPY ) drop_controller.set_gtypes([SourceFlowBoxChild, Gdk.FileList, str]) drop_controller.connect('drop', self.on_drop) self.add_controller(drop_controller) def on_drop(self, _ctrl, value, _x, _y): if isinstance(value, SourceFlowBoxChild): self.label.props.label = value.name self.icon.props.icon_name = value.icon_name self.stack.set_visible_child_name('item') elif isinstance(value, Gdk.FileList): files = value.get_files() names = '' for file in files: names += f'Loaded file {file.get_basename()}\n' self.text.props.label = names self.stack.set_visible_child_name('other') elif isinstance(value, str): self.text.props.label = value self.stack.set_visible_child_name('other') def on_activate(app): win = DragDropWindow(application=app) win.present() app = Gtk.Application(application_id='com.example.App') app.connect('activate', on_activate) app.run(None) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gtk4/examples/extended_example.py0000664000000000000000000000122115074674453023674 0ustar00rootrootimport gi gi.require_version('Gtk', '4.0') from gi.repository import Gtk class MyWindow(Gtk.ApplicationWindow): def __init__(self, **kargs): super().__init__(**kargs, title='Hello World') self.button = Gtk.Button(label='Click Here') self.button.connect('clicked', self.on_button_clicked) self.set_child(self.button) def on_button_clicked(self, _widget): print('Hello World') self.close() def on_activate(app): # Create window win = MyWindow(application=app) win.present() app = Gtk.Application(application_id='com.example.App') app.connect('activate', on_activate) app.run(None) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gtk4/examples/layout_box.py0000664000000000000000000000162215074674453022553 0ustar00rootrootimport gi gi.require_version('Gtk', '4.0') from gi.repository import Gtk class MyWindow(Gtk.ApplicationWindow): def __init__(self, **kargs): super().__init__(**kargs, title='Hello World') box = Gtk.Box(spacing=6) self.set_child(box) button1 = Gtk.Button(label='Hello') button1.connect('clicked', self.on_button1_clicked) box.append(button1) button2 = Gtk.Button(label='Goodbye') button2.props.hexpand = True button2.connect('clicked', self.on_button2_clicked) box.append(button2) def on_button1_clicked(self, _widget): print('Hello') def on_button2_clicked(self, _widget): print('Goodbye') def on_activate(app): # Create window win = MyWindow(application=app) win.present() app = Gtk.Application(application_id='com.example.App') app.connect('activate', on_activate) app.run(None) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gtk4/examples/layout_center.py0000664000000000000000000000135715074674453023250 0ustar00rootrootimport gi gi.require_version('Gtk', '4.0') from gi.repository import Gtk class CenterBoxWindow(Gtk.ApplicationWindow): def __init__(self, **kargs): super().__init__(**kargs, default_width=400, title='CenterBox Example') box = Gtk.CenterBox() self.set_child(box) button1 = Gtk.Button(label='Start') box.set_start_widget(button1) label = Gtk.Label(label='Center') box.set_center_widget(label) button2 = Gtk.Button(label='End') box.set_end_widget(button2) def on_activate(app): # Create window win = CenterBoxWindow(application=app) win.present() app = Gtk.Application(application_id='com.example.App') app.connect('activate', on_activate) app.run(None) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gtk4/examples/layout_flowbox.py0000664000000000000000000000633115074674453023445 0ustar00rootrootimport gi gi.require_version('Gtk', '4.0') from gi.repository import Gtk, Gdk class FlowBoxWindow(Gtk.ApplicationWindow): def __init__(self, **kargs): super().__init__(**kargs, title='FlowBox Demo') self.set_default_size(300, 250) header = Gtk.HeaderBar() self.set_titlebar(header) scrolled = Gtk.ScrolledWindow() scrolled.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC) self.set_child(scrolled) flowbox = Gtk.FlowBox() flowbox.props.valign = Gtk.Align.START flowbox.props.max_children_per_line = 30 flowbox.props.selection_mode = Gtk.SelectionMode.NONE scrolled.set_child(flowbox) self.create_flowbox(flowbox) def draw_button_color(self, area, cr, width, height, rgba): context = area.get_style_context() Gtk.render_background(context, cr, 0, 0, width, height) cr.set_source_rgba(rgba.red, rgba.green, rgba.blue, rgba.alpha) cr.rectangle(0, 0, width, height) cr.fill() def color_swatch_new(self, str_color): rgba = Gdk.RGBA() rgba.parse(str_color) button = Gtk.Button() area = Gtk.DrawingArea() area.set_size_request(24, 24) area.set_draw_func(self.draw_button_color, rgba) button.set_child(area) return button def create_flowbox(self, flowbox): colors = [ 'AliceBlue', 'AntiqueWhite', 'AntiqueWhite1', 'AntiqueWhite2', 'AntiqueWhite3', 'AntiqueWhite4', 'aqua', 'aquamarine', 'aquamarine1', 'aquamarine2', 'aquamarine3', 'aquamarine4', 'azure', 'azure1', 'azure2', 'azure3', 'azure4', 'beige', 'bisque', 'bisque1', 'bisque2', 'bisque3', 'bisque4', 'black', 'BlanchedAlmond', 'blue', 'blue1', 'blue2', 'blue3', 'blue4', 'BlueViolet', 'brown', 'brown1', 'brown2', 'brown3', 'brown4', 'burlywood', 'burlywood1', 'burlywood2', 'burlywood3', 'burlywood4', 'CadetBlue', 'CadetBlue1', 'CadetBlue2', 'CadetBlue3', 'CadetBlue4', 'chartreuse', 'chartreuse1', 'chartreuse2', 'chartreuse3', 'chartreuse4', 'chocolate', 'chocolate1', 'chocolate2', 'chocolate3', 'chocolate4', 'coral', 'coral1', 'coral2', 'coral3', 'coral4', ] for color in colors: button = self.color_swatch_new(color) button.props.tooltip_text = color flowbox.append(button) def on_activate(app): # Create window win = FlowBoxWindow(application=app) win.present() app = Gtk.Application(application_id='com.example.App') app.connect('activate', on_activate) app.run(None) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gtk4/examples/layout_grid.py0000664000000000000000000000212415074674453022706 0ustar00rootrootimport gi gi.require_version('Gtk', '4.0') from gi.repository import Gtk class GridWindow(Gtk.ApplicationWindow): def __init__(self, **kargs): super().__init__(**kargs, title='Grid Example') button1 = Gtk.Button(label='Button 1') button2 = Gtk.Button(label='Button 2') button3 = Gtk.Button(label='Button 3') button4 = Gtk.Button(label='Button 4') button5 = Gtk.Button(label='Button 5') button6 = Gtk.Button(label='Button 6') grid = Gtk.Grid() grid.attach(button1, 0, 0, 1, 1) grid.attach(button2, 1, 0, 2, 1) grid.attach_next_to(button3, button1, Gtk.PositionType.BOTTOM, 1, 2) grid.attach_next_to(button4, button3, Gtk.PositionType.RIGHT, 2, 1) grid.attach(button5, 1, 2, 1, 1) grid.attach_next_to(button6, button5, Gtk.PositionType.RIGHT, 1, 1) self.set_child(grid) def on_activate(app): # Create window win = GridWindow(application=app) win.present() app = Gtk.Application(application_id='com.example.App') app.connect('activate', on_activate) app.run(None) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gtk4/examples/layout_headerbar.py0000664000000000000000000000131415074674453023676 0ustar00rootrootimport gi gi.require_version('Gtk', '4.0') from gi.repository import Gtk class HeaderBarWindow(Gtk.ApplicationWindow): def __init__(self, **kargs): super().__init__(**kargs, default_width=400, title='HeaderBar Example') header_bar = Gtk.HeaderBar() self.set_titlebar(header_bar) button = Gtk.Button(label='Button') header_bar.pack_start(button) icon_button = Gtk.Button(icon_name='open-menu-symbolic') header_bar.pack_end(icon_button) def on_activate(app): # Create window win = HeaderBarWindow(application=app) win.present() app = Gtk.Application(application_id='com.example.App') app.connect('activate', on_activate) app.run(None) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gtk4/examples/layout_listbox.py0000664000000000000000000000633615074674453023456 0ustar00rootrootimport gi gi.require_version('Gtk', '4.0') from gi.repository import Gtk class ListBoxRowWithData(Gtk.ListBoxRow): def __init__(self, data): super().__init__() self.data = data self.set_child(Gtk.Label(label=data)) class ListBoxWindow(Gtk.ApplicationWindow): def __init__(self, **kargs): super().__init__(**kargs, default_width=400, title='ListBox Demo') # Main box of out window box_outer = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=24) box_outer.props.margin_start = 24 box_outer.props.margin_end = 24 box_outer.props.margin_top = 24 box_outer.props.margin_bottom = 24 self.set_child(box_outer) # Let's create our first ListBox listbox = Gtk.ListBox() listbox.props.selection_mode = Gtk.SelectionMode.NONE listbox.props.show_separators = True box_outer.append(listbox) # Let's create our first ListBoxRow row = Gtk.ListBoxRow() hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=24) row.set_child(hbox) # We set the Box as the ListBoxRow child vbox = Gtk.Box(orientation=Gtk.Orientation.VERTICAL) hbox.append(vbox) label1 = Gtk.Label(label='Automatic Date & Time', xalign=0) label2 = Gtk.Label(label='Requires internet access', xalign=0) vbox.append(label1) vbox.append(label2) switch = Gtk.Switch() switch.props.hexpand = ( True # Lets make the Switch expand to the window width ) switch.props.halign = Gtk.Align.END # Horizontally aligned to the end switch.props.valign = ( Gtk.Align.CENTER ) # Vertically aligned to the center hbox.append(switch) listbox.append(row) # Add the row to the list # Our second row. We will omit the ListBoxRow and directly append a Box hbox = Gtk.Box(orientation=Gtk.Orientation.HORIZONTAL, spacing=24) label = Gtk.Label(label='Enable Automatic Update', xalign=0) check = Gtk.CheckButton() check.props.hexpand = True check.props.halign = Gtk.Align.END hbox.append(label) hbox.append(check) listbox.append(hbox) # Add the second row to the list # Let's create a second ListBox listbox_2 = Gtk.ListBox() box_outer.append(listbox_2) items = 'This is a sorted ListBox Fail'.split() # Populate the list for item in items: listbox_2.append(ListBoxRowWithData(item)) # Set sorting and filter functions listbox_2.set_sort_func(self.sort_func) listbox_2.set_filter_func(self.filter_func) # Connect to "row-activated" signal listbox_2.connect('row-activated', self.on_row_activated) def sort_func(self, row_1, row_2): return row_1.data.lower() > row_2.data.lower() def filter_func(self, row): return False if row.data == 'Fail' else True def on_row_activated(self, _listbox, row): print(row.data) def on_activate(app): # Create window win = ListBoxWindow(application=app) win.present() app = Gtk.Application(application_id='com.example.App') app.connect('activate', on_activate) app.run(None) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gtk4/examples/layout_notebook.py0000664000000000000000000000145715074674453023611 0ustar00rootrootimport gi gi.require_version('Gtk', '4.0') from gi.repository import Gtk class NotebookWindow(Gtk.Window): def __init__(self, **kargs): super().__init__(**kargs, title='Simple Notebook Example') notebook = Gtk.Notebook() self.set_child(notebook) page1 = Gtk.Box() page1.append(Gtk.Label(label='Default Page!')) notebook.append_page(page1, Gtk.Label(label='Plain Title')) page2 = Gtk.Box() page2.append(Gtk.Label(label='A page with an image for a Title.')) notebook.append_page(page2, Gtk.Image(icon_name='help-about')) def on_activate(app): # Create window win = NotebookWindow(application=app) win.present() app = Gtk.Application(application_id='com.example.App') app.connect('activate', on_activate) app.run(None) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gtk4/examples/layout_stack.py0000664000000000000000000000261315074674453023071 0ustar00rootrootimport gi gi.require_version('Gtk', '4.0') from gi.repository import Gtk, GObject class StackWindow(Gtk.ApplicationWindow): def __init__(self, **kargs): super().__init__(**kargs, title='Stack Demo') self.set_default_size(300, 250) header = Gtk.HeaderBar() self.set_titlebar(header) stack = Gtk.Stack() stack.props.transition_type = Gtk.StackTransitionType.SLIDE_LEFT_RIGHT stack.props.transition_duration = 1000 self.set_child(stack) checkbutton = Gtk.CheckButton(label='Click me!') checkbutton.props.hexpand = True checkbutton.props.halign = Gtk.Align.CENTER page1 = stack.add_titled(checkbutton, 'check', 'Check Button') checkbutton.bind_property( 'active', page1, 'needs-attention', GObject.BindingFlags.DEFAULT ) label = Gtk.Label() label.set_markup('A fancy label') stack.add_titled(label, 'label', 'A label') stack_switcher = Gtk.StackSwitcher() stack_switcher.set_stack(stack) header.set_title_widget(stack_switcher) # Let's start in the second page stack.set_visible_child_name('label') def on_activate(app): # Create window win = StackWindow(application=app) win.present() app = Gtk.Application(application_id='com.example.App') app.connect('activate', on_activate) app.run(None) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gtk4/examples/popover.py0000664000000000000000000000237415074674453022065 0ustar00rootrootimport gi gi.require_version('Gtk', '4.0') from gi.repository import Gtk class PopoverWindow(Gtk.ApplicationWindow): def __init__(self, **kargs): super().__init__(**kargs, title='Popover Demo') self.set_default_size(300, 200) box = Gtk.Box(spacing=6, orientation=Gtk.Orientation.VERTICAL) box.props.halign = box.props.valign = Gtk.Align.CENTER self.set_child(box) popover = Gtk.Popover() popover_box = Gtk.Box() popover_box.append(Gtk.Label(label='Item')) popover.set_child(popover_box) button = Gtk.MenuButton(label='Click Me', popover=popover) box.append(button) button2 = Gtk.Button(label='Click Me 2') button2.connect('clicked', self.on_button_clicked) box.append(button2) self.popover2 = Gtk.Popover() self.popover2.set_child(Gtk.Label(label='Another Popup!')) self.popover2.set_parent(button2) self.popover2.props.position = Gtk.PositionType.LEFT def on_button_clicked(self, _button): self.popover2.popup() def on_activate(app): win = PopoverWindow(application=app) win.present() app = Gtk.Application(application_id='com.example.App') app.connect('activate', on_activate) app.run(None) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gtk4/examples/popover_menu.py0000664000000000000000000000403515074674453023105 0ustar00rootrootimport gi gi.require_version('Gtk', '4.0') from gi.repository import Gio, Gtk # This would typically be its own file MENU_XML = """
About app.about Quit app.quit
""" class AppWindow(Gtk.ApplicationWindow): def __init__(self, **kwargs): super().__init__(**kwargs) self.set_default_size(300, 200) headerbar = Gtk.HeaderBar() self.set_titlebar(headerbar) builder = Gtk.Builder.new_from_string(MENU_XML, -1) menu_model = builder.get_object('app-menu') button = Gtk.MenuButton(menu_model=menu_model) headerbar.pack_end(button) class Application(Gtk.Application): def __init__(self, **kwargs): super().__init__(application_id='com.example.App', **kwargs) self.window = None def do_startup(self): Gtk.Application.do_startup(self) action = Gio.SimpleAction(name='about') action.connect('activate', self.on_about) self.add_action(action) action = Gio.SimpleAction(name='quit') action.connect('activate', self.on_quit) self.add_action(action) def do_activate(self): # We only allow a single window and raise any existing ones if not self.window: # Windows are associated with the application # when the last one is closed the application shuts down self.window = AppWindow(application=self, title='Main Window') self.window.present() def on_about(self, action, param): about_dialog = Gtk.AboutDialog(transient_for=self.window, modal=True) about_dialog.present() def on_quit(self, action, param): self.quit() app = Application() app.run(None) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gtk4/examples/simple_example.py0000664000000000000000000000053015074674453023367 0ustar00rootrootimport gi gi.require_version('Gtk', '4.0') from gi.repository import Gtk def on_activate(app): # Create window win = Gtk.ApplicationWindow(application=app) win.present() # Create a new application app = Gtk.Application(application_id='com.example.App') app.connect('activate', on_activate) # Run the application app.run(None) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gtk4/examples/textview.py0000664000000000000000000001732415074674453022253 0ustar00rootrootimport gi gi.require_version('Gtk', '4.0') from gi.repository import Gtk, Pango class SearchDialog(Gtk.Window): def __init__(self, parent): super().__init__(title='Search', transient_for=parent) box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=12) self.set_child(box) label = Gtk.Label(label='Insert text you want to search for:') box.append(label) self.entry = Gtk.Entry() box.append(self.entry) self.button = Gtk.Button(label='Find') box.append(self.button) class TextViewWindow(Gtk.ApplicationWindow): def __init__(self, **kargs): super().__init__(**kargs, title='TextView Demo') self.set_default_size(500, 400) self.box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL, spacing=6) self.set_child(self.box) self.create_textview() self.create_toolbar() self.create_buttons() def create_toolbar(self): toolbar = Gtk.Box(spacing=6) toolbar.props.margin_top = 6 toolbar.props.margin_start = 6 toolbar.props.margin_end = 6 self.box.prepend(toolbar) button_bold = Gtk.Button(icon_name='format-text-bold-symbolic') toolbar.append(button_bold) button_italic = Gtk.Button(icon_name='format-text-italic-symbolic') toolbar.append(button_italic) button_underline = Gtk.Button( icon_name='format-text-underline-symbolic' ) toolbar.append(button_underline) button_bold.connect('clicked', self.on_button_clicked, self.tag_bold) button_italic.connect( 'clicked', self.on_button_clicked, self.tag_italic ) button_underline.connect( 'clicked', self.on_button_clicked, self.tag_underline ) toolbar.append(Gtk.Separator()) justifyleft = Gtk.ToggleButton( icon_name='format-justify-left-symbolic' ) toolbar.append(justifyleft) justifycenter = Gtk.ToggleButton( icon_name='format-justify-center-symbolic' ) justifycenter.set_group(justifyleft) toolbar.append(justifycenter) justifyright = Gtk.ToggleButton( icon_name='format-justify-right-symbolic' ) justifyright.set_group(justifyleft) toolbar.append(justifyright) justifyfill = Gtk.ToggleButton( icon_name='format-justify-fill-symbolic' ) justifyfill.set_group(justifyleft) toolbar.append(justifyfill) justifyleft.connect( 'toggled', self.on_justify_toggled, Gtk.Justification.LEFT ) justifycenter.connect( 'toggled', self.on_justify_toggled, Gtk.Justification.CENTER ) justifyright.connect( 'toggled', self.on_justify_toggled, Gtk.Justification.RIGHT ) justifyfill.connect( 'toggled', self.on_justify_toggled, Gtk.Justification.FILL ) toolbar.append(Gtk.Separator()) button_clear = Gtk.Button(icon_name='edit-clear-symbolic') button_clear.connect('clicked', self.on_clear_clicked) toolbar.append(button_clear) toolbar.append(Gtk.Separator()) button_search = Gtk.Button(icon_name='system-search-symbolic') button_search.connect('clicked', self.on_search_clicked) toolbar.append(button_search) def create_textview(self): scrolledwindow = Gtk.ScrolledWindow() scrolledwindow.props.hexpand = True scrolledwindow.props.vexpand = True self.box.append(scrolledwindow) self.textview = Gtk.TextView() self.textbuffer = self.textview.get_buffer() self.textbuffer.set_text( 'This is some text inside of a Gtk.TextView. ' + 'Select text and click one of the buttons "bold", "italic", ' + 'or "underline" to modify the text accordingly.' ) scrolledwindow.set_child(self.textview) self.tag_bold = self.textbuffer.create_tag( 'bold', weight=Pango.Weight.BOLD ) self.tag_italic = self.textbuffer.create_tag( 'italic', style=Pango.Style.ITALIC ) self.tag_underline = self.textbuffer.create_tag( 'underline', underline=Pango.Underline.SINGLE ) self.tag_found = self.textbuffer.create_tag( 'found', background='yellow' ) def create_buttons(self): grid = Gtk.Grid() self.box.append(grid) check_editable = Gtk.CheckButton(label='Editable') check_editable.props.active = True check_editable.connect('toggled', self.on_editable_toggled) grid.attach(check_editable, 0, 0, 1, 1) check_cursor = Gtk.CheckButton(label='Cursor Visible') check_cursor.props.active = True check_editable.connect('toggled', self.on_cursor_toggled) grid.attach_next_to( check_cursor, check_editable, Gtk.PositionType.RIGHT, 1, 1 ) radio_wrapnone = Gtk.CheckButton(label='No Wrapping') radio_wrapnone.props.active = True grid.attach(radio_wrapnone, 0, 1, 1, 1) radio_wrapchar = Gtk.CheckButton(label='Character Wrapping') radio_wrapchar.set_group(radio_wrapnone) grid.attach_next_to( radio_wrapchar, radio_wrapnone, Gtk.PositionType.RIGHT, 1, 1 ) radio_wrapword = Gtk.CheckButton(label='Word Wrapping') radio_wrapword.set_group(radio_wrapnone) grid.attach_next_to( radio_wrapword, radio_wrapchar, Gtk.PositionType.RIGHT, 1, 1 ) radio_wrapnone.connect( 'toggled', self.on_wrap_toggled, Gtk.WrapMode.NONE ) radio_wrapchar.connect( 'toggled', self.on_wrap_toggled, Gtk.WrapMode.CHAR ) radio_wrapword.connect( 'toggled', self.on_wrap_toggled, Gtk.WrapMode.WORD ) def on_button_clicked(self, _widget, tag): bounds = self.textbuffer.get_selection_bounds() if len(bounds) != 0: start, end = bounds self.textbuffer.apply_tag(tag, start, end) def on_clear_clicked(self, _widget): start = self.textbuffer.get_start_iter() end = self.textbuffer.get_end_iter() self.textbuffer.remove_all_tags(start, end) def on_editable_toggled(self, widget): self.textview.props.editable = widget.props.active def on_cursor_toggled(self, widget): self.textview.props.cursor_visible = widget.props.active def on_wrap_toggled(self, _widget, mode): self.textview.props.wrap_mode = mode def on_justify_toggled(self, _widget, justification): self.textview.props.justification = justification def on_search_clicked(self, _widget): self.search_dialog = SearchDialog(self) self.search_dialog.button.connect('clicked', self.on_find_clicked) self.search_dialog.present() def on_find_clicked(self, _button): cursor_mark = self.textbuffer.get_insert() start = self.textbuffer.get_iter_at_mark(cursor_mark) if start.get_offset() == self.textbuffer.get_char_count(): start = self.textbuffer.get_start_iter() self.search_and_mark(self.search_dialog.entry.get_text(), start) def search_and_mark(self, text, start): end = self.textbuffer.get_end_iter() match = start.forward_search(text, 0, end) if match is not None: match_start, match_end = match self.textbuffer.apply_tag(self.tag_found, match_start, match_end) self.search_and_mark(text, match_end) def on_activate(app): win = TextViewWindow(application=app) win.present() app = Gtk.Application(application_id='com.example.App') app.connect('activate', on_activate) app.run(None) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gtk4/images/application.png0000664000000000000000000002103015074674453022447 0ustar00rootroot‰PNG  IHDRäåC [(sBIT|dˆtEXtSoftwaregnome-screenshotï¿>&tEXtCreation Timejue 08 dic 2022 22:08:02ëúi IDATxœíÝw|Õþÿñ×nØt’Ð’Pi@ EDëEc¹*ÈOëõz-¨\½(¢¨ØîW¯Š *‚HïÅFM„FB(Ò@ ¤³ûûc ›dÓàóä1dgÎÌ9;ä=çÌlB!„B!„WÕU²M!”J×–k‹ðÔ· ¦¸–ÕÄV´¥¡©½žª‰Ë„¸ÚÕœ®‰Ëš¤¹a±ik=®]¾QM ‹¥ƒhi’PŠk‘¥0jë™j‡Õ|ýzuhB#êë­Ì~Z®@gÀ °1l[)®%æÁª*€bà4p¸h˜´f?Í×UÑH( dí0{@c;Ž€Ï²¥K&… … t@qP¡Óiuçöî‹_<)*j9p¸€>¬*.…ÒÌFCÙXpjQ̓¨\CBBB]òóÿ©T8·ø‰ q•ÓAá]&NOLLŒÎUèƒiì5- aëh(æ½£±gì`˜¬§aÆE®Xúów:]“†¾B\ÓT¨ªoŸpÏ£IIIÑ@ P‰>”ÕÔ<·„zBÙX -õŒÖèÏŽM_Ò3 q‰ê\oo߀$ôç˜ÆPZê)ëP×·ÕZ¿CiªvùyщH…¨EçòÓÂïïFSƒ>3VÔ|Õêé {Û›ùPUƒ¾g´úgMÿE.­n¿×V{¶ï€ûC@úžÒxNYû"O ûYº²j ¦‹J¥ëÔ¶o«âÚ R«]ÐwVj^ÜQÓȕ֦¾Y;öhå¥ !,Ó©{jYo˜iPSzÈÚìXKç(Dƒ¬¹”ó@§f]Ô1ªoØjÕ&MâÚež•Úo)­—¥ÒÒǧj‡RÝÆŸËâZcþöÒúÂX§§lÊ[ç,½‘ÜJò(DƒÌÃhé5ô:¤¥×"Í7~ÍØüûŸ,Y¾’ââb‹ËϰdùJþÚµ»IÛ+**æ½yŸñÛ_ۛݖ˜½ûX²|%I)©5æ9–ÁÚM[Ø»¯Æü²òr–,_É–?þàëïàë…?6»^s·þÎ’å+[µ Q'/–òTGK?í¡º–:È[ÿ ãÄ *+«xøûê,_¾f=¶üÆÀFGF4º½´#G‰Þ»3gÏ1ö†QÍjË™‚s,^¶’ða 4Ð4ÕúìØƒ££=aÆ Vë¥)i‡X¼l%ãoËù ØøÛü=jv¶¶ÍªÛhÃÖß9™™EÔÄ»[´¾ZøÙàæ|Ú£Ö¼k)’úç²aËoL¸ë6::8˜–×êéÞCóÌSñéÛ§IåÍ -=Ý´®N§#1å çÏ—räXý|úú@ùÂÁÁž/>‡Z¥ÆÎÖ¦Ùu×u-ý[6áG8 3^x'''ŠÏŸgîÇŸ“|0U‹¶fóõ}ÃF½»ÊÚ”Š®eåå¬Ý°¹Æ¼µ›¶PYYY§ì¹ÂB¶íÚÍŠµø}ûΙ–•œ?Ï™³gÉÎÍ5•]²|§ÏpôØqÖlܶ]»©®®®³ÝîîtéìFaQ1y§Np23›¢¢b¼zyŸ˜d*0õjµ¿¦²'³³MË—¯^GJÚ!NŸ)`óï±iëïÕškµZbãâYµn#“Ñéê±äÂvÅìaõºÄÅ'¢ÕêßlrüD&K–¯bgôSÙ£'X½ncawrjK–¯"+'§Î¶¯¤žž=HMKgæì÷)..¦¤¤„7ßyŸäƒixzx´fÓ-ÊHs?¥q©’kðàéÕÓ“u›¶2á¶ñØÛÛSV^ÎÆ­¿èO|‚!:È?}šé/¼lú£°µµá?3^¡¿¯7g Y²l%a!D†…šïØc )ÀÖ?¶ñÎ3ê´#È0[ÿÜFZÚºwéJB²¾w|ô(Þž;ø„d¢îþ•••9–¯wìíA¿®ZƒFcÍÝ·ßèwtt¤¸¤„Š ýeñòU|öÞlœ¨¨¨äÍ9sIK?\w‡þÓÒÓyïãÏky€¯oÍx;;[–,[‰{÷nŒ`ý¦-ü±}'~úáï÷:ë6neϾ8ÆÝ8FQ;o½ú/Þxg'Nf1ó÷Q©T?™I×Îù÷«/¶E[›Ì–öפ‰wÝAii)ë6oôç–¥¥eL¸ýÖåºuéÂô©“yï?3ùßÇs™4á.ÊË+XºjuƒÛ¯ªªbæË/òÆ¿^ÀÕ¥ÉÓ8|ôhrAþƒHMO 1%'''‚üéÛ»éGŽPZZJú‘cTWW›Ê×ç\aÿï‘¿3çÍ×ñТ¢b~ß¾€u›·’–~˜¡A|þÁ^xzÖÖÖ¦u«««ùäËù\(-ã¥çžâ³÷g3Øoi‡°bízºué‚WOOróò)26!ù *•Š´ô#”•—pðP:Þ}úàÒIYŸGpsuå7fàÞ½+'2³8~2“.ݘõÆ+tíÜù²·§ÅÔ]CÿŒ†‡ ý{7ÖnÜBñùÖnÜDèÐ`<{¸×yÎ7…ƒƒ©é‡±µ±F¥R‘“›[k›5ëðñîÍ † dxÈ0ròòë´ÇßßµZMZúa.j/’r0ÀÁ~ ‚!AhµZ$%- €@ÿÁuž‹ùc;;;n3Šý}¹cü-äêOÒ÷üwßu;ž=Ü9œîݺš¶qôø òòó JDx(={ö`Ú”G8”„¡Ã†zø0Y¹9œ=Ë£"õíL>ÈÉ슋‹ xÅÿ¯-ý³²ê€µæÒAHÓAƒF£iÕ6[JzH3jµš»ï¼’óçykΜ+,b·Ö)WUUÅ»~ʳÿzßþÜΩ‚T*«µ¶j™³¡§¸xñbeðéÛ›Ìì$%SV^Nà`ýÅž¡AÄ'&“’z;[[Óž¦p餿pQm¨·  Ÿ>},–Ï7œÇvér©·pïÞ •Je:o @Ú¡t“booσ÷Ý‹Z­æ@R2©† OƒšÜÎËå\a‘~Èš™…§‡žääåñæì¹5® \.-¤¥/Á»Z'³ç4fD$®..Ë8߀~ ðõ­ó]c ‰)ìÝÏ­7å™3xrÊ£t°²ºT¦ö>ªoŸ5°ýýÑjµüºb-ƒü@¾}ûÒÑÑ‘ýI?r”Á~±R[Õ_—¥ºÍæurÖN:m±mΆ+99y¦eG@§Óé{Rx{õÆÕÅ…Ôô#$$$p°®:ÑÏLJøÄ$RÒáÒ©}¼z]ùÿëZÓÛsç‘•ƒ§‡³Þx…Yo¼‚§‡Y99¼ýþG­ÿ›j&é!kéСQÿF¯^Üû·;-–)-+ 3'‡²²2’¦šzœ¶l8/L;|÷nÝèÒÙ Ð÷âCü9}¦€òŠ ‚ =gK 6\ÿÃ"²rrˆ‹çÔéÓ¦åÞ½{ãè`OlÜ~þܾ“ܼS¬X»€pð[¥R:4˜£ÇINMeH ¾L^þ)öÆÅ„J¥¼‹óÇOÐÇ«³Þxgg\œ™õÆ+ôñêEƉ“—½=­ø.œVKx»eÌhn3ºÆ<ó2Áƒprr"ù`*=þjµšŽê-_÷1õÌ»¤¿o_ììì(++#ÐP2C‚ض;€?‹ë×g鱎»nGÌÞ8SòìK¯aee…‡{w2³²v<ùØ#|öÕw|öÕ|ÓÚ‘a¡Œ{ƒi»¡CƒÙôÛTWW0Ð24…‹¡¬¼œ¡Cëi畵rÑ÷fôísqvbÞ»ÿ©1ïriq •·k[nÜØ1œ+*•Êâó²µ³#jâºwïŠpìØ‘ß›ELl:Ž@?Μ>Kfn:ÀÅ¥Q'㇇ÅÇ~ú5q^½{Y¬S¥V3õ‘9}¦€à e‚ƒˆš8VVôðp¯±ì޿݉Z­6Í«ýØÍͨ‰è㥯×ÁÁž¹³fw€ââbû¡¶R³3:Ö´NDx>Þ}I:˜FyY9Þ}{3 Ÿ/péï`°ß¢&NÀÞÖWWt€‡»;·êêjæ/XHIÉùoÃÜڛضcGùI))¬\½¦Îüòòræ/XÈùóçIJI!zÏž:ešcÍú MÞw׫v䱌 &?1¿ý{öÅq )‰>þŒ·Þ™ @ff&‹—þÚÞÍh3«Ö¬·|c Zûܪªª˜ÿýBŠê¹‘lsËÈàëïÔ™?ÿ»¼?ùf„ä~]± ~Z¼”/¿ù®Uõ¯Y¿¡ÉûîzÕŠÏC6îÌ™ú9¦=6…Iï®ñE¹–¾B_´¯ðÐP–,]FQq±éÉËËËIHNÁ×Û›ÑÑx÷½tK¸ýñ„… E¥R1kækoŸ'ÚV»ò¿_~Å£Frß½÷ÔYfeüê}ƒS§O³;fU•UDF„ãáînZvüäI“(>_oo ߘ °g_n..TWW“”Œ½½7޹;»Û‹ãÈ‘£ôðð oŸ¾Ë8Êè‘#MËOŸ9CÌÞ}TVTB&Þ°°°˜}û8}ú ݺteô¨ؘÝ= ãÄIb÷îÃÉ©#áa¦0´¶îæ ðÇÚÚš„Ä$Fˆ`üúùx3fôhþܶGzÐT~ßþx&N¸ €IÉ”—•šöÙêuë{à $¥¤pìø <=<5"²ÆA·¢¢‚Ý1±äæå2ØÏÏb›2³rˆ‹ßJ¡Ã†áÞ½;›¶nÅɱ#ÃÃMe—­\M?_̾­}ÁO‹¸cüx:¾Ùýj×®CÖ»vq§á>… 9WXÈ3/¼HZúavFGóàä©ËП’SòÏ—gŸHbR2¯Î|“÷>¼ô•°±±{yöÅñÁ'Ÿ’™•Éâ¥Ëxìñ'©¨¨0•ù÷Ûï0gîGœÌÊæÇÅK˜üÄ4þܶӴ|ÿ›ö©iiJ?Ì£?Il\\£í®ªªbòÓÙ¶}ÇŽeðéÿ}ÁcӦ׸ÁkÁÙ³¼úúL2Nœà—eËyhÊÔ_QßÒº[ÂÆÚšàÀ@âLó¢ccÆÈÈ’¦RXXÀ…ÒR¥§6Lð‹Ý[cŸ­Z³ž¨‡'³|ÕZ²srxï£yÌz÷=Óò¢¢"¦NšŸ–,ádV6ÿy÷=ÓMwŒ6lÞÂãO?CÊÁTþÚ¾‹'Oewt Ù9¹|ûæ²¹yy|øÉ§,øñ'Ó¼™™,øqNNÛp/]YíÖCæŸ:Å…²2zõôl´¬½ßó•©W›:ýi–­ZÍË/üƒA~Y±d‘©ìîè^œñ:Ï?=;Cy¿ùhŽþœôBi)ãﺛ»£;æ¶íØI\|¿üð=ŽŽŽèt:^{ó-Óö´Z-s>ø€Ç§<Ê]wÜÀ ¿|ùõ·„~5´Ávk4V,Y„Z­?®—”pÇ=“Ø·?žÃÍKíííøîë/q°·G«ÕòÒë3ùïÿ¾â£9³[UwK…‡†°qËÓã˜ØXf¿õ&ž=<ðêÙ“Ý{b¹mÜ-8@o¯^ ö<ÞEÝÀ¨ÈþñÒ«<÷Ôt\\:±à§EtíÒ…çÌF­Vs¡¬Œ¿OžjZ÷ܹB>úä3>ýp.ƒé{ϯ ç²ËÿĨȾ]ðÊÊp°³#fO,aÆ€ŠŠ lllØ·ŸaC†Ô¸ŸåÕ®ÝzÈrCe¼1MClllj 1‡‡†’››`•••qøèQ¬¬¬Ðétœ:sÆT¾£ƒ£éw{{üù‘“—@ôžXn¾ñMÛëéÙÓT>'7̬ÊË+X¿i3ë7mæì¹BNœ<Þ¤ç©V«Ñjµdœ8ɱcÇñèÞS†[¸ØÙÚéïnl(ûPÔ}Äío“º["<,„ÃGŽráÂ2³r(-«À×Ç€Q#"Ù­¿gȾ ip[/í÷¡ÁÁh4róôwˆÞÄ;ï0¬ììpss5•‹ÇÃÃÃF€‡ˆâÔéÓdfgãëãC×.]HHH :v/÷ßw/îîÄÅ`oÜ~F kí.Q”v ¤§‡:t0 =›ÃÞÞÎtŸûÊÊJÞ™3—)OLç—¥ËÙ·¿ÑõíìíMëçåŸÂÕÕµÞ²%çKý°97/ܼ<.^¼Èä‡nR[ÿò+Q?Â7ß}Ƕ];Mw ®OwÊË˹PZÚêº[¢w¯^ú?ôÄ$bbc‰ 3ôFFF³g/ÕÕÕì‹‹'4´á@šÓh4h4V¦Ï­çŸ:[û=7?WW—óììèÔÉ™‚‚³Œˆ'n<ÕÕÕ$§dHp0cFdwL Z­–¸øxÂÃB›¹”­Ý†¬VVVø³hÉRFDD´x;6mæHÆ1~üî4 Z­–Ÿ–üÒäõ;»º’›—_ïrãÅ£Q##Ø¿³Úv"3“/çËŠÅ‹LC»ƒ©© ®söÜ9p°·oUÝ­Âþ ;~œ»ÌÎñýÀÆÆ†m;v’™•EP€‹ëpuq!7/A†ÛÝYZž—›Wc^uu5%%çñp×_ØÉ—ßÌ'19…Áƒü°±¶fôȼ:óMn¿u<]»t¡{·n-n£µëEž}†Ää>úìsªªªj,Ój›v·áÓg P©Ôh4@‘¤9† fËo¿sæLi޳᮳“Aþ,üégS¯Ú • ­á%ã6­môç0UUU×|ÿBi)çΚ¯\½–‘Ç7©ncÏuQÛ¶/  aÏÞ}$$%bvÅZ­V3"b8_~3ŸÀÿ:W‹›cXpKW¬4½TRYYIQÑ¥;ø“•“Ãî˜Ko6X·a#½½z™®´ $+;‡-¿ýÎÃÕÖþý|Ñét,[±ŠÈðp®5íú²‡wß>Ì›û³ß›Ë_Ûv0xÐ@4 ©i‡ð4ˆ¿öj£Û5"’?-â©ç_ WÏžÄÅÇ7ëeÜMcÙ´y “§=Éè#ÈÊÉ!99…‘‘‘¦2/ýãüó•<ùÜó„ J~þ)\:uâ©i×Ù^PÀ`V¬Y‡µ cFÄÕÅ…'žz–¡C‚IHJâl­FuUS¦M'bxY™Ùäæçòù¼šT·­­-ý|}ùß7ó™tÏ= lòónHÈÐ!¼þÖ,‚ê¼<422‚5ë70q„VÕ1uÊ£Lî¦<1  “’)9Á´¼‡‡Ó¦NaÆ¿ßâ¦17p±ú"{ãã™ûÎ,ÓH£Ñ2”õ›6óø”GMëŽɲ«øâ“[ÕF%²²0OEÍ[ÒYqé¶t6†Éóõ×_×” <=<˜pçø ˆµÆšî]»qûm㉚xþ„_¥ÂÙÉ ³“{TЭ[W|úö¥³›7Þ0+•š=FDDàÞ½»~«R1$8ˆÛÆßByY9C‚ƒxöé§píÔÉ´½ÆêAEeÝ»u¥k—.MÙå²¶¶¦“³3£G ‡Ùë½Ýºv¡ƒ¦ãnkº¦ß©5÷³Jû÷ÃÍÍ­F™ Àìíqttäöñãpî䌭µ ÝÃÃBéáánZ'0ÀŸˆ°0ª««éë݇ç¦?I¯^=Í›C÷®ÝèíåEȰKW»wïF'ggÆÝ<ÖtÑHif¿ûîf ¨4Læ·¡3ÞŠ®Žß²ôÂù«öþoüçmú÷óåáî¿ÒM×({ÇÝR™‡—6f~¾Z\Rž½{1ü ¶HËÚõR){ò)zõôÄÍÍ»v3éž{èc6ÄB)®Ë!«íM†¬B\$B(H‹Ï!óòò/$„h–²»áÝBˆ¶#CV!D)„‚H …P ¤ "BA$B(ˆR‘@ ¡ H!D)„‚H …P ¤ "BA$B(ˆR‘@ ¡ H!D)„‚H …P ¤ "BA$B(ˆR‘@ ¡ H!D)„‚H …P ¤ "BA$B(ˆR‘@ ¡ H!D)„‚H …P ¤ "BA$B(ˆR‘@ ¡ H!D)„‚H …P ¤ "BA$B(ˆR‘@ ¡ H!D)„‚H …P ¤ "BA$B(ˆR‘@ ¡ H!D)„‚H …P ¤ "BA:\é\Oòòò‰;p€‚³gquu!È?ÏÍÞÎoü‰·w_úxyµC+õróòøkÛˆšÔnuˆº¤‡¼L–üºœ‡û슎&7/Ÿ¿¶íä±iÓ)**`wÌ6lÞÒ¤mÍ÷ kÖ­o—v^(-勯¾!êáÉ,Xôs»Ô!ê'=äe—ŸÏg_|ÉÂù_áëímš¯ÕjQ«õÇÄ䔃dfgqÛ¸[ÝÞ¯?ÿˆƒ½}›·óÈÑc<ûâ¿È‹Ï?Ã_Ûæuˆ†I /ƒcÇÑh4ôíÝ»Æ|c“’‰OH ¨¸„ù â׿?ÃÃÉÌÊ&5ía¡Ãؾk7¬¬¸õ–›ùkûvöïO?__2³²9~âý|}ˆ‰¥²¢ŠÈˆp<ÜÝkÔuôXûã`ç`ÇèȬߴ™û'M¬Q¦gOO>ûè|½½ILJn×}",“!ëeÐÛ«UUUÌÿ~!••u ¨T¨T*T*°²²B¥V™™Éß|ÃãO=Ão¿ýΉ'Xµf=ié‡MeÞš=‡çþù©‡³3:š'OåXF†ióËW­fڳϓ~ø0Ûwìbâñó/Kë4ÃÆÚºF..?é!/wwf¼ô"ÿýß×,]±’›oCÔ¤{éãÕ €€Áƒ  3;‹)ÿ½ÆºçΞã‹O?fßÀz·¯ÑhøáÛ¯±±±`êô§Y¶j5/¿ð øü˯øï¼<È€_—¯äÇÅKÚéÙŠÖò2¹ó¶[Y½t1ON}Œ¤”|t 3g½Muuuƒë9;;7FkÆF€á¡¡äææŸ@OOOSzõôlÅ3íIyÙÚÚ2iâÝ,úþ[>ž;‡í;v±~Ó¦6¯ÇÞÞN@Þ©|Ü\]Û¼Ñ>$WHxh(Aþ7œ¶7WWòòòÚµÑv$—Á…²2 kÌ+.)áHÆqú÷ó@c­!ÿÔé6¯;80€ÌìlvÇì1Í;UPÐæõˆ¶!u.ƒ½{÷ñï·g3 Ÿ/ž=zpñâEböîcØ`n;€ðaÌÿ~!³ßÿoo¢î½§Mêöpwgê£3cæ›Ütã´Z-ѱ{±ÖhÚdû¢mYY˜§2›Ô†2 `c˜<_ýµq—«‘W»Þ^^Ü}׸ººbmcM~ Ѝ{'¢Ré_âèÒ¹3‘áᔕ—ÓÃï^½@¥ÂÙÉ ³ 2* ìß777ËeTЭ[W|úö 8(aCƒ©®¾Hÿ~ýAbR2÷Þ3¡þF«ÀÑÑ‘€ÁƒÛ|\f¿ûîf ¨4LU@5 5L:Kë©ê™g £1ˆ¶€=ÐÑ0…—^8?¯mŸ‚¸\V®^Ãö]Ñ|úôs²rrðéÓ‡”´T¬;Xsû­ã¯t³„ÈëÀK/<¥› šH†¬B(ˆR‘@ ¡ H!D)„‚H …P ¤ "BA$B(ˆR‘@ ¡ H!D)„‚H …P ¤ "BA$B(ˆR‘@ ¡ H!D)„‚H …P ¤ "BA$B(ˆR‘@ ¡ H!D)„‚H …P ¤ "BA$B(ˆR‘@ ¡ H!D)„‚H …P ¤ "BA$B(ˆR‘@ ¡ H!D)„‚H …P ¤ "BA$B(ˆR‘@ ¡ H!D)„‚H …P ¤ ÒÜ@êÌ&!DýZ”•Æ©«õ³ö|!„eõe¦Áì4¥‡4ßÖ0I …h˜¥¼4š›¦YÍ7~Ñ0 !êgÌI³:±õÌ×Y˜jÒÞÁñÀ°4†m©¹rUKž…W cÀŒ¹¨ª€J  ˬ=ÕG 5lIDATQ_ kW\»Òý€=ú@Ú¢eÀ ¤¸>˜ò"úlTåèYŠ>+Õ4£—´H—ÂdÞ;+­*¸<­až•aR!a×c>Œ½¡1冟Æ@{ÊÚ=c€6ÔCZªƒg œqž†K½£R\/jwXÆ!«±§¬4̳4tµ¨9CÖjô«4›oì1½£1B\/Ìi ¥y0«¹4lmѵveÆ.Ye¨jÌ/æ¨R\?,]ô4°Êì§1¬¾Q ±!+†JàÒKæcfc¯(a׫ú^‰0ž;ÖwµÕ¢¦Y!¬=f–0 a9”æál4ˆF Heá§yø,Q)®GæïÄ1fíßk—­£±©jý^;|µ{E ¤¸Õ~)ü7´ôF€z{ʦ¨v™úzC £¸ž5õÍä [›¢úÊJ…¸¤¾À5齬- “„PˆÆÉ§¢„B!„B´›ÿŒ×ÇS[{/IEND®B`‚././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gtk4/images/basic_example.png0000664000000000000000000000773415074674453022757 0ustar00rootroot‰PNG  IHDRä nùËsBIT|dˆtEXtSoftwaregnome-screenshotï¿>&tEXtCreation Timejue 08 dic 2022 20:57:52‘‘#û¬$Üp<7È:«‚]¹²®ˆ'Ú:=Y´;hG£‰ü9O/nt‘ÁÛxY›´7·ð<­|ÝÑí¹Ålåk·ŸkU{B‰ Ͷx#¾&p£‹Œ/| D|yý˜Ú‹[„Nˆn Q¢'r‹1e‰Œ5üç£òµáFDãÂNã$¥JJ“4PRŸÆu$z’ð°$]–T+é´¤*IW—@ØiøÏz#ÊXAFÆèŒ€N„>I‰’F®{uͽùyÓæÊ#¿‚ˆ^À£`0¬úý¶«ï;w½¤O%]P(Vš£tÂŒe¬p"§¨á!ÆKJÍÏÏ/X»æ•ç=%wøŽ7¸ TýåÙs¾¹k×®í’ÎJªW(LgÔt›Â^¥µ ÃGGgdô5. ’æååÍÚðê+/ƒmšú=šGž†;gßó`QQÑG’ÎIªS(ʵ|m)E‰2Vn#c‚B¯o)=¸ÄÈ4óT ¿yÔW$)ôÓ‰Òm¤¼Š7ÚZ#¾v¢t¦ªé¯¼¼jŽˆˆô¿´êÅ»ÚÁ¯P3qjù®ƒe0ŒuØ[øT5^¡‘±Ÿ¤Ñ‡îÿ¥Gòwúö=L08;bÔ˜û%í“ô™B#¥óš2r'O ­½ösÛ³ê„é÷x‚)]{X-Ð3x¼^¿BƒU¼ZîÜñ*ÆžÖ¶¾dxkpôHꯖSV瀙Vµe„Œ Ò')ÁhU‚š{ ÒYÚµSÇmÚ×%7è¹Â[‰<¤4*·ÒíãS‘Qz»øs™@O~xi´¯)ÛrèœÛäqô´*œÞµûiÒÄñš8~¬r³³u´â¸^Ýðšv—”hˇ[õÇ·ßÚ-Û½fåAó9=:ÿÛ8p $©öüy=õìs*ÞS¢×V¯êÌê£ý…¨:zP8ó–6Xÿ?ohòÄ êÛ¯>Ùµ[I‰”?mŠúõí«C¥eúÝöÊš©YÓ %…¦‰k_Û¤¤ÄDùS’UV^!IzëÍJõ§è¾{îj±þiOÉ~¥¤$kfa¾|¾æ§3hÇÎb­¨PZZª&Oœ¨úKr¦½ïëŽÛoSmí9íÞ·_É5«° ißš÷õ¦u–«ªš½ð‹—u᳋Ýú˜]k9ÙCµ·d¿?±BK[(ǣǟxJ‡ËŽ(;+«3«îP#í ²y# 1­}íu½ûþ®¬T}}½$)+#CO>þ˜ú÷í«5ë6*=}f†‚üôÀa­^»AöÅ;´·dŸŽ”•$½ùë÷äõzußÝw5=îÛvìÒ–?nÚÖ;›£¥="Iªª®Ñ²®ÔÁC¥M—òûµxá ÏÍÑÙÊj­Y·Q[>تŠãÇ›×ñÞo´lÑ£-îC}}½JöÐ;ッ„„åO™Ü£žûï?ò]-Zö¤ÊŽÕâe+äñxTz¤\ƒÓÒôï,èŠûÚ®0c½‰N:SY©þÆßë¹§ŸÔ´)“tìÄ ­}“2† ÑÍ7 ×éÓ•:qò¤¤ÐU’fäiÁ·Òm3B¡>»|©6¼ôb‹õ&è¯Åß[ G¿ó/JN¨¢Ý{uàÐ!IÒªÕktðP©î»û.=ÿÌr}ùÏ¿¤Êª*ýìÅ_´XG}}½o}w¾Rý)*ÞS¢Olº|ë¶íšûwó´ø‰åª8v\sž2î¶Çêz”šªe‹UfÆ`••Ué‘r¥§ Ò’E 58-íšßžä_Ì’”’œ¬[g*{h¦þáoÿZ’T´§DA5«°@’´³x‚ jû'»”””¤qcG‡­ÁyµØr½£GÔÔÉU7ES§H’ŽŸ<¥@0 ~·M©~¿îÿ«ÙÊÊÌЃ_½_þ”•ìÿT—._nZÇÈ›‡kê䉚6u’fä‡v;q²i;Y™™šs×_èö[g*!>^Oÿçózë½Í×ýqíêqq>%Ä'4ýߎ÷Å+>>¾Sëì(FÈk(}Ð y½^ÕÔÖJ’fNÏ—$í,.Ö¹sçt¨´L3ò§ÉëmßÓ’’Úás%PuM._®SzZjÓ[^¯WCÒ U][㺎dgW®4—34SÜ{~hžV,Y,Ç£—Ö¬kß6®ªº&4e-?ªì¬,ege騉zü‰§TUíþXu§ŽéöGðXÜ?~Úø}ii¹€§¥KAiHZºFŽ¡¢â½ÚþI‘€fä_ýó ûNU—ó’$ÊëõêÄ©S \ HAéJÕ–•+..N驃¢?‡nç5.¹ÙÙп¿.\¼xý×.\–>µRG+Ž);+KK-Ô’E ••¥£ÇŽiéŠg:ÿÜ·#d7;sö¬þ÷í_ëø‰SÚðƯ$IùS'5]>kzÎ]¸ õ¯¿¡¤ÄDÝ2~lÓeÉII’¤m;v6íŠÅçóiܘѪ©9§Ÿ¿¼F'OÒ†M¿Òg—.©pÚ”6¾ úás?Õ[?Vé‘rïÙ«Ÿ¾ðs;^#oÞŽ{oßáÒ2–«%‹ÊŸœ,r²–,Z¨Ãru¸ìÈ5¿=ø[8ø5ÐËü÷ª—š¾ó¹QºóO¿(çñ›9=O«VÿRG+ŽéO¾ðyy½Íp|~Ö ½ùîf½²v½Ö¬ß¨Ÿ¬\®–»û9ïÁ¯ê+žÑ¦7ßÖ¦7ß–$ ÏÍÖ×þæ]ý+<q*•WThëï·éƒ­+\fÆ`=üÐ<—íÞ¸6¾übØw¡ûåO¨•ÿñƒç]+²ç<%Ý+-5UëÚ·ÿ€2† VÞ”IŠ‹k>8=-M7¦C‡Ë4£0¯Åã:jäMzvùRíØU¤> }”ÐG~¼æÎ™­Üìì¦ëN7V^¯WÃrr””=T?^±L;véLe•†ffhò-äóù”ä÷§hîœÙÊšÕ´ŽqcFkîœÙ6Ÿ†ffjâ„Ðvxî»Û{$áÇ­:Hî«Ð.“—éöí^y­näê¯ÿ£&&é¿~ütÔë}íŸæ«¾®N«~ö\‹7÷qã9züw$mUè¯Ï“tQÒ%µüSW½âìø³Ï¯É¶kå±ÚY´[µµµšYX _œÇµ—ã5ä5ý±úí‡I’ ¦Mnõzè:>e-)fÊ D1rÌ„k;eåw9Ðõx ÂkHÀŽÔ !HÀvê†tb§I])+`H‡GÈŠ#‡»òvP'‚,¼íŽ®¼Ä”0… C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0„ C0¤½AÃÑu¨•XA#N#Ïà.Z3­¶Ó–2|EÆ… Ö¹õ³›¶NYÃW~¥qÓI»1_”óƒ.K‹ ûHœ/©Ÿ¤Iñëòª9rOGîpƒpsºhT/©NÒgr2r¹J´ #7¹Ñ?Hê¯P}ŠÒ')N‰Þ!<È+ µQ'é’BA^T¨•µc”t 2¨æ˜ÂGGg£õ’.«9¼@ãyq‹GĈÞÁéà 6.5ž:A:#eäÈxU ­nSU'<'8ç¼x5މÞ"rÀr¦¬ÎHY×xžÛÔÕU{¦¬ Wv¾3b:££$Ð[„éDfƒš§­š²FnÌ’=’ZþFß™ã#$z·žN€õa§N¬1ˆ5eUãF¤æ·:ÂçÌΨHŒè­¢½á¼vŒ¶·ÕU[§¬N„‘sfbÜ£ 3fˆŽÖò¸œ†Çç"A¢7 ?'<Ìȯ#¯{•Xy"¾ŽŒ/rT$HôF‘oe„†nD)ÛPäu¢†ÄˆÞ¬­“·:mmODÑ®Kˆ@³hÁµéXÖŽÆD„@l|* ÐmþÁrëO \ݯIEND®B`‚././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gtk4/images/clipboard.png0000664000000000000000000007046515074674453022123 0ustar00rootroot‰PNG  IHDR ‰³rˆ§sBIT|dˆtEXtSoftwaregnome-screenshotï¿>&tEXtCreation Timedom 25 dic 2022 14:44:236 ¾ IDATxœìÝwtÕùðñïl×j‹êªwÙr·±166¦“„Jè!”@€B „Nx P„$@pè6ÍÆ˽۲zïÒ®VÛçýCÒZ’%K–lI¶ŸÏ9s$ÍÞ™¹s÷ÎêÙ[f@!„B!„B!„B!„B!„Bˆ½¤ìÇýíë} !„bä©ýü>,à ”^?{¿&ˆBqàSé;ðP{ýÜ+C zÝÿîþ»f(B!ĘêüÙ=é”ô¤ôkoÞ-šn?û <´{“!„BŒIÁΟ½‘Pë»ÿÜ#Ý ÞW+‡¦×ïš^ë¥D!„8ðiÙptý Ññ¿¾¿ cÀ d0- ½[7zZv Ýý ö-„Bˆ±ÍOÏÀ£k Ò3(éÞ*2`—Ì@- ½ƒî‹–]Á‡ˆâ+1ˆ} !„bì 퀨;×iéB‚tÄ Ý»dºb‡~ƒÁ ½ƒ]çu€ÈüâóO®—“ól¨2F!„8h(¨¨´îعó“OúÉK@1Ю†Š@¯-B `O‚BÏ1Ý[;º0¡¤pÇKt"B!„8¸µdd»Ø ÔÒ|t-½»fúíŠÙSÒ}–KWwKWàa¢€©%…;þ‰ªÊx!„âP¡(þŒìq€fÀÇ® ¤«[¦÷,™ž»èo×ôœÝ¢¡cP©®ó§˜Z´sû[ ØöÉÉ!„‡BkVÎø éB¼t V tþì>XµÏVÁL•íÞÓÕúÿÙÇ]&Á‡BqhRÀöÙÇ]FǻƇv͆ݣþÞ÷úè=þÃ1n\·›y!„B¸:c»âƒ®‹Þ÷ ÛÍžfÁôî†éÚ¹ˆR4ŠuŸ=“F!„E£Xéªgר qƒJÏ›•õ0˜û€ô¾÷‡0«!U‘¹¶B!Ä¡KUU0Ó³û¥kÙãTܾÞÏ|é=¤kÙwÏäB!Ī{lÐ{ H÷Ÿ=†= BíÝúѽ+Fžó"„Bèôõh–>õ×£ôú½{0ÒyOiÿB!DG³ô5ð´Ïq ýuÁô¾û©¾s1„‰?„²ú†âbcG9'B1l†nK÷»¢jéûɹ€<0Nˆ}æë¥ËøjérŠKËp·»Ir$°`ÞÎùééœùUD˜L¼úì_i÷x¸öw·¡Q^{þŒFàöþåWa³Xyñ¯ïç3œï~Ègá_žâŸÅ眵Ûë7ÝþGŠJJúÜöíW_Äd4îï,I÷÷J±ÿ 9‘!:„B!~ìIV®^ƒÉh$#=ˆ¡¸´Œâ²ò׊  ÒÓRÑ( :½n¯¯¥±ví ôÌíÙ3C¯ïùQ£h4cî¿z… Ÿ¼§Çº½3V®½Þ¡U߯ÿæÚ+ÃeÒÿöcÑXÏŸ{çÌ /eâ„ñÜñÛß`³uÜȼÕåâ‘¿ü•›·òþ[ÿÑüHŒÃ …xç?ÁM×^µÛ?ZFÓo7×_^oàõžÿýãÇét’¿j-‘–HÎ<íd~|Âq=¶k÷zyôÉgX³~#Qv?=õd~|±=òóïñͲåÔ54š’Â…çœÅ¬Ã¦ÐÚÚÊ[ï¾ÏÚ hhlÆn·2oÎ\|Þ9ôúp^æÍ™M|l,Ÿù ñ<|Ï´··óÒko²jÍZB*¤§&«ì}òo,û~—^|>gv ÕµµÜp˰Ûm<øÇÛyÑ'æóÈ#Çd4ñýÊUh4NùÑ qøLþþ7ؾ³ˆ¸Ø~uÅ/˜û‚¼ñ¹1ó0V¯[ÏŸ}‚P04êõOYöf¹÷ö[HJtPRZÎ\È\HQI)ޏ8î¾ýæ¡ï{ˆ¤Dˆa¨®©Àfí«‹aïDGÙyâáÐjµ,ý~~êo|üùÌ9|f·4Q<òÀÝh4¾üvO>û}¾˜Ù3£¾¡‘ÏIZj =tZ­–Ï¿üšg^|™÷}Ĥ ã1™Œüýé'Âû«ª®å×7ßʪuë¸èܳÃë5 ºûNÆçfPY]MþêµÄÇÅòçïE«Õòé’¯xö¥W<¯ïóWõø[£ÕqÊI'`·Û¸ü’‹xê¹¹÷áG()+çÔŸÄ´É“•ÏÈH3{ìÿ¡ÑhxóÝÿðÿù€Ž^À¯¯º€ßüþÊ**©¨¬"+#}ÐåÜ¥¨´”Uk×3ë°éÜ|ýµx}>¾[±’ÊêêQùÖ(ÄPÅÆÄðà]wp׃SRV@|\,÷ßuޏ¸ÏÏ0¡#ìâ  @UMÍ ®‰Þiºÿ­×éÑh5¨¨1ë0E¡¢ªºWŠFAEeÞÜÙ<õÜ‹”WV¢¢R\VF(â°iSÃû9êÈ9<óâË”UT„÷³uûþ÷éì((¤ÅÙŠªª8[]=ŽÁ¸Ü¬ðºÒò ¦M™Þ·ÕÙí,ú?÷×^xºG×T÷ó>îèù|óÝrÖ®ßHRb—\pî^åS£Ñ†Ëc|NG°¤h•pšq99”UTÒêr†× ¦œ»òX^Q Àª5ë8ó¢K{¼ît¹öxÞBŒEZ­ƒ~×Ì;½N^¯•º,- B CJr†â’2JÊÊÉHKÝ'ûõx½=>(zóú|è´—±ÇÓ±M0Ü•ÆëCQ”ðX”ÊêjîyèŽx®¿ú RSS¸ú†›ÌO0ØñH‡“ig³g±ÑQ¿©(eÈùÔhvïQÖj÷ÜËc rîý^ýøøãøø‹ÅÜ~σ{Ô<êikoç–ß\»Oò#ÄH)*.!+#?Þv3ÑöŽÖŽûïº>FQIéˆçg•áœ,²Œ%Âdä‘ûÿÈ%œKnvUÕ‘àˆcâøq€Ê¥O´ÝÎ'‹¿¢¸Ç…Þµ°FF’èˆgŪÕ$ÆÇqçÍ72.'«GšŸx–ÈHVä¯"ÁÇí¿½žIÆ…Óüþ†kùÑ ÇÒîñ²jÝ:òÆå²ðÞ;;[0T&æårîYg ÕjYòõ·ÄÇÆt|¹ë8=ÿîXn½ñzæ>“úÆFŠŠ‹¹þêˉ‰Žî3m÷ý¬È_ÅÒå+z,ÁP—ßx“†Æ&.½à\b¢íüò …øÛ‹/“7.{ùdë_ν߫+/½ˆKÎÿ­†ÿ|ø?¶ï, ÂdDUC#ZÏd‘e¸Ë{ÿ|…ÇÿtÑv[x]´ÝÆãº÷þùÊ0ö=4}=¥®ûSo»žѹ˜ 0§`Û¦±q?h!ýòl+Ï=ùèhgå &å,ľ—›7ùwÀ À¸öÎÅß¹ØõL˜°a´€!„B ÍÐÇ€ ½ÕEѹ®F†”³£Nž#Ę"×ÕÈrb´É,!Æ€7_zv´³pHrbìÆP…B!†FÆ€!„bÄÉ!„BŒ8™†+„Bˆ'ˆB!Fœ BB!ĈÆ T A„B14Ò#„Bˆ7äŠÒ¢}™!„BB†€ÌYp닚XW줺5(CÄèP Ѧez¦•iYÑ&WU•Ö¦&šëhw·@…è[„9’è˜xlÑÑ(J_'ßEê­+ö¦ÞîɰnÅþÅšj6V±ÚbHJ‰ή„¯§%[Z¨mörâa‰ý¦SU•úÚ*ÚœN’Ó°Ù£F0—BôÔÚÒLMe>¿‡8GR¿æRoÅXÒ»ÞÕõEMl¬ —Èü“ =bèT`K¥‰e;#ØXU#ª©Ï–UUiij¤ÍédÜÄ©#ŸQ!z±Ù£°Ù£Ø±ez½{tÌnAˆÔ[1Öô®·C5äA¨ëŠXmvæç˜˜$Á‡E 0)ÙÀüV›uÅÎ>Ó…B!šëIHNÙ 1€„ä4šë …B»½&õVŒU]õv¨†ÜRÝ$)%‚‰É†!\ˆ}ib²eT5w{MUUTUÅãnÃj³£Ê4r1†XmvŠ ¶†ëiW+ˆÔ[1–uÕÛ¡ú4ÜÎë@Z>ÄX®‹ý|Fˇ·ëúª£RoÅÁJî"„Bˆ·_’ÒÒý¹{!„B ¤D!„#nX÷âÀ$}êâ@$õV\$‡Ó'DRoÅÁf¿ UUUÜ{ï½|öÙgTWW“À‚ xòÉ'‰‰‰Ù߇Çã! a6›Çäþ„¬Å_~Ň}Äö‚ÜmnÒÒR9ëŒ38û§gŒÈñϾàBÊÊ+ú}ýÝ7ß #=}Èû÷ú|¨¡&“iÈû£ïÎ{ïã³/ ÓéHKMå쟞ÁyçœF3üQé'R‡GÖ~ @|>§z*³fÍbÑ¢EÄÅÅQQQÁ7ß|CTÔØ¸•ðC=DAAo½õ֘ܟƒqÿC“¿f ×\u%7^wþ€Ÿ­Û¶cµDŽX^ùï¨7ÒzóÿÞae~>ydaøõá导ö:eååŸßÿþ÷dddàp8¸úê«q¹\»û‘Gᡇâí·ßF¯×sÝu× ¸ý}÷ÝÇôéÓ ¸\.ÒÒÒxõÕWûÝ_—óÏ?Ÿ_þò—=Ö-\¸3Ïüø#^û盼ü×ø|ñæs<ö—Q/÷}¿ d´ó·ÿ–Ó§ÑÜÒ‚ÛíÆï÷ñ—¿þ•³/¸£N8‰s.¼˜>ý´Gúå+¾çÒ+¯bÁ‰?â¬ó/äéçŸÔ~ëÉžêÔáý]oû·_éÓ§3uêTŽ>úh.\Hyyùniî½÷^Þ}÷]Þ}÷]V­Z…ÑhäøãÇçó…Ó,^¼˜_|‘‚‚²³³9üðÃ)--eÑ¢Eäçç³sçNþð‡?„Óßpà lÛ¶•+W²zõj ¹í¶Ûv;ö­·ÞÊwÞÉùçŸßïç™gžpû;ßÏ_ÿúWî¾ûn¦M›Æe—]ÖïþºœwÞy,Z´¨Çóþûßÿrî¹çº,ë‘GáÕW_åõ×_gýúõ\|ñÅÄÇÇc0ÈÍÍå½÷ÞcãÆ\vÙe\~ùålÛ¶­ÇöŸ~ú)Ï>û,………Ì;—sÏ=·Ï|ôwœÁžÏ+¯¼Â£>Ê–-[8òÈ#9餓hnn°¬DÇCYy9S'OÚcº^y•Å_}ÉÂïçõ¿¿ˆA¯çšßÜ„ßï§ùïGó›ë¯å7_gêäÉ\÷Û›q:œtüñ|ûÝw=Þ‹o—.ã„ãŽÝëüþù‰§()-çµ—^àW^¢¼²’§Ÿ}€Ë.¹˜@ ÀÛïþ€çÿþwÆåæpúÉ'ó‹‹/äŠK/ᤎãû¯—pëÍ7íõ±ÅØÕÐPOll,fsz½žÔÔýÓƒ¼ýú«œ~ÊÉÜ÷ÐÃáûJµ¶ºøýwqú©§ð¿ÿü›??ü Ç}4@¿õdOõnoIÞwökb4Y¶l7Þx#O<ñ™™™\xá…¬[·¯×Ëc=ÆsÏ=ÇÔ©SÉÎÎæµ×^£µµ•ÿþ÷¿áýüüç?gÆŒ$$$pË-· ª*·Ür YYYŒ?žË/¿<ü ½µµ•_|‘{ÃAjj*<ðï¿ÿþ ò<ÐöƒçŸž{ï½—ÿýï¼þúë¼øâ‹ƒÚ÷)§œB[[?üðµµµ¬Y³†ÓO?}Ðe1@€?ýéO<÷ÜsÌš5‹””.¼ðÂpóü¯ýk¦L™Bvv6wÜq™™™áÓTTV˜0~|x]DDS¦L¦¸ŸîQFÃÔ)S(-+Ãh4²`Þ‘|»lS&Obéwß1göá=Æ› FIy9¡PˆÛîº ¥óÉ=`·»-œfÆôiüè„ã¹ùŽ?pïw×y~âàòÖ;ïòÖ;ï¢( ÉII\xÞ¹üì¬]Ý«ÍÍÍ|úù¬Û°‘æÖ›ñx<def2ë°Ã¸à—rÔ‘GòÓÓOcv·Ï™ÞSïKêð¾5b÷Ñëõœ}öÙœqÆLž<™wÞy‡sÎ9‡`0H À`ØõT]£ÑØï4¥®  ¿u]³kV¬XABBÂ^çs°Ûçää …ö8£/çwwß}7=ô|ðA¸KÁãñ ª,ó`ªææf€>íír¹˜;w.?ûÙϸûî»IOOçä“OpŸ}•ûžŽ3ØóéM«Õ†Gš÷WVb»ÝNLt4ËWüÀ¤~ŸßG(" ö˜æhÐé1ýî[«Ñ„ß«O8žç_z™k¯¾Š¯—.åÄ!t¿X#;ó½úÂóÄDG÷›.%%…P(„Á(SVçœu&×]}ƒ¡Çç€ÛÝÎ忺–Ž=†+/¿”„„n¼åÖðë†gžxœÕkÖòáÇsëäð™‡ñèŸêóXƒ­wƒ!uxßñ[±ët:’““1™Läææ¢( ß~ûmøõ`0H~~>S§NÒþ322°Z­|øá‡ƒÞ¦{?ø`¶ßºu+ .äÏþ3×_}øq_ûëíä“O¦¤¤„Í›7óÍ7ß„»S‘‘‘lÙ²eÀóÉÎÎ& ‘ŸŸ¿Ûkùùù444°páB&OžŒÕjí3¸Œ=g°ïmï–©•+W2yòd ÿ²>õ Z.ºà<Þxó-**+ú|=5¥£…níúuáu¡P-Û¶‘›•EWc³ËÝÖc»Í[·’•• ¨9窫«)*.bÍÚu5oÞ òÖ³¬“DšÍ|»tY¿Û—óúÿäÆë®åÑÇÿ‚Óé챿ŽÁߣ_æûgÈhçoß§A§Ãb‰Ä`ÐïöúÖm[iimáúkEvV&‘攺îXf6{þp;/ýíi¾þv)uõuáýw¯'ƒ©w{~OÔ½ÚסW‡‡n¿ k×®åÆoäóÏ?§¨¨ˆ;vpÿý÷“ŸŸÏ¹çž‹ÕjåŠ+®àÚk¯eåÊ•ÔÔÔpÓM7áp8øÑ~4¤cêõzn½õVî¸ã¾øâ ‚Á eee}þ“HKKã›o¾¡¤¤„¶¶¶·ƒ\~ùåÜzë­Ü|óÍÌž=›[n¹¥ßýõf2™8ýôÓ¹ñÆY°`v»`Pe1þ|þþ÷¿SRRBii)/¼ðBŸçËYgÅõ×_϶mÛp:|øá‡¸\.’’’hiiáÙgŸ¥®®Ž7ß|3<&goíé8ƒ}oï»ï>þûßÿRWWÇ}÷݇ÓéäœsÎÙcY‰ž.:ï\òòÆó‹_^Í;ÿyŸ…E”–•ñÉç_ðí²ïˆ4›9ãÔSøþ ›·n¥±©‰ÇŸú+1QQÌ9bW÷ÙK¯¼Ê7K¿£¹¹™_y•6·›ãéÜg4X0=ù43¦OÃ2„û‹èt:~~Ñ<ýü üŸO(¢¦¶–Í C¡÷?¼Ÿ_|!_p>“&NàÉ¿=ÞÞáp°zÝzª«kztÁŠƒKll .Wÿ~ïš››ùäó/((Ø~½ÅédÑGSW_ÇãaõÚuDDD„»g{דêÝÞ:¼oíפ«;ãÆodêÔ©ÌŸ?Ÿï¿ÿž%K–——ÀSO=ÅÉ'ŸÌYgÅ´iÓhjjâ“O>ò·r€;3Ûo¿n¸»ÝαÇ˪U«úL{É%—0oÞ<¦L™Â\0àö=ö.—‹ßýîw<ýôÓ¼ýöÛ,Y²¤ßýõvÞyçñÅ_ìÖ¥0PY<òÈ#¤¤¤0yòdN<ñD²²²úmBÿûßÿΔ)SX°`iii<öØc444——ÇÂ… ¹çž{ÈËËãý÷ßr°·§ã æ|N<ñDn½õVrssY¾|9_}õU&ÙþÊJì¢ÓéøÛsÕ—óù’%\uÝõüòW¿æßï@[[Ǹ›oºyGÎá÷¸‹ /½g«‹'´Ç{qĬYüõÙç8ë‚‹Ù°iÏÿõIôz}øõŽ;Žòó‡ÔýÒåŠ_\Âe?¿ˆÇžü+ÇýäT®ùÍMlÛº€7þõ6ííí\|þyüþ·7òÅ’%ä¯Z À)?>‰éS'sÁ¥—qç}÷9blËHOçúkÅó/¿ÂÏ.ú9ß|»”9³wÊ.§“Å_Íϯ¸’“N=ƒ>üÿ÷À};?7úª'{ªw{Kêð¾Ó×yMç¢ôKDçb,Àœûþ¹áñ¤Ôt®:ºÿA%¥¥ÃºmíÁjûöíL™2…ºººCú[ýìÙ³¹æškv»ßGw{[V/~ÓJUy)¿?3«ÇzUU lÙÀ¤é}Î=”]vÕ¯8û§gpÆi§ö›¦´¬Œ /½œO?üË^@Û¼.ŸÜ‰SÑétáÀPê­ë6¯ËgÖ‘GÿX¸7ÐÞ¹ø;—ê\ÂF|ÔBe IDAT ˆ€÷ߟN8á>KÊjìøúۥ̞9S‚!Ä>!OÃo¿ý6×\sÍhg〰Êjx§ný—ÍçK–pö™gì1ØŸ¤ÜÅÁEZ@FXAAk×®åŒ3Fæ ¥2)«±£¬¼‚;9zþüÑΊâ ±_[@düÇîrss ƒ£1¡ë¹/ý‘²9¯¾øÜ_OKMaùW‹÷˜F!ö†´€!„bÄÉqÈîó Øûþܹ8„I½›¡ xUúžË+ÄH „X!åÃVˆ¤ÞŠƒË»`mZ¼žv¶Tîý£â…ضTúðzÚI´iûMc2GâjmÁ\ 10Wk &sÿÓ›¥Þбh z;! Ó3­8[[X¶ÓÃæJŸÄæbÔ¨ÀæJËvzp¶¶0=ÓÚg:EQ°Û£©«©Ù 1€ºš*ìöè~¶)õVŒE]õv¨†Ü3-+šÚf/«ªYÒngYÁÞ=Vˆ}ÉëiÇÙÚ”$-Ó²v¿ EAQ"mvüE;¶Ÿ„Å&78£ÇÕÚB]Mf‹…H›=\O»H½cQïz;TÄzâa‰8¢šXWÜHUCPº(ÅèP:ºŸhí3øè¢ÑhÐjµØ¢bÑi ÔÕVQV¼³ßôBìo&³›=³ÕŠV«E£Ù½QZê­kz×Û¡ö,˜iYÑ{üÐb¬P%|±Xìv",B!U"g1 4šŽ:Ùµô×#õVŒ}ÕÛ¡’i¸âÒõaÞõSÝ¿s…Ø£®.F³Ç'€K½cÉ`ëí@$‡ùcÉ`?À¥Þбd8G @Ä!k_\@BŒ4©·â`!·bB!Ĉ“D!„#N!„BŒ8 @„B1â$B!Ĉ“D!„#N!„BŒ8 @„B1â$B!Ĉ“D!„#N!„BŒ8 @„B1â$B!Ĉ“D!„#N7Ú說£!DäqðBˆ}aÌ { 8$btu:z_!†bÌ ½õtH "ÄÈê .º_{p!ö…Q @zªªöX'ˆ£¯¯`£ûº^BˆþŒhÒWÐÑý÷®¿ F$bÿêDô:ú 2E‘Ö!Ä ŒXÒW@Ñ=Ð…Bá¿û @$îbduÅ} ]‹F£é3 t\»„!ú2"H÷€£÷OUU …Bá$RQé @H„ûG]¿£ Ñ(á® ¤¯ýH"„èË~@újíèxtý †B¨¡ííí´··ãõùðû|ƒÁpºÞûBì½FƒV«Eo0`40›Í˜L&mçõÜ•®¯î B„½ø ÔÞ­Á`ˆP(ˆÇã¡­ÍM  àñzðûüBjh·}!öŸÞÁ‚FÑ Óé¨Á@€¶67‘‘ˆF£E«íhé«KF!zÛ¯HïpkGg«FHU øý´··ÓÚÚJKK 6«•¨(1Z;(€ÄBŒ ףߠ¥ÅIC[Q¾(¬V+¨èÑ„BáÖ’îÝ2Ò "„èmDº`z·ztu¹\.õõ x=íädgumÕã‡b è¼õzqqÑÄÅÇPPX„Ûí&..‹Å‚V×ñ‘ÒhôB„¢Ë~ @ú»ÇG÷࣫壮®‘–– ¨2ÕEˆHzr 5õõÔÕÕ£Ñhˆˆˆ½>lôþÙõÙ Áˆb¿wÁô|ü~?µµµèuZlV½^Ævq QU =±ÑQ´:Û¨««#))©Ç}Bº¦Jà!„èmDž†Û}¦KWðÑÖæÆç÷a21›ÍÒð!ÄHEÅlŽ "ˆ×륭Íßï'ì6½^!zÛç- }ÝÝ4<Û%$ âõzinn‰Ñh(!`ªªbÐë1›#hnnB¯×¡ÕjQ… }߬L¤ !ö[ Hﻚªt"@¯×GSs3V‹…“ieA1BL‹…¦æf¼^_ÇôùP(|SÁ¾n((„8´í·A¨»Ýå´súm Àï÷álu úPUýþÈ‚b„…BAœ­NüþŽD«Õ¢Õj ) ¡Îé¹2DÑe„¦á¾ÿG s H»§P™j+ÄA"Ri÷´ã÷wÜ@P§ÓuZiùBìf¿ ½»_‚ã?‚wQôù|M´BˆƒA(ÂçëhýCák^«Óõø<Ö!ŒÀ,UUQ»ß€¬+ ä[‘UU;f¿t^ãÝ»_åZBô¶_ÞƒÏ:n¿¾ëVìBˆƒKøQ ê®)¸2UÑ—}ÚÓ׌ªöºj0H(¤ ©¨j"ÄÁAUCák;Ôí)Ö]ãÀvO/Ý1BÊöÿºÏ†éù<T$þâ`Ñ9Ø|×¢î BV!DOûåFdý= &ÜÒÙ<{¨ªoh¤²ªŠ`(ĸì,Ìfs‡vuñx½ÔÔÖÒØÔ„Íj##= V;àþUUÅëõ²nã&TÒRRHINR^먭«Çàˆ‹Å΃×륡©™ú†L&‰ŽxlVkx[ @Qq îövbc¢‰‹cõÚµC!r³³HNZžºsº\•”âõz™0.k·ã‹‘×Õͺ§®™Š+„€˜†Û›|‚òÊ*¾ýn9í~ŸŸ‰ÆcµXúL—¿f-ådefœ”4¨$¤ªÔ54²ü‡|<^sŸ5䤡±‰µë7RSWÇÄñã8æ¨yè""hnieÕÚulÙ¶H³™ãÅÄ ÖŽ§¶«* M,_™ÛÝÎÔÉ“0Œ|ñÕ7øü~ôz Ú>¯½ÑØÔÄ·ß}OSs3ñq±€Œr !2"£ëþ{Ï–õì©ohdãæ­467£ àpÄÙãa0dóÖm|·b%MMÍ€B0Ty©ªŠ»½×K[[;míîa•s]C=«Ö¬£½ÝÃÜ#ïxâ)PߨÈòV²eÛôz™éädgb0©!JËËÙ°i3z½ñãrñü¸ÚÚðùüx½¾ðÍ©†ÃéjcÓÖmTU×pÆ©'’õiO|~?; ‹1ôÄÅDcµZÃe ©oh¤µÕ‰Ñh$=5eXÇ õq÷¾þ…¢Ë~Ò×ï=ÿ>Ttœ·ßï'ÍZæÏ›CBB<&£1œÂét²m{å•DšÍ=¶ë>¨WUAQ@£Ñ (´Z Yiœxì1(ŠBjJRx»`0Ø™N w‡)(hµš>›ÄâqÄÇáõy)-/Çï÷Cçmõ.%e(Š‚×룶®žÆ¦&„B!JÊËqµ¹ÉÍN =5™¸˜hÎ=ë§ ªÝI:-ª"¢Ñ(y¢sp2áç‰ô †:Ó(½ºòzÖ§]eÔ±N£Ñ„ÿùv”EÇ­Â5Š‚¶³e©û6»¥ï\¯í¶~¬kjjâGþL|\,§þø$Žœ= ‹Å‚ 4·¶òѧŸ³ü‡|²2Ò¹ãæ‡y´]ÁFµ{ø,BºF¼ ¦‹|uŽÕðùX»~ñ±1äfg…_Ë_»ŽÊš‚ÁànÛy½^j(¯¨¤Õé"Òl&=5…„øxL&#ªªÒîñÐâl%b³Zˆ‰ÆÕÖÆêuHLpm·ÓÜÒBEU f³‰ñ¹9DÛí»ýcµZ,ÄÅÄbŽˆÀétÑÐÔ„ÝfÅãõQW߀×ë%!!žúújjk©©­  eeå´··CbBÁ`ÚÚ:Bjˆøø8ZZ[Y‘¿ŠÔ”Tb£ì´´:©©«C¯×3aü8lVK88€Ž–¡; ©­«G¯×ÓÜÜÒg] †B´{<ÓØØ„^o$91ô´4 õ Mãt¹HJL`ò„<›š)+¯Àét‘””HVFZ­–úÆFJJËiiiaòÄ<âbcÑéFíò4­NK‚#žšš:}òm®6N:þÿü×;¬ß¸¿?@”ݾOŽ'×µb°Fô´ÏfØCøóJ£ÑÅ–m;Ÿ“MfZZŸÏϪµëPU•ؘhüþ@Ç*¸ÚÜ|õí2¾_™ÛíÆï¢Õi±Y-Ìœ>£ŽœCLT®Ö6Ö¬Û€ÇãA¯Ó‘‘–Fk‹‹¥ß­@¯×ÑÜÜ‚ÛãA§Õ’Á±óç1eâÄžyT4DGE‘œ”DQq U$ÅÇÓØÒJUu-&'½€OIumÕµuLSU|>?•Õ˜LFâbc0›L4µ´°tù ¡q±±d¦¥ÑÒÒÊg‹¿":* EQp··ÓÖæF«íøÇyöé§’™ž†F£¥¶®ŽO/¡ °—« FC  ±©©£^u6€¸Ýnvóé—_Q_߀ÇãE£ÑegBn.'ÿè¶í(`ý¦-L—Ã伎¤  e+VR[_O^nɉ ˜#"(.)ãë¥Ëq»ÝL›29ü~Œus$œ}&ïýïcÊ+*ùvù ªkkQU•u6á÷ù™yØtŽ9jÞ>=érB dì…;ˆôzfL™ÌÆ-[)ØYDnvŽøx¶RZVAVF:Q6+;‹JÂÛè´Z z=Qö(R’’0 ”WVQRVF("6&šyGÌÆï÷SWß@{{;®¶6Tµ£Ë§¦¶§ÓIJr‰ 6o¥¹¥…$‡ƒÌ´4,½ÄFGÙIOI¡ °ˆ²ò &ŽGCc#µuuØlVf6ƒõ›6S^QEmmííêëhmuâpÄF£!RUSC ÂínèTªª©©­##=øØX,æHvSQUÅ„qã°ÛlhµZ6lÚÂÒå+Ðëõdeda2RY]ƒ¿ªºÇXƒ²Ê*–|³”5ë60qü8ÒSS¨oh¢¬¢’úúFR““ÉÍÍèhIÑéðx¼ JÊËÙVP@Ss3~¿ŸŸzª ¡àÞýP…ÈÈHt:]ø¡½éu:ì6+ÉI TTVSX\LM]=&“‘¬Œ †ÌŒt¢ívªkëØV°“ºº:4 Žxì6Û^åI§Õb‰4£( ÁP°s°®—Ë…¢($'$`6Gô¹­ÛíÆånC«Õe`5›#°Ùl¨*8]n‚Á I‰RS’Ù´yÅ%Å´:[io÷0.7—q9Ù¬Z·EÅøü~ZZZ±ÛlädX]³•Úø¿÷>`݆MâãQU•º†>üè|~?'w –HóÀ;Bˆ}dtCyn·ß'ŒËeÃæ­ì,*¡¾¡‘Ì´4²32±DFîJÛYV•ÕlÞº¶67GÍ=‚“t"z½Ž¾ýoZZ7í¾ÿnÛîöw碠ìvœÞÌfr²³©ª®eͺM¸Ú\ÄÆDw E!1>ž˜èhv•°mGmmn’°Y­hMÿyè+Ÿ*ßлåI¯Óc2™Pi¥ÕéÄïõ£5{îGíWcÔ444 A¥cOCE!ÊnG¯Óe³‘^¯§°¸ŒúÆf̤%'KbB;‹‹ñz½´{<¤&'‘àpPuÖétñÚ¿ÞaÓ–­qøLŽ[0 ÀÛï¾GEu ß,[Ž‚Â™§þdx;€ÊE1úŒ›ä"##É—Äñ¹ÄÇÅ2îDGEõ˜~Ú¥­­ g« ׋F«%Ñ…PgKÁþÁ¸œlôz¥åå8.¢£¢ˆ‹‰AQŒF#‰ŽxÌ&uõõ¸Ýn2ÓÓ°FFî“ã["#ILH  ñCþjŠJJ¨®©¥¢ª*<ÈÀfµE(bÇÎlÛQ@Mm;‹Jغ}Z–ÜìLÌèuzb££ILpPZ^Á΢b¬ÖHlV+9™444±cg!ɉ‰ †}r>#Åçó³aÓTæ>“ã>Šñ¹9L—Ëé§ü˜qÙY´´´PTR2ð΄b’.˜1@Qr³³Ðh447·0eÒÌ&¼>ßni-‘‘˜Íx}>vì,ä“/–ÐÜÒBumí°ûð÷$Âd$;#£ÑH«³G|ŽøxŒFCøˆ‹‹¡¬²ƒ^OfF:˾iÖ‰fRÞx¶lÛÎÚ ñú|جªkêèþÕÛAZZ29™élÝQÈ×Ë–³cg!MÍ—–’’”ÄÌéÓ°Z;ÚFEÙÉÊHcóÖm¸Ú\9{ޏ8ÌæòÆåðýÊ|êIIN"%9iŸœËH2 Ì= s„‰Ó¦™Ao@UUfÍ˜Ž‚BaI ޏ¸ÑΪâ3C¯ÝÖd4…ßè TâãHˆïùOÀç÷a6GÕjAQ ÁǸœlªjjiniá£Ïc6G 7èINJÄjT´: v»£Ñ@„ÉŠŠN§!:ÊŽÑ`è TPT"LF¢£ìX­ôz=}½'½žÄ„xR““Ñh4d¤¥’–šÜ#mR‚ƒÌŒtÊ*ª0 dd¤a6›Ãi4Z…˜˜h‚ÁPç]_Ut:-±11èt: †Žc+Š‚Á` 6&›Í‚^¯#6&šÃ¦MagQ1å•lÞ¶½N‡Õja\neåèõzt:-™éœpÌ| UU”–•¡Õj‰‹aÆÔ)L™”>~”ÝÆ¸œlb¢£Ðh4¤$%uü®Õ›‰ÃËå"-%…䤄>Ëf,³Z-\ñó z­UQ”Ž rþÜÙÌŸ;;¼^!FÊ(Ï‚94?òR’9zÞ‘ƒAôz(JŸå ÓëÉÍÉF«Óàˆ‹C«×aÐë9öèùŒŸËÎÂbTUe\n†ÆFt:-ŠFƒÕjeÎá³ðû¤§§¡é\7ÿÈ9ètZR’“P雞žÊü#ç`·[‰ŠŽê÷=ÑëõœtÂ1ÔÖÕKNVF´G<‡ÏœAdd$Fƒž´ä$ C8M„ÉÄñ Ž"¤†HINDì6'w B|\,jçy'8â9ñøcˆ‹‰!&&­VKZj ¿¾ò26mí˜me·‘˜àÀð³nã¢;óż¹s˜7žÂâRœNV«…Ô”dR»µb¨€ÅbabÞx~|âñ˜Œrs²0š:¦¤&%&ð㎣Íí&o\ ŽøC²¾–”boôÕf¯é\t€¾s‰è\Ì€˜ãns=Þ{Ãî  ƒƒAü~ŸǃÛÝŽÛÝFSs37lä¸cµon} øü~P!"ÂÔïcÉ;nÀð£Õj1 ág¸Aü?ÐÐùlE£ÑH(Âëó¡ª*z½^O(Âãõ¢  ×ë·÷ûýø4 z®Ï±']ùñú|ƒA´-z}Ï´ªªv¾ßþŽoØ=ÎMUUÚÛ=¨¨ t:¡Î[¦CGËV« ?§Åëóîvµó.«²SÐju¨¨ø|¾ðö]éB¡þ@ üÐ;V‡N·û¹ƒyÐ(`0Ãiºni¯†Tô=zN!¿MÍ-|ùÕ·L™:…è¨(ÌæŽîB“É„Þ`×­®güt-Bˆ›9Òò;`àÜ@{çâï\@¨s “Y0£@§Õ¡Óv+ú~Ê@AÁ ×cÐë{¤UP:‚Š^Ï"Ñëv¥Ñ("Œ¦Ûi fSDuÛéÑëô»­ï+?&C¯V©=_7èôúÙ—‚‚9¢çñ5ІÈsu :­]¯õ]ûèk ¨>B·[:­F‹ÖÐ+àèãÜ´ sßÇêQ^ýl/:IÙ!ö‚Ì‚B!ĈåA¨‡hˆ%¹–…ƒ'- B!„q2 F±Oȵ,„Ø2U±oȵ,„Ø 2D±Èµ,„<"„Bˆ'ˆB!Fœ B!„q£þ0:é5B!=£< FíX„>¹–…{Aº`„B1âFµÄëõàiלP1æy½žÑ΂â2ªH{[Z%4pB!Ę×ÞÖ>ÚYB@F5É™0G|ühfA±ÔÖÕ±vÓ¶ÑΆâ1ªˆV«E«õ‰8Bˆ}@«ÕŽv„„*„Bˆ'ˆB!Fœ B!„q€!„bÄI"„Bˆ'ˆB!FÜ9ÖçóÑÚÚJKk+>ŸƒAÝf#:&­FC›ÛM}}ƒ¤Ä„ÑÎî> ))-%ÒlÆn·c2™µ×륩¹…¶¶6r²³†UU)*)Ád0âpÄ£ÛÇÓ¨›šhjn&Âd"1!fWŒhlj¢µµ•‡«ÕÚcÛ`0HeU5¡PG|<®¶6ü~?QQQ˜#"†7§ÓI]CQ6v»]¦ !Ä0PˆÏ磮¾žÒÒ2jjkpµµÑÞîE£ÑËÄ yŒËÉ¡¡¡‘•ù«ˆŽŽ:hŸÏÇÒåß“ž’Âĉ€8].¶lÝFIi)Y™=þ¡E0ä»ïWÃQóæa±ìÛ*TU]Ãú1 œzÊɺå×ÕÖÆù«(**âèG1iÂôú]·òw:]¬Z³U…ùGÎeõÚ5´:]Ì™}8iiÃÎ[Mm-߯ÌgÒ„<&æå±‚!„8T0]0¡PˆŠª*¾Xò%¯¼ñ&Ÿ-^BiYõlݶ%_}ÍW_C0¤¥¹™õ7²£`çhg{Ÿñûý¬Z½–‚Â"œ.× ·kkkcga!ù«W£ói¥ªªX½f-[·ïÀëó k}ñx<ì,,dñWßàëµÿ¦¦f}ô1,úˆuë7ÒÔÜÒãõ²Š ÖnØHiy9Á`ÕkÖ³â‡|÷IÞêY½f-啸üþ}²O!„8T0- N§‹¿÷_ªª«8ûôÓ˜?ÿÈp¸RQÕŠ¢ìó.1²Žx ¬^³§Ë…ÉdB§Õ qºœCm]•UU8âãÂÛ–”–b4HKIÂǯ¯þ%@‹Åº‡# !„ Ì믾þO»›Y‡Í`ΜÙX-–ÝÒôþ†ïõy©¬ª¢°¸˜` HZZ*‰ =Æ445QUYECS# àp™Á`:º0*ªª°˜#QÕuõ ¸\mØí6òÆÃh0 (Jx@€¢’jjjÑétÄÆÄ`6›ih¨güøñ˜ŒÆpºæ– ‹‹ñy}ÄÇÇ‘œ”Ôçyõ' áv»),)¡©©  Žøxrs²Ðjµ»å«º¶–Ò²2ÔŠÃOjJJ8?]ü~?MÍÍã÷ûILL )1Kdä ó5q11¤¦¤ …(,*ÆiÁb‰¤¥µ•êê’“™:y2.—‹ªêjfL›Þ¶¸¤“ÑHJJ ~¿ŸŠªj|>/™éé˜LFšš›Ù±s'ǧ®¾žšº:‚Á ޏ8Æåæö(/UUñx<ÑÔÔ„Õb¡¶¶®Ï<ûü~š()-! àˆï(³Î÷rÓ–-ü~I‰‰áí6nÚL $91‡c×3‘6mÞ‚?`\N‘‘æ}]ÄB1&0Èšuk‰Š²3eÒ$¢£¢úLÓýˆÏïgÓ–­ýFCk«“å?üÀÌ38òˆÙ˜ÍfêêëùbÉ—47· …p·»ñ´{9|æ æÌžÃÓédõêµTTVb2Ñëô´{<´¢8˜ IDAT{<¬Z½†Ÿžv*11Ñ(ŠBm]ËW¬`ëö˜Œ&TUÅï÷£h4ÄDE‘––†ÉhÄér±mû¾[±‚“‰`0H»ÇCJr2 æÏ#)aàq+ªªÒÐÐÈ;ÿy•`0ˆ«ÍM("';“Ó~r2KGÐ ¨®©åÝÿ¼N¯£½½U…Œô4N<þ8¢l64šÿßÞ}Ç·uöþÿœƒƒIÜ{S{yÊV,¯xÄ{ÄNìÆIc§iFórÒ&M“ÜŒÞ&½MÓþ2Ú4¹MgÚiÓ$ÍM³<â)kY¶¬aMJ¢¨ERÜ$H‚Øøý")Š¢DŠß·_ç%88xpç‹gÁ¤?`×îF^cn·‹X4ÆÆM›¨«­eå[Vdå‹].EE…ÑÔÔļ9 x½9ôööÒÒÚÊâE Y~Ùe<óÜs´µ%‰`·Û‰Æbii¡¾¶–ªŠ †C!vìÜÅàÐPj€r~>===<ÿ‹lxíõLKÙÐð0±H”K.ZÆ5+¯Âëõ‹Å8ÜÒÂK«^¡§·‡ÃN<§¥µõ¸îœîžvìÚÍkßÀãv‰„‰FcTUVpÝÕ+©¨¨ ¥µýû›Y0>åee$“I†††xiÕ+ôXù–+¹±äzlx}#§ƒóæžóó-"r¾Lû1 ‰‘O¢­mmäææRYQ>µÇ%Äcq,Ë¢ª²Šêª*:ÌÆ76qààA’É$‰x›ÍFA~>5ÕU”––2â™çžçð‘#$ Âá0­­­lݾh4õ鶪²’I~÷‡§ØßÜÌðð0CCCìÞ³—_~ËfQYQAyYáH˜m;vp¤¥•X4ÀƒY¿aG¶SZRLuU‰x‚]»Ù¸ió”ÏMˆ'PSUEeyÃÃÃüá™g9ÒÒ’£‘H¤ŠaT”•QQ^ÎÐЯ¾ö:olڜٯ©©‰ ¯¿NggåeeTWWFÙ±k[Þ|óÔ*î4†AžßO]m ûöï'L}Å{Oo/­mm\¼l æÏÅårÑÓÛKgW‰D‚ÎÎN†‡‡ÉËË¥¨°h4J{{;--­™cƒÃìkj¦qï>l6‹ŠòrŠ èéíåW¿ù-]]Ý$ ºº»Ùúæ›l|c>oÕ•U`˜&¡p8SÖX,ÆÞ½M¬]·ž`0Hyi)••„Ãa6o}“µë_%‘Hàq»8xèMÍÍÄãqâñ‡´pððaÞܾ$ ZÛÚhik#4ʴ‰ˆ\ˆ¦} H"‘ /`8ÆårMyæÝ²¸hÙRyÏ»3oäCCƒ45 qß>–-]Jyy=øÉdêÝ?0Àœº:¾öÍ£½£ƒèÈ@C›ÍFeE÷Ýs7õuµÄãqvìÜÅšµëØÛÔDUU%Á`Ý»‰Åâ<üž‡(,(À0 6oÝÊo~ÿT¦\±XŒ»w³»±‘»n¿+–_ŽÝn§¤¤˜Õk׳þÕ Ü}ûm'}}†aPR\Ä£þ ¦i‹Å…ØøÆf¾ñ­o³¿ù¥¥%™ò—••ðþGÞ‹ÇíÆ0 ^c¿úž}îy–_v)–ÍâÍ;8pà·ßzW,¿ Ó4),È畵ëxíõ7¸å¦›NµúN‹ÏçcnC=xæY‚Á`fúmWw7K-¤¸¨ˆÊòrºº»i>p‚Böì݇Ï륨¨ç¸n¥ÑW,¿œÛn¾‰Ò’zûú(.*âËÿüU:»º(++åÀÁCìØ¹‹¹ ¼ûOÄ›“C,§rÍZþë—ÿ9ÖÀÀ »9ÚÞÎ'>ö(ÕUUØl6¶ïØÉS|ŽV­æöÛneN}=–eÑÝÓÃàÐ.§‹]»)-.¦»»‡ŽŽNÉõûin>€Çí¡²¢\Ó|Eä‚6í[@’‰‘Hd¤;#F4›Òãl6N‡çÈÚš|^/@j‰a$’I"‘=½½´··§ºq’©)ŸÃ¡¦iâq¹3SXm6~¿Ÿ††z‡†G"ttvÑ×ßÏe—\„ÏëÅ4M ÃÀíöPXP)C 0@GG==} ¦Z!Ö¬[ÏþýÍôöõÒÝÝuJçÇ0 b±Ý==ii¥¿¿Ÿ‚¼<@&@™¦‰ÓáÄíreÊUW[ËÒŋٳwÑh”þ@ U®Þ~ë^ÝÀšuë9pð=½½ôôž™$Sá÷û˜3§¶¶£zzzéííÇ0lTWUa·Ûi¨¯Ã²l457EiÜ»—’’ŠF뉆ÇíÆf¦.î¹~ÿȱ,úúû ‡ÃttvÒÛÛÇÊ·¬ÀétbvË"Çã3F§µ­ÊËʨ«­Í†ùóç±xázzzhï褠°ÒÒR"á‡!žˆ³«±‘¹sX¶l Mû›I$457ãóæ¤ZÙDD.`Ó¾IJ,JŠ‹q:ôõ÷Ñ××G®ßZDz;ì©‹D2™™Rúû§ŸaÛö$â Š‹‹°,kJÓKMÓÌ\œHBpx˜áPŸÏ‡1ÉZáH˜H4B,£?`h8¤Zz*+*X¼`Á”_ÏÀà «×¬åÕ×_Çf³‘ŸŸO08L8&ÉäSn=n¹¹>Âá0¡PŒÔÔh,J_ ŸÁàP¦\uµµN¹\gÊåtRQVFAA­G¦ÆÜ 3îœÌ8ŸºÚZÞܶ‡Ù½gW]y…§XNÓ4±, Ë:Vg¡Pˆàp¿ß9j\ÑxƒƒƒDã1rÆ Ðµ[—ËI?•åeÔTW‡8xð UU•8xk®¾ ¿?—í;v°»±‘‹–.¡ùàA.¿ä**@DäÂ6íˆa8*ËËiimeϾ}ÔÖÔœö±Ò°p$Âö;ضcÕU•,Y´¯×K<ç©?þq cLаÛ,LÃdp(8ézn·—Ó…Çãaá‚ù”––dZV \®wŒ‡9pè¿úŸßróM7P_[ƒÏçãHK+Mû÷Ozá„Ô‚b±X »ÃÝnÇétàt:ñy½,Z¸€²’9†a¸]Ù[tË4MêëëÉÍÍ#/7¿ÏOkkÛvìäê«®"™HRŸß§©Ã"ra›ö]0º@¬¸â ¢Ñ¯oÜÄ®ÝÇív* mÅb1š›ÒÓÛGuu5Ë/¿Œ… æSYQý4ÖñçúñxÜìÙ»¡Á¡Lùâ±áQs<Š ð¸ÝôöõQSUÅœúzæÔ×ÓP_GEùäƒl“É$$!ŽÐÑÑɾýû™?w.—]r ‹.¤ª¢"hF]PÉ‘h”P(œ9GÝ=½´m§¶º§Ã×륰°§ÓÉ@`€ºÚºc媫;nEÙäÈçŠÝngÉ¢…tvv±s×nBá0sæ4dî÷¸Ý™1.¯¬]‡Ãa§  Ê+ÄNÆïóáv¹Ø¶cGf1´t‹ÙèÅÑ òq:´wtÒv´x<@Ww7]]Ýx½^Š‹ŠFBWâõzijnfÇ®ÝÔ×Õâ÷û)).¦¨°€Ö¶£lÜ´‰ü¼< Ƭð*"r!šö- i+®\Ρ#‡Ùµ»‘§ÿøƒƒø|^l6Ñh”D<õisª­#©‰‘H„––Vöîk"‘LpäH ápdÌ'â©(-)¦¢¼ŒÍ[¶²aãFêkk°Y{›š8ÚÞN®?H]Xëjk(/+cÍÚõ”•–RTTˆAê"çr¹'\>Þ0L|>/Àí©ñ†ÝnçÀÁC¸]. Ó qï^G €DEÚl6™.'-[Êó/½Ì˯¬fϾ}¸]NšÂ0 # Œ™¦‰ÃaÇép`šÇ.²¦aàt:±Û혦IYi)—^|onÛÎOÿëçÌYتµ­Þž^ò–ëX´`!CüÇýœ'ö3æ44``@2I]M ÷Ü}çq¯ß²l,Z0Ÿ-ongÓæ-¸Ýnj««¨®ªä÷O=Í–­obÐzô(¦‘;“)¿ÝN(âO<Éüùs‰E¢ôõõQVVÊ­·Üœi5¸hÉRƒüê7¿á‡O>É܆‰$¦i2·¡žÛo½»ÝNMm MûšXÿê,›ÅÂùóÎz±ÛíÌ›3€¼¼<*ËËqŒ«Ï²’bêjkØ´y K-Ä›sl€¨1ÎG&”˜¦‰ËåÌœ›´T—ËJ-ÞV_WÇË—óæöüä§ÿImM5Ãá0GÅnÙ3÷æäpɲe´·wðëßü–}Mû±[픕•òÎÛïÍt…™¦Iii e¥ìmÚÏÞ÷0>_ª¼ùÌŸ7—ç_z‰ÛÞö6 òÏê¹™ŽfL¨ª(çûîå†k¯áÀ¡Cmo'OàÏË¥º²’9 ©éŽ……\±|9~ÿØ~ôòòr.¹8†ÇãÁ²,jª«ø«G?ž½{é(,,àOzoîØÁ‚yóp8ø|>–.]F8<¯—PxMû`ŒŸÏËÕW­`Þ¼946î¡»·˲¨®¨`þ Ÿr:ÜuÇíTVV2<<ŒË餪ªŠÿó·_`Ó–- )**¤¨¨`p¿Ï‡ÇíÆaOM;­®©Æçórøð,›êê*êëÉËÍÍ\ ssýÜpýµ,^´€ÆÆ=ôôõáp8¨©®fÞÜ9™²Ü÷]4îÙG`pà´º«¦Â0 \.·ßr3±x|Ìó§±âŠåÄbqV\¹¿ïXý¸Ýn–-[J(4œ¹ äsÝ5+™ÛP?f¬M®ßÏ]wÞIUUv‡—ÓÉe—\BÕç+Ù¶cÁ¡ %%Åøü>BÃ! òó2ahNC=ï~ð\¹ür:Œe·¸åæ©­©É,P—VWSÃÝwÜIKk+e¥e™€\Z\ÌÍ7Þ€×›ÃEË–žö k‘™d¢­æÈfö‘Í=²y/°"84øñLŽÌ.I¯«ljÆbD#‘ÔÌ‚à0Áà½}}lß¶|€’’’S*pº/~x8D("™»ÝJ­âra‘H”¡àPjºì¨Á|¡Pˆp$‚iš™0ŽD‰Æ¢Øív¼99 âv¹p:$ †‚A’‰^¯7³‚f,#Àn·ãv»2·'  GÂX6‹Ý{÷²jõjJJJ¸ÿž»3«¸&“Ibñ8Cƒƒ„#QL#5Õãñœpý‡D"ÁÀà ñx§Ó‰Çí&ˆÅâ8©OüñD"õißé$92Í8a³l  *M­©2¾Ë"}~‡ˆD##­®ÔÔÕ‘rÅãq†‚A¢Ñ(n·;sÞÏ…¾¾>’€Ûå:n|Gz¹ôþ@€¼¼T(H¿žx<ÎÐPD2ÇãÁa·‰D Œ vf^O4£««‹¼¼¼‘–.sä<¤¾&‹´œYÄã l¶Ô9ý\éßoÃ42e_Ñh”áááH˜‚ül¶±ï PTX0c ëèèà¿ø%K—-%?/'ÇËåJ v¶,l6[ækÆþ‘™É“ãýk`0á‘-:²Å€ÄÈ–1£Z@àXÓºÝnÇÏÄ3RâãgC¸&¸ˆ9œãÞð ò5›¦9á'R˲Žk*O&“†AnnjÿX,Æp0HgW×]sõ˜²ÒkKä`Yù‰LT–T9&30ú úNö.éó›?Él’ñÁî\šìü¤ÖYqO¸8]j­–±et8M0M×nYcÆ—¤m·[c~NÄf³‘““sÜtÜãžgä÷–q¿·S}¼ˆÈ…dÆ鬷·»Éñxp8ôõ÷³·© ŸÏ—éÒ³ª«»‹ç_|™â¢B|>GÛۃ뮹zÂOÞ"""³•ÈY4Þ<¾øùÏžïbˆˆˆL{3b!2¹°(€ˆˆˆHÖ×.˜ááa†††ÎgDä,µJ¬ˆÈÉœ×FÇ|·†ˆÌ\Ñhô|ADfó@ü~?ùSXgAD¦?9""""Y§""""Y§""""Y§""""Y§""""Y§""""Y§""""Y§""""Y§""""Y§""""Y§""""Y§""""Y§""""Y§""""Y§""""Y§""""Y§""""Y§""""Y§""""Y§""""Y§""""Y§""""Y§""""Y§""""Y§""""Y§""""Y§""""Y§""""Y§""""Ygœªd2y¾‹ “0 ã”öW}Î<§ZÇQ‘#™Lèí¥·§“áàÐù.ŽLÀíÉ!¿ ~þI/RªÏ™éTêx2 "2#$“Iº:Ú ´¢nÞù.’L ÐßG{ëa"ÑE%å'¼@©>g®ñu|º@DdÚK&“ô÷ö040À¼EËÎwqdþÜ<ü¹yìݵ »ÝIn~Áq!Dõ9³¯ãÓ¥A¨"2í% z{º(­¨>ßE‘)*­¨¦·§‹D"qÜ}ªÏ CºŽO—Z@DdZK&“$“IBÁ!|þ\ Xœ!|þ\ìÛ©¿t+ˆêó‘®ãÓ¥™öt‘š¹&ª;Õ§€ˆˆˆˆœ """’u """’u„*"3ˆÆ\XTŸ³™ˆˆÌ»xaQ}În "2+½ðÒËüسoÁ¡ ÕÕUÜwÏ=Üï=Y+Ãç¿ø% øë¿üXÖžóBóù/~‰?>ÿ–eQ]UÅý÷ÞÃï¸Ó<óQáH„d"Ëå:íò©Ž'¦""³Îßù+lܼ™¿øàø«G%‹²»q>oÎù.šœ†wÞ÷výð‡…¬ý5¾þ/ß$ òþG>ãcÿè‰'9|ä_þâß…’Êh "2«<ûÜó¼¾yÿõ“““s,pÌŸ;÷<–J΄ÝnÇëõâõz¹ûöÛ ð£'ž<+DΙAÎ|ÐÀ÷~ø#>üçï''ÇsÂã% žøŸñ»§ž¦·¯—‹–-ã3ýqÊËÊxäâŽ[oá¹^bßþýÔÕÕòéO|œÅ‹òÙÿýEóÉO²yëV~ýÛßÑÑÑÁòË/ãóŸùùyyD£Q¾ýÝÇX½v]”–”ðçï{˜;n½%ó ñxœï|ÿ<ûÇç sÃõ׳qófþíëÿU••D£Qþý{óü‹/‡yëµ×òñ=ŠÇã>ãs}rgcÈØspÉÅÑ×ßO0Än·NzŽÖoØÀwÿû¤¨°›n|+ýð‡xâ?~Æòê²»ÿž{øô'?~Šçl¶×ñ‰i®ˆÌ¡PˆÃGްlÉâI÷ûÞ~Ì /¿Ä?ÿÃßóäÇa·óK]xÒ~ûÔÓ|ì£á—ÿù$Ë–,áÑO|’Þvã¬^·nÌw ¬^³–›nxë”ÊøÚoðùÏ|š_ÿügTVVðð>ÈÑö£üëWÿ‰'~ð=Ž´´òï=¤>ùWUUòÕü~þä¹ûŽÛùÒ—¿ÂÁC‡2ÇûÖwãÕ ¯ñõþGžøáã¦Áá#G2÷í_ÿƒ‡ŽðÄ÷¿ÇOô}Ž´¶òíï<6¥²NWÝÝ]âñ¸OzŽA>õÙ/p÷wð‡ÿ÷+¾ö•àÆë®àá÷<Äûy/o»é^]õ"ŸþäÇ3?gªã™1’É3Ûi%™L’›—Â}Âáÿñ³Ÿó¿þæo˜ÓÐ@Ey_üüçbÕšu©™Ixðþû¹hÉRŠ ‹øøG%?/—?>ÿ"+ß²‚P(ÌŽ»I&¡§§Ý{÷ríÊ•Ç=Wúƒñèÿ¿ã–[˜7w.ùyù¼ç]‘L&ùÓw=DyY9ÕUÕÜ}Çílys[æ1ï|û}4Ô§ÊùÈŸ¾‡ŠòòÌs‡BaþûW¿æ³ŸþóæÌ¥¬´ŒOŒ †L&appˆÿùÝïùÀŸ½¼¼<Š‹Šù‹þ9/­^}Æçz*3\ÎÊsŒ:‡±XœÝ{öòû>ï}è]S:GDc1®¾ê*|>/ õ ,Z¸ð„utªçl¶×ñdÔ#"³FqQ!---ä.\8á>-­mÄb1ΟŸ¹Íív³té<8ácLÓdÙÒ¥:|§Óɵ+¯bõÚµ,]²˜5ëÖ±âŠåcÆ›LU}]-¡phÌmÁ`0óÿ}}}<ûÜólݶ¾@?=½=„B¡‘×ÒJ<‘`á¼y™ýQÇ?xä‰D‚Ï|á #÷Äâ1‚Á¡S.ëùô³_þ7?ûåcåå<ôà¼ó¾·gîŸìÕ×Õqù¥—ò®‡áš«®âÞ»ïâŠË/?ásís6›ëXDDfÜÜ\ òóY¿á5Ÿ €D¢‰ñx|Ì4N‡eÇétžðØ6ÓÌLÕ¼ù¦yìû?ä#ú «Ö¬áæ)v¿ŒgLxÛ±[ƒÁaþìÃᦷ^ÏþìJKKù«¿ùtæþX5xÑéppíÕ+ùú7¿Í%_„÷­/RXXÀàà¿úõoèëëã™çžgß¾¦Ìý9wÞ~_ùÚ7رk½½}üð'Ofî·,‹?}÷»øöcßãµI$´wt°³±ñœ”÷|8Ù9êà÷O=MgW¡PˆM[¶âv»ñûý”””°ië›=ÚÎððpÖÏÙ…\Çê‚‘YŲ,þý_¿Á/~õkž{ñE¾óøãØ “ºú:ÞqïÝ|òãÉ·¿ûŸú܈Åb¼eù|ó_Å8öÑ“+/¿œo}ç»tuw³lébûÖ7±Ûí™ûoºá>õ¹Ïó¥/|–Úš>ú‘óØÄwœ+—/gÅËÇìó©ÿ%ÿò­oó‰O›ÍÆmo» Ó\ÿþ‡ß‹ËéäëßüGÛ;(ÈÏçáw?Äâ ÎY¹³édçhp`€V­â[ß}ŒàPÚšjþéÿ| çHWη¾u¯®ç]¼Ë.½„oüÓW²zÎ.ä:ž¨ûÉÙ,À>²¹G6àV‡¿1þÉd2³Åãqâñ8ÑXŒh$B("&¢·¯íÛ¶óàƒPRRrî^ˆdMGG¿øÅ/Yºl)ùyyx<9x1‘³ìð‘öîk⺫¯>ßEapp=ñSþ÷ßÿ%Åżãí÷pßÝwïbÉY4SëXDDäýøñïNzuU%ë_~!K¥™ÜÒ%‹ùñ÷¾s¾‹!çÐL­c‘¬S ˆˆÌÉ3ýò ™VTŸ³›Z@DDD$ë@DdFpyr ôŸïbÈ úqyN<Yõ9ó¬ŽOFDD¦=Ã0ÈÍͧ³½í|E¦¨³½ÜÜü ›S}^Òu|º@DdZK¯˜šãÏÅãõÒ¼w·>9Ocƒ~š÷îÆãõ’ãÏ=nÅ[ÕçÌ7¾ŽO—¡ŠÈ´gš&6›È`qIDAT ^!–ÍAgG‡4ü’u.nŸ›Í6áWÄ«>g¶ñu|º@DdÚ3 #óFçÍÍÅíõ’H$INó•gÓ42ßù“þÞŸãöS}ÎXÕñéR‘!}ÑJÿ«)œÓSº‹Å4ÍI¿lPõ9sMµŽOFDDf ]¬f†©^”TŸ3×™4™qÎÆ›ŸLªÏÙI³`DDD$ë@DDD$ë@DDD$ë@DDD$ë@DDD$ë@DDD$ë4 wŠD¢  208H4Åápà÷ùÈñx°Ûí§}ܾþ~¢Ñ(999xÜî³XâÉ%“IBá0ÝÝÝø¼>rsýY{n9= ³L 0À‘–VŽ´¡«»›P8ŒË墤¸ˆùsçQUYÀðð0ñx—Ë…Ã1µPÒ¸g/ÝÝ=Ì›ÛÀ¼¹sÏåËRÁ#ŽÐÓÛˡÇÙݸ‡K/¾ˆ‹/ZvΟ[DDÎŒÈ,³~ÃküöO0§¡'‡žž^š››¹ãÖ[xà÷aonßA À’E‹¨®ªœÒ±_{}#Ûwîäm7Ý•‰Di>p€?<ý,|ñE’É$yy¹ ""3€È,Çéíëã÷O=Í¢E ¸þš«)-)Á4Mâñ8ápŸ×‹Ëåb`p¦ýÍíh§¼¬tÊä÷½;o»•ü‚üsüj «»‡ç^xõ^£¸¸ˆî;¯¬Y{ΟWDDÎY"‹ÑÚv”ž¾>ÊJJ˜;gn—ë¸ý‚Á ¢qϺ{{yýMDÂÊÊʨª¬ ¿¿ŸŽÎnrr õu ‡B¼´ê÷5Q˜ŸOey9ýÖ®{•îž.Z¶ä¸×c3MrrrˆF£Y>›""r¦@f ›ÍFaA÷Þ}O=û,xæÙL¹öê•4ÔבŸŸONNõuµ4Ô×ãr»X~Ù¥\~é¥@j @(bé¢EüÉï ¢¼|òç5M®½z%ïþ“°¬Ô¯[``€£íìmj¢¦ºŠÎÎ.^xùîºý6n¾ñŠ‹  ©®\Åïžzꜞ9?@f™Ë/¹˜…óæ²w_ë7¼Æë›6ñòê5,]´{﹋«®¼ò¤Çp»\”••×-2Ëfa·Û3á`nömßÁàà ÃÃ!÷îÃï÷S_[CáÈVËf£´¤øŒÖ%‘éKd–±Ûíäææ²xÑ"*Ê˹þºkص»‘—_Y͆×^§¸°Ò“ Ã00Mó¸ñ#Såq»°Y6‰$Ñh”®®.r<œNç˜cš¦‰a§õ""2½)€ÌB†a“ã!'ÇCyyåeeìÛ×D€¶£í' gjt°0 ›e#“H$ÎéóŠˆÈô¡ï‚™%’É$±xœH$2æBoš&ùùäxs°,Û˜Û#‘HfÜǹâpØ)/+#ÐÑÕÅÐP0S^…‘ —Z@f‰x"Ao_íGÛq:x<l6“D"Aoo]ÝQ^VŠÍ´áó{ého狼»—Ó‰û|¿‹Ó墡¾‡ÃÎÎ]æPSSÍðð0Í1 Ÿõç‘óOd–‡Ãìܹ‹ï~ÿ‡$âq*++Èõû‰D"lÛ±“Úšjn¹éFæÏ›G4eé¢Eüæ·¿çÏ<ËÁÇY¼p!×_{õY/—ݲ(+)áÖ·ÝÌïþðÛ¶o§¡¾ŽP(ÄÖí;05DD䂤2K¸]©)µ÷¹ÏpäHKê‹è"œo½îÚÔšee†Ýn§¾®Ž~ä/8tø0†a—çÇ0 Š‹‹YyÕ[¨«­=î9.˜GIqåe˜¦™Ú÷-+¨©®³_UU%ñd‚â¢" 5Eøm7ÝHmM5‡!ŽãvsÉųê•Õ']`Ì4M ò¹þ𫩝;¾\""2ý(€ÌæÈÂ]s(-)a($‹c³Ùðzsðy½™©²†aàt:YºxÕÕU$âqrrrR¤¨«Þ²‚œ ºcæÏ›G4ÁëõbE…E\õ–+뺩ª¬L-Åîpdž/×ïgñ¢ETWU‰DI&ìÚÝH^^.çñKÆmùùù\³r%>oÎY:c""r.)€Ì2v»üü|òóOþ…q999™ÕFÓÜn÷ Ç‚äçåÛ×…Û]vÜ~>¯Ÿ×;æ¶d2IŽÇCŽÇ@?û›PXX@^^î¤å4 —ÓIeÅä‹¢‰ˆÈô¡"ç]2™äHK+áal¦ Ã0èèì`_S×^½’²’âó]D9Ë@伋Åã¼²f-͇ár8°Û-ZÛÚp»Ý\´té9_—DDD²ODÎ;»eqÿ½w'HMz1ˆ'â¸=îÓ^qUDD¦/™ÎÅ#""2}飥ˆˆˆdˆˆˆˆdˆˆˆˆdˆˆˆˆdˆˆˆˆdˆˆˆˆdˆˆˆˆdˆˆˆˆdˆˆˆˆdˆˆˆˆdˆˆˆˆdˆˆˆˆdˆˆˆˆdˆˆˆˆdˆˆˆˆdˆˆˆˆdˆˆˆˆdˆˆˆˆdˆˆˆˆdˆˆˆˆdˆˆˆˆdˆˆˆˆdˆˆˆˆdˆˆˆˆdˆˆˆˆdˆˆˆˆdˆˆˆˆdˆˆˆˆdˆˆˆˆdˆˆˆˆdˆˆˆˆdˆˆˆˆdˆˆˆˆdˆˆˆˆdˆˆˆˆdˆˆˆˆdˆˆˆˆdˆˆˆˆdˆˆˆˆdˆˆˆˆdˆˆˆˆdˆˆˆˆdˆˆˆˆdˆˆˆˆdˆˆˆˆdˆˆˆˆdˆˆˆˆdˆˆˆˆdˆˆˆˆdˆˆˆˆdˆˆˆˆdˆˆˆˆdˆˆˆˆdˆˆˆˆdˆˆˆˆdˆˆˆˆdˆˆˆˆdˆˆˆˆdˆˆˆˆdˆˆˆˆdˆˆˆˆdˆˆˆˆdˆˆˆˆdˆˆˆˆdˆˆˆˆdˆˆˆˆdˆˆˆˆd]Vˆac6¹°èo\D¦êœÑo>½é JäÂr¢¿é“½ˆÈìtN[@F¿!¥6MÓ0õF$r2 Ó01Ms¿‘´¬tÁŒn’5M3³‰È…eôß·ºbDd2ÖÙ>àøO<£ƒ‡ašØl©mË–­Øívb±‰D‚d"A< ™L’L&ÏvñDä Œ6› c$lX–E4Íüm#ï™ ÂØ±! %"rÖÈx†1¶ûÅf³áp8(,,¢«»‹p(D$%‹ÇˆÅb$“ÉT  ""ç×èéPaY–ÍÂn·ãpØqº\áp8°ÙlãZAÎó ‘i' dlø°l.—‹ššjÂá¡pˆh$B8&‹§ZC’ ‰ ð!2]¤CHz—eYX– §Ó‰ÝáÀåtát:p¹\X6ë¸""2ÚY †aŒ ™O?#Í´6›-ÕDkY8ŽL7K: Äb1âñ8‰D‚DB­"Óɱ2ê…eaÙí8ì{ªõòFºbFÈ BˆB‰ÈìvÎZ@Æ :M$Ƽa9FZ7ÒûÙl&1ËN,ž Éd’¤Z@D¦•L7ÌH H·hZ–m¤ÆÃéÄa·cYÇZ@ÌQÝ6 "’–½.› kÜØ JÒ­ñx"3DD¦3@Ž}¨°Ûí©–M»ûH±, ÓfSð‘ óÇÖ`äÍ*}›aÄm6Ë">2ø4Ó¢¨"ÓÊøn¶‘paŒj³™c‡ÍfÓš?"rBç´ Æ4Íã„eóaš&ñx+n#nÙÍ~ASpE¦«ô´Úñ-!éÖôϦi;D-!"2Ê9  6;F¬‘µ@RoRÇ&2-ZDdú¿ž‡9fùÈÚ Æ¸u@´þ‡ˆŒ“Õi¸†aŒ„ ƒ„af‚ˆÂ‡ÈÌ2Q<´ªˆL本„šéŸG¿ù¤ß”L3I"a4M’IÆv»(€ˆLo£Çƒ`dœ¨ÅcôØ‘cW ™íÎiL:|¤ƒÈøŽÑaet«‡Z@D¦·‰ÂD:€¤ž¨õCÁCDÒ²2 &mtIÿ¿ˆÈÌs¢2Qk‡ˆÈDÎi6N´Ïh "3ÃDÓ“…-+ƒPal°˜èMêdAED¦§“ýÍêoZD&’µ.˜“µtèMJä ¿e™Š¬ŽMoR"""³—9ÅýÆÌеˆˆˆŸ ¦4˜ód$9îçäO$"""³[‚c9!mÒ 2Y™(|ŒÞDDDD&Ë'Ì Sé‚I§šÄ¨-~ÚÅ‘ Iœ±aJ½%' ‰Qÿ¦GÝ0"""’2:Œ“f…‰fÁŒoB=ö#Ä€˜'Çû1À1²ÙGŽe#jL@Ó\DDDf¾Ñ½ é"#[ldBÆgˆãºbN6 w|øH?ñ€kdK‡‹c!Ä`ê3lDDDdúJ‡ŠL#ÇÂGhdK‰BÈ„N@F'–‰ROº•ƒQ÷ÛP ˆˆˆÈ…f|ˆs,€¤·(c[AF‡ ƒÈd- ' £ÃÅèÛG‘ ÁD½!QÆvÃL@&t¢1 ƨŸÓOh06X¤ïÝ*b›`?™¹F·d¤Fº+&:n?dô1Ƙ¬$=zÕ`lI(}ÛD]/ """މzEF ™(|¤÷Ðdc@Fw³ãî=et·Kz\ˆ Šˆˆ\8N´,Çè 2zêèàqÊc@ÒOdNp tÝê1¾õC­ """3ßDËrL´@é)-F6Y ë~}{úàã»\Ôõ"""ra¿äúøÐ1¾ëå„QOF‡ŠÑÝ+…ŽñDaDDDdæ›è»áFÿ<þËjO>`j!a|°0'¸]ÁCDDäÂ6Ѭ–Ñ!c¢á'4Õ°p¢qï!""2û$Çý{²ÛsºÁA-"""³Û¤ë|ˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆˆÈ…ïÿ³­×äHIEND®B`‚././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gtk4/images/drag_and_drop.png0000664000000000000000000002630015074674453022734 0ustar00rootroot‰PNG  IHDR­G¼M¿sBIT|dˆtEXtSoftwaregnome-screenshotï¿>&tEXtCreation Timedom 25 dic 2022 22:26:49Hÿh IDATxœíÝyœMõãÇñ÷½3ƒ1–ÌØ—±‡Šoýú¶)dK}‘Ð××7%iÑ·R_¾‘(!¢UÈÒW–ŠK}#b6ÆØiÆlwæÞß3sݹî,Ÿ13w–׳Çç1wÎ=çs>çœ;λóùÜs$€2ÈRˆõtÝÀœ#›×WåjNò·Ÿîï ð>‡<‡ÛO#ù9É»‡×ß]_[óÓ P ì?]ƒ„{¨È.ddË$@¸_q°ºüô|L EZÆO÷ a÷0ÝõgŽ|ó¸rOW¬n¯­nÓ¹€÷ùèr`ÈüiWú¹:»ÐkˆÈË÷« î!ÁG—„kðËCÝ pÙ”58d–4e ®W%ríÒÈí „{xp->º|%U“,©²$ÿ<Ô _ª¤DIq’NK:—1ÍGé!"Méçz×.Ìs¶!"¯'y÷ðà›±b_IU%5Z¿î¿Ãš5iÒMU‘ƒo`PlXäC>rä¿wÝÝm®¤IuùBAªÛvå"§½EYÇ8¸^mÈ,!’ZF=÷íš!„J&‹Tå»o× Qú ÊéòøÆÌoSæ(»á~¯÷ñ!Íš5ézµÞ“q.Ñåó{æ÷û=]!§oa¸wcdVî')ÐbµT–£ÀžÉŠ˜Åj©¬ô1~º<ö!Méç}‡²Þl*‹¼ÜÂýÞ¾’*:ì ßÕ är8I•µû"³äøUNOÂý™îc 2KÁ=x‹ë¹Ý} „ëÏ,§ýœQº_}píÊà9”®çvO¦ð(». Oëv»…5×(\Máià¤ÇqÙua¸ß}Ò/£”sò¥A9—âzWJy~r§$x…Rîéq/+<2R’d±XT½Z5Õ­][wßq«þzó_¼Üº‚³}ç.Mzgºzà>õÿÛ}W¼_\÷ƒk»Ü}¾`Ž*”/_Ä-Ê›~Cÿ!ÿ ´àƒÞn à5ù\€@Iòé$«Õ¢˜ØXýòÛoÚ÷ë¯ÚúÓN{f”·›V r{þnqÝ7¶o'?¿¬ÿY¬ÖbÿïLqoP˜®â :( Ò?§Oücˆ*V¬(I:|äˆÞ|{º~úy—6l٢ηþÕ› , Žl^gVüöCz»Fަ*•*eû~ñUÜÛ‡Ò¤ÏCƒuMËæzaôHU©’~#è?ãã5ùúõ·ƒZþéÇEÚº0Pæ4kÒDƒôÓ´™³µný&牳ÿÐáº¹Ó ®^]ë¾ß¢š5ƒõÂè‘úô«åÚûË/:{V­¬›;uÔÀÿ¦r~éÏKLJÒG ëç°½²Z¬ºëŽ[µòÛµê}O7 xðþ,ëþóÏ?s­/³þ*hûŽ]²;ìêÖù=Ô÷r]‰‰‰š»p‰vïÙ+»CjP¯N¡î‡·&¼(»Ý®¥+Vi˶uúìYÕ«[Wýí>uhw³ÎþC‡«ë]w*..N»vïU@¥õéyºv¾Ã¸}’ôŸwgjÛO;4x`?Ý׳»bOÒ¨gÇ«jÕ*zãåqZ¾ê¿¹îË›:Þ  å+è§ŸwËjµª{—ÎêxC{}ôñ':t$\5ªWÓ?}D­[¶È÷6$%'ë“ϾÒÎ]aº”˜ V-Zhتœ¯í<©_¯®<¤—'NÒë/Ž•ÅbÑ„‰“¥zuÌÿ ¸Zùÿ:¦ƒB)%“ÛôNÚI’¢cb²Ì»é‡íúrùJTTÃúõUί¼vîSÍÝÔñFÙÓìZ±ê[}µl¥s¹©3fiý÷[T-0P-š6Ѳ•k”””ìq½y©O’6nÞª]aûT¿nÅÅÅëó¯Wh÷žýÎy¦¼7K6mQP` Zµh®ßñ¸¾‚ÚrH.øD‹¿X*µ»îZ Ðë“§è·‡²,»bÕ·:|$\×¶i¥³gÏ郹 ´ãç°Û5söÓYÖ|·ArHÃ?¬Êúbé ?Qsæ/’-5U#ÿ9LU+WÍÓ¾ü~Ë6íÙÿ«êÕ­£ó.hÑg_êé±/)ÅfSõ @EEÓÛᆵ”[Þ·ÁmþgÚ{ZóÝzµhÞTÛ·Sؾýzó?ÓdO³{ÿo€RjÊ«ãžUíZ!ŠŒ:¦—ߘ¤—ߘ¤ðÈ(…Ô¨¡WÆÉÝùÄ”Iþþþò÷÷Wbb’ÒÒÒäãã#I²Z­zó•Õ¼icç¼½7ÍùúDì)=>æyíÞ·OúÞ¯˜ØXý¶GÁ5ªëí7^•Ö¬Û ç/ô¸Þ ÊçX_¦€€ŠzÊ¿åë뫯W¬ÒÂϿԯ¿P‡ë¯SLl¬v…íͲε7郹ó m?œ9{Nßmø^õëÕÕ”‰ÿ’Ö}¿YïÏ™§e«Ö¨UËæÎ:ƒ«jÚ[¯ËÇÇG[Ú¡·§ÏÔ·ëÖ«Ó í³mÇO»vgùÝêã«îwwVÕªU4tÐMŸ5G¯¾5Y‘ÑÇÔ£ëݺ®u+I9×}9sÊ¿eµZµä«¯õÅ×+ÔùÖ¿êñ •$|îEÑñ˜ mØÀx£¢´{ï~uh×Vcž!IJNIÑö?+&6Ö+ÿgˆÒ©zµjzã¥ôÒo)2ú˜$)¸Fu½öÒX…Ô¨Qäí¹ŠA”W[€"æÈø/SJJŠ’’’T«f°¬>Vç{þþþjÖ44˼Öêµëuø£º÷§‡âþŒ—CE‹‘$]צ•³žÀªU<®3/õe²Z}äãë#‡jÖ¼‰$éâŸqrÈ¡¨cǯXgåJY¶´ ÷CDt´ìv»Ú]w­s¾[nê¤÷çÌSôñãYêôóõsÎÓ±C;Y,?›c»~øž*»ÈœÿŽ[ÿO[¶ÿ¨½ûUíZ55¨_ç{yÝ—«E9Ô¼Iz ²øXœó4kÒDÑÇcôg|œsZ^·Á!‡ŽOÿ ìÞ³O} Îò~\||ŽÛ ˜òññU9¿rÎßý|ýäççç•ÏW P&íÿßor8jX¿AŽóÅÄÆjÂÄÉ Ö“ÃU½zu5|Ôçû¶ÔTI’… yZonõyâ듵§1-Ín´Îœäu?dvɤÙӜӒ“Sd±XrüªeRrúr®ÿàåGõ ÀŒWY¬é÷·ÉϾ´Z¯ìµõñɹ'7·m¨”|:´k«¡÷Ïòž7þ¯¥×ù õÊÄI:v<ÆyeëXLŒ&Lœ¬×^« ÀªEÚÆ@PJwÉä2íĉSš·ðSY­V=xÿ½9Îûûï(ÅfS‡ëÛªM«kT¥R%92ŸBëêÔ®%IÚ½g¿l}艉‰ëÊK}ÙµÃuZZ5¯\gBR¶ë,ˆýP¿nmIÒ®°}αa{÷Éáp¨QƒúY–MLLTÂ¥É!íÛÿ¿Œ€R7Ïír/{öý¢ ›·ªZµ ˆ=¥/–®Èÿ¾TÓL¶A’Ý‘>¾¡AÝ:²Z­:tèU©TYukÕv?_?ïÿ PJMy}òTgxxí¥±zí¥±ªW§ŽŽÅÄèõISò_w>qeÂì‹äãã£S§Ïèð‘£JMMÕàýÚ ~ŽËÕª™~²^÷ýfIÒGÕšqÕA’BÔWËæÍuðÐ!=ûÒ¿Ô¨a}íÜ–ïúò¢Qƒúº¦E3øýðåuîÊ~®ò»Ô«§v×]«=ûѳ/¾¢Æ iÇî0ùùù©ï}½³Ìwé’Æ¼ôªZ4i¢{öÊb±¨OÏî9ÖÿþœùWÜbÔ?‡Éf³éý9óT¥Jýçµ záÕ7´lÕýßM d_f'·m¨Z¹ŠNž>­%_.Õ}½z¨ëwèÛõ4nºý–›uæì9]JLÔ³#GH{I ˆThÃzyìUM¿ÚðÚKcõú¤) Œ*òö\ÅC±ŠA£Pr-é¶lûQ›·n×Å‹uc»ëõöÄWÕûž.çuvM‹¦ê{_oùøøhãæ\½šË@ºôyžúquìÐN§ÏžÕ‘£úË <Ö•×ú®\öʺžêIuº¡½Îœ;§ðˆ=9|¨ªy\gAìÉ¡çFP—η+1)Y»÷íS‹fM5éÕ3®ˆ\^¶r@€j…kÇî0Õ ®¡Ç<¥fMBsl׎]»µõÇYJš=Mó>Y¢³çÎkpÿ¾ªTUd€ìv»fΙ§Í_žÌyžÜ¶að€~ ªZUÿݰI‘Q6x€õ{@V«¾^¹Z‡Žü!ÿ ååpسÙn ż,[<_Sßü—‚ªVqN ªZESßü—–-žuç§§l¹>u3óþ¥¢¤J’:ýñûÿ¦æ{­@)¶vý÷š=¡{t°ºt¾ÝÛÍ)Rþþ˜ªTª¬YïþÇÛMÉ·Ò° €‰¦-Z?#i‡¤xI ’3Š-£¤êò31œx,7p•ÒÒÒ²ü¾s÷IRƒõ¼Ñ(ù‘ÿ«@©²þû-Z¿i‹š7m¬¨èýïàAµmÓZ-›6-»'¥a»KÃ6…ˆgaW©JåJ²ÙRµaó ¬RUݻܥÞ¯²ý7R¶½4lPxò?âௌ „kÚ²M¾Æ@ð8o`Œ1Àc €1¾Æ Œ €1QcW1ˆ’@YE0–ï+ǣ ² Éw€èô×ÎÙP‚Ð…Œ €±«¸%`îhx¸V¬Z­»Â{ò¤$©VÍšêxC{ÝÛ³‡‡†z¹…¥—ÍfÓ‡ÍךïÖéìÙ³W¼_£FuuïÚUÿ:X~~~^h!€’„"a³Ù4í½™ZöÍJÙíYè¦ðˆ…GDè˯—ëo}zkÔã#8‚9óhѧŸeûþ™3gµpñY$>¬è D*µ"))I‰‰‰räã~þüå_Ñ¿ZU6Ùl6~~œv…íQùråtß½½Ô¥ó mÔHRz€X»~ƒ–³J_~½\Qš:ù-BD[óÝw’¤93gèÚÖ­¯xÿ¯¿jø£´zíZ€\•Ú‘˜˜¨ÀªUe±š óp8ºpá¢M{o¦v…íQ­š55uÒ›ÎnФ¤$IR«k®Q«k®Q¯îÝ5fÜxý¦éÌÒ˜Q#½ÙìRçÌ™ôn OáA’®kÓFm¯k#‹ÅR”ÍPB•ÚA”)))Ù†‡„„K:pðJNN¾â=‹Åâq:òçhx¸–}³Rå˕˒““õÀÀAê;ðçþnÚ¤±¦üûM•+WNK—­PxD„[^6Íž1]³¦¿ëíf(Jí›Í–í{‘‘ኋ‹Wtt¤š6mn´,̬XµZv»]÷ÝÛ+O$›6i¬>½{ꋯ¾Ö7«×è©'/‚V–] ¬_¥ö „-ÕæñyΟW\Ü%…††êüùóŠó¼, ÄΟwK’ºÞ•õÆcåË—×Ò%Ÿè«%‹T¾|ù,ïuíœ>eQx2Vz Òå•sç\Ä-PÜ•Ú+i©69$¹öæ:E‹’ÕjQppMEFF***J­Zµ¾bYŒS§NI’6h”ezß+úXŒ$é§Í³¼×(4}Þ“±±…ݼ2•ò«ô^ðÐ qæÌi%&&f™§óçÏåº, Ö—‹?ÉþÍÌ+G æ+P5jT—” 2åe`¥ë|©Ì»Ý®ãÇ9_ÿñÇ!çýŽEGgùº'¢à„„„H’""óþðµððIRÍš5 £IeV÷®]%IߥŽååÖ(éÊL€8y2V)))Îßk×®ã|Ý aC%$\Ò¥Kñ:îü7:Bþuêxƒ$iíú y^fí† Y–EÁøÇÐÁzdàÕ¨Q¯j¸je&@ÄÅe,ùÛoÿs¾öññQ\ÜŸŠWDäQ5nÒ´HÚXÜÛ³‡¬V«–³J9êœÞwà ¯9¢+WËjµªwîEÚÖÒÎÏÏO¦UK¿ä«š®Z©Dé š4iªÔlº&RRRdµX¡fÍ[ªj•ªEÑÄ2!´Q#ý­Oo}ùõr7^Sþý¦š6i¬//ºbÞÃGŽhÌØñJIIQ¿îWhÆ^h1 /Jm€°ÛÓd³ÙT®\9IéW|||<Χ£áájÙ²•«e3Ë„QPDD”~ Ó£=®>½{ªËwªqhcIÒÑð£Z»aƒV¬\­””uìÐA#G<æåV— 5jT×™3gµÿ×_&]íÿ%}ÀepEÝ4Åœ§ŽPkFñ•ä—Qü3JEI•$uJ¸?µ¨™‘‘Šˆ8ª´´´\çõññQÛ¶íHx(,6›MÓ?˜¥¥ËVd;ÆÄÇÇGÜw¯FŽxL¾¾¥6Û+3?œ«…‹—ä:߇ê±ü½Z ¨U ¨ôŒ¤’â%%HJÌ(¶Œ’*ÉžQœJm€@ñ¡oV¯ÑŽŸw+öä IR­šµÕ©ã êÝ£;ÝEÌf³iÎüµfíZ_Õ ®QC=ºuÕ߇<Â(RŠŒå7@”Úoa€ÂC€ÆÀ#@c`ŒŒ €10Vâ8ðòk¯«zµjzúÉ'$IÉ))rØíªP¡B‘¶có[õÞ¬Ùê÷Àzà¾{‹tÝÞæíc`·ÛõÅÒeZ»~ƒ"£"T½Z5=pßýê÷ÀýE²þâÄÛÇâRB‚¾Z¶\7mÖ±ècòÐ-7ߤ‘ W@@@‘´€w”¸áîãE‹}ü˜^åå"YßÁßiúÌs"6Û‡B•5E} Öoܤ]a{ôäcÃU§v-íØù³&¿ó®jT¯¦ÎwÜ^$m(®ŠúX$%%éxÌ =õÄãjP¯žŽÇœÐÛÓÞÕä©Óô¯—_,’6ðŽ ŠÚÊ5ßêŽÛnSŸ^=4fìxo7§LºëÎÛÕå®;¿÷éÝKaûöé‡m?–ùQÔªW«¦ñÏqþ^£Fu=7ú)~~œ[ (”è±èÓÏ4Ñ'’¤›¶¨O¯žznôS²Ùlš5ç#mØ´YIÉɺí–[ôÔ«bÅô˺C‡Ð_o¹Y?lÝ®ÈèH…6 Õó£ŸÖž}ûµbå*:uJ:´×øçÆ\ñˆïçF?UäÛYœyãX­WÝ ÔÙsç ƒ‹1o O““U·nÝBÝVÞW¢Qz¨¿†zXwÝy»¶m\ç<¹O™þž"£iþì´pîlÅÄÄèýÙ³³,»kw˜Æ??F_-Y¬ºujkÈðÇtòÔIM™ô¦æÏ™­cÇc4sÎG^ت’¥¸ƒý¿üO­Z¶(èÍ+Q¼y,ìv»âããµcçÏš6}†ôï[˜›  (Ñ“K úfÕj òˆ‚‚¬áÆjóÖmYæëÖån5kÚTÕ‚‚4°_?9 ì×Ouj×VƒúõÔëžnÚ¿ÿ/mEÉVÔÇ`ËÖmŠŠŽÖ½={Ö&•XEu,æ-\¤»zôÖSÏUHp°Z·¼¦°7 €—•è. O¢¢£e·Û5î• ²È"IJMKUBB|¶Ë4jÔP’””œìœÚP ‰‰…ÛØRª(Á™3g5iÊ;=êIFý{PTÇbØÁzô‘A:«Ï¾Zª!Ækñ‚yªU«fm €â¦ÔˆJ•%IófÍTµ  <-cñ8ÍÓTäEQƒä”}ùÝØ¡ƒzÞÓÍ´™eBQþ=X­VÕ­SGcFÔÞ}¿è»õÈ€‡Lš  )]©©©Î×µk…(Àß_[·m÷b‹Êž¢>iiizqÂkò¯PA㟓ûeHqø{(WÎOþå‹öÞ,ŠV‰!!ÁÚ³ïÅÆžTbb¢|}}5p@½ÿá\íܽ[v»]'OÒß÷vSK­¢>v»]¯N|S1'Nè_/WZZš•˜˜(‡ÃQ ë(©ŠúXìÞ³WÓgÎRØÞ}Š=©Ý{öêíiïêØ±ãºíÖ[ dЧß…qO—»µý§0t¨Ú]ßNSÞš¨¡ƒV…òåõλ3{ê´ªiÐCýtM‹²=J¿°õ1غýG­Ûð½$©ÇýYGû/ÿüÓ2Ýï^ÔÇ"$8D6[Š&OyG±§N) @×µi¥Y3¦)$8¸¶@qå©cÓšQ|%ùeÿŒRQR%I.ÅO-ªF€ÂQ1 Ò3’vHŠ—” )1£Ø2Jª${Fq*ñ] è €10F€ÆÀË÷} ¢Âÿ(Èv€$ߢAhÓ‚l(AèÂÆÀ#@c`ŒŒ €10F€ÆÀ#@c`ŒŒ €10F€ÆÀ#@c`ŒŒ €10F€ÆÀ#@c`ŒŒ €10F€ÆÀ#@c`ŒŒ €10F€ÆÀ#@c`ŒŒ €10F€ÆÀ#@c`ŒŒ €10F€ÆÀ#@c`ŒŒ €10F€ÆÀ#@c`ŒŒ €10F€ÆÀ#@c`ŒŒ €10F€ÆÀ#@c`ŒŒ €10F€ÆÀ#@c`ŒŒ €10F€ÆÀ#@c`ŒŒ €10F€ÆÀ#@c`ŒŒ €10F€ÆÀ#@c`ŒŒ €10F€ÆÀ#@c`ŒŒ €10F€ÆÀ#@c`ŒŒ €10F€ÆÀ#@c`ŒŒ €10F€ÆÀ#@c`ŒŒ €1 Õ˯½®¿Üv§þrÛºùŽ»ÔwàÃ÷òýq䨷›V¬<4øQ-\¼Äù{rJŠ’’’¼Ø¢‚oƒ7¶Én·kÊôêÚ«ú=Ò3¦©~½zÚ¸i“üþ{‘¶(|½Ý”~åüü I TÛëÚ¨VÍM™>C7uºQ•*Uòr ½ï±üÝÛM(•¢¢Ž©U‹ª^½ºsÚ§ x¯A@)B€€W<ô`_}úÅWÚ²m»ºwí¢¡ÃGèÁîךo×ê·ô毩}Ûë4óÃ9Úº}»N>«š!ÁúÈ ÝÓång=iiišýÑ|}·~ƒuû­·*lï½3y’êÕ­“e?íÜ©Ùsç+<2R5ªWӷ߮LJ“”~©{ѧŸiõ·ÿÕ¹ótݵmôÜÓ£T»V-Ié—£ÿzËÍúaëvEFG*´Q¨žý´öìÛ¯+WéÔ©SêС½Æ?7F’$›Í¦Ys>Ò†M›•”œ¬Ûn¹EO=ñ¸*V¬pÅþ:|„î»·—z÷è®EŸ~¦ù‹>‘$mÜ´E}zõÔs£ŸÊµ¾ü´1;ùiÃÜkÓ–ôñœÙòññQBB’ú?2XÇ Õùó<Ö—“¼÷ÏL§:8—ÿ÷ÛSµbÕjIÒ·ëÖ©q£FZ4oކ¡îï£ݺz\onû9§Ï‘»°°½Z¾rµÂ#"T¯N=ûôSj{]›<­'»í3ù\…‰. xEùråÔ´q¨¢£9§M>C]»Þ¥ÙïÏPÛ6­åçç§zuëjÒ¯kÉ‚Ôãžnzý­IŠŒŽv.óþì9úiçÏúÏ[ohÁœY²X-Š>vüŠõÅÅÅk싯¨W÷{´ò«/4yâëºãÖ[œïÏ]°P7mÖ[¯ýKÏ™¥r~~zâé1²ÙlÎyvíÓøçÇè«%‹U·Nm þ˜Nž:©)“ÞÔü9³uìxŒfÎùÈ9ÿ”éï)2ú˜æÏþ@ çÎVLLŒÞŸ=¢ö$0 IDAT;×}3è¡þ:èaÝuçíÚ¶qóD›—úLÛXm÷ªqh¨êÖ©£Á¨NíZúíÀAIRrr²–.[®ž{FÍš4QíZµ4zä×uúÌiÙRSuóMT¹r%5 Õ5-[J’RRR´äó/4nÌh5iœ¾® ãÇéÒ¥KúaÛÎ:ºu¹[Íš6Uµ  ì×O‡CûõSÚµÕ ~=õº§›öïÿE’t)!A߬Z­aCQPP B‚ƒ5|ØPmÞº-_û*¯õ™´± Ûàçç§±cÆhîüÚþãOZ³vÆ?÷l¾Ö•×câé3s5rÛÆœ>Gžôêq®iÑBAA<ð!=wNÇŽÏóñtß¾‚þ\Wƒ. xÍé³gtK󛜿—/_îŠy.\¸ ïÖoÔ¾_ÕÅ‹uîü9%gŒä9qBiv»Z4kæœß’ͺ5l¨×_¯C†êÿnºI½{öÐíÛK’ŽŸˆUjjj–AŒþþþjݺ•"¢"=×ר¡$))9Ù9-4´¡%IQÑѲÛí÷ÊY2Z•š–ª„„øÜv‹Gù©/·6F®o{­îî|§žÿ’^?V5jTÏ®ºåõ˜xúÌ\ܶ1§ÏQnjת%%$$æùxºo_A®€«A€€W$§¤è£ázdà€lçIHHÒßG<©;o»UÆ<¢š55ú¹±Î÷SSSe·Ûe·Ûeµæ|1ÍjµjÆ;o+lï>­þö¿÷â+êо&O|]¶”dÙív¥¥¥e©§œŸŸÊ—/ï±>OAÅâ2µR@eIÒ¼Y3U-((ǶåE~êË­…Õ†ºuëÈn·«|¹ü_ÈÏ1)¹mcNŸ£¼°XyZO~Û%º0àŸù•êÖ©£Ž.ƒÞÜ<ô».\¼¨'®ÐFàï/‹Ëù¯Nݺ’¤½—äÛ_ßV/¿0VsfÎЖ­ÛtúÌÕ­W/½ž_.×c·Ûuð÷Cjj¸eéj× Q€¿¿¶nÛž¯å¥ô€TõE"¢¢´hñ§õøcz{Ú»ŠÏúÆ®õå¤0ŽI^äu?{úÆz j9 0 Pèl¶T%&&êÒ¥KúíÀMñž>_ºL/<;ZKöÿG\½z5]ºtI_/ÿF.\ÐÚõôÇá#Î÷üýÕ£[WMš2U¿8>Òá'ëú3.N«¾ý¯NŸ9£¤¤$…íÝ/U©REþþêÕ½»&OyGÔ¹óçõÎŒ÷¨Ž7Þ¯möõõÕÀýõþ‡sµs÷nÙívœ· @Ú`·ÛõÆ¿'ëáý5 ßƒº¦eKMŸ9+ÛúrZa“ìT­ZU'NÄÊápäº9}ŽLä÷xæe¹q/OТO?3߀!º0Pè–._¡¥ËWÈÏÏO6TÛk[kÉ‚T5—tÖ¯¯'®ç/Ðsçªã Ô±c֓ǘ§FjÚ{3õ̸åã㣮wu–$Y­YƒI\\œ6nÞ¢÷g¨„K jP¿¾Þzm‚Ê—Kïc~æ©'õþìõüK¯(55U:Ü ioOÊ1àäfè ‡U¡|y½óî Åž:­jAAôP?]Ó¢E®ËÞÓånmÿi‡ ªv×·Ó”·&^U}Ùù3.NÕ«y¾nچş¡„„D x°¯$éÙ§GjÀ¡êrWgÝоÇúrZaOzðMšòŽŽFDhү帹}ŽLä÷xæ´œÝnW̉X…„çwwyæé/ÑšQ|%ùeÿŒRQR%I.ÅO-ªFyuöÜ9õ¼¿¯6}÷m¾þQ/kºô¼W_›ç€¥mý¤Š•ž‘´CR¼¤I‰Å–QR%Ù3Š](U>¬zukò æÄ ÙRSÕ¶M›2¹~W‡. ”hQQŠŠŠV‡v×ë̹sš9{®öïïíf•ýý5åßoªœ—–·×àê P¢ÅÇÅkþ¢Åzåõ‰ ®¡ûï½W}zõôv³J„ÀÀ@µ¿>ç[Z—æõ¸:”hmZ·ÒüÙ3½Ý (sŒ €10F€ÆÀ#@c`ŒŒ €10F€ÆÀ#@c`ŒŒ €10F€ÆÀ#@c`ŒŒ €10F€ÆÀ#@c`ŒŒ €10F€ÆÀ#@c`ŒŒ €10F€ÆÀ#@c`ŒŒ €10F€ÆÀ#@c`ŒŒ €10F€ÆÀ#@c`ŒŒ €10F€ÆÀ#@c`ŒŒ €10F€ÆÀ#@c`ŒŒ €10F€ÆÀ#@c`ŒŒ €10F€ÆÀ#@c`ŒŒ €10F€ÆÀ#@c`ŒŒ €10F€ÆÀ#@c`ŒŒ €10F€ÆÀ#@c`ŒŒ €10F€ÆÀ#@c`ŒŒ €10F€ÆÀ#@c`ŒŒ €10F€ÆÀËk€p¸ýn/膯p?§»Ÿó=Ê-@8Ü^;<¬”lv]>ÏgÊ1Hä <…×J¾œÎñÙžïóÒ…‘™Jì.%-ßÍÅIš²žãóÔÛ[€°»ü̬0MtcPZ¸žÛ]ÃCŽçz_ÓÜ/a¸Ž}H“”*)µb@¥‘’Êe¿Œº|”J¬’,ùßP@\{2Ïã6I)%5£¸†÷ pEW†§á¾R×ð¹âÝ’*d”Ìá«Ë!Â"¾" @q œt9<$e”Ìá)Dx”]€pMžRKæU¹¼ï#®@PܸŸËÓt9@d›²^…p ƒDNW ² ®áÀuºk€°ˆ@qà©7Á¦¬Ý9²aqy¹B‹²ƒÌ÷\¯Jøx˜xë•„Ì€Ù•as+îc!\ëÈ"§+™£/-Ê"2+Êœæ©ë‚ð@ñá©WÁuL„§ð9¯G9pí¦°¸½ç:õÛ"s\((>²»-ƒkpDéŒÇ@d®Èê¡¢ÌázÕÁýêW!ð>O·eðtƒH£›IåtBºÜ}á:=³r÷. º.(ÞÜoYíÜ».²H™Û ß5¸vOx î‚0€÷yz¶•ëk÷‡e椼ä݃ÕÃt‚Å›§oU¸†Oò•ד}vãï@Éãpû™Ûô+ä÷ÄÏJ¶<=¶ 4ûŒ½V9rÈ×IEND®B`‚././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gtk4/images/extended_example.png0000664000000000000000000001246115074674453023467 0ustar00rootroot‰PNG  IHDRàdŸ &tEXtCreation Timejue 08 dic 2022 22:05:23\¡õ ‘IDATxœíy|TÕ݇Ÿ™ÉdO&!@ÂBÂ’«ÔµÖJ‘M‘"U¡**Ö¥Õ¾no©U,¸Ö÷EË&Yñ-¥ YT [öldß™„L ™™÷›™ÌLf2“ $!9Ÿó¹÷žý^òß9çžs@ @ n8²›$O » ¿ž™]±ØÊCQГ°%¼ ÒY‘X¦“9&ÜlX Lï`˜C´WÖ„&kãÜÙr‚î€5±éÛ8·–®MÚ# KaÉLœÜâÚ–‚› K±™:ŵe|»8*k¢3Ïš"ô¬‰OgÃYŠÓ4½M\¨„-‹§09*€>@_ÀpkÎ[Pp3c*¤&à* Êj@Ûìt&GÓ´2ìˆÐž-Åg°pѹÞ@ø®±ó&Mœ0þè…à=z½N_}:þÜöyóçï2+Hâ”Ñ"BƒíŠÐžP,›œ¦ÂS}&Mš4ù«Ømkd2TNߘ@p“¡‡šYsæ>›p¨‘„h°ŠÖš¤­hK€¦ÖÏ`ù\š+à;qâÄÛöìÜö¹^ïPSV èQÈ5Ý?çÁE‰‰‰'€Zà’›0ï‚ Ú 5ËçŠÔÇ“{1#„åôfdÕ¡Ã"‰H}Dƒ­YÂVÈmåjqn¡¡éÙoÛÖ/æ"Ä'èõèý·|±é¤H%’F˜¿ÆÎÞ42Ó¦§Éòy#r.fì‡ë/Üäèuºª¡#Ò ’%4ô -eÌh«ïfmäÓ D™Lïw}§¥ 7'2¹ÜÉ)1Œ‘cg$ÔÑ÷€–ôD'^5zà‰yÔ0!¥M±€–t\…ñÌp¥E¦4¸v Â°Õ U\—* =SmXNÉ´‰5 hm9‘¥å×y]¢@p³c:=Ó–øZYBG¦¢Y›x­úÌ0Ÿµ Vië= µw¦™÷ ö:Lìî84 fþ•ÕÕÄîŽã‡'ʧº¦†ØÝqÿ)ÞèwìøIbwÇ¡®«kw½NžŽ'vw‰É©fþYÙ9ìýö€Y9š†bwÇqà»Ãí.Ë”´Ì,bwÇ‘•k3Î¥Â"bwÇ‘”šÖ¡²n2,õaM?­°×4$6ÍDȬ-Žê‰î›ƒß±}WW43ÿŠÊ*¶ïŠãû§ʧ²ª†í»â8~ê'£ßѳ}WêÚÚv׫¢²ší»âø×þƒfþ_ïû† _laÍú hu:£rZ:ÛwÅq17¿CÏ#-=“í»âÈÊɱçRaÛwÅ‘˜’Úåÿåpr-¬#ƒ0–5Ÿwõ-wòãµê×Þç`ß™<$36 €´Œ £Ÿ^¯#!9€ººz²²sŒaÉiéÄDGÝ çq=žÏws,ä·ßA­¾lôS×Õ²tùJæ,XØÁgbó‹6qvu¯i‚¶—ŠÊ*’R¸¢©'røp†……¶;â’2RÒÒhh¸Êðˆ0"† k'$8˜~}(¯¨¤¤¬Œ þýÉ¿TÈåËj† H^~ç@Jj:r¹œèÈQÆËWȹ IÌ`6×®]#+;‡ˆaCñòô½d9ÿúÑÿPsYmÌodD8o½ñ*îîn¤§g»+ŽÔ´ .$%0tÐ@«uþñä)>þl=6ï«»ðÖëÿÅÒwÞ%/¿€?¿³ ™LFnþ%ú÷íË›¯ÿñzÔ·]Bˈä­¿¾×fx]]=ÿ»~#^žž|°òm oÿõ=¶}µ‡_Þs·Ce³aóVúðÒsKhllä£5gßÿpˤ Œ‰Š4‹o`jFwÝq+ ÉÉøúú2nL4a¡ƒÉÈÊ¢¾¾žìÜ|šššˆ‰ @SS¶+õ^yñw aÝ_’”’Æž½ûøÍ¼edfçðÄcà¯òeDD8Ù¹yfuh¸z•µÿØ‚^¯ç•Ÿc`È6Çîä̹ ÝsgЧï,}Cá¥úõ `ÙÒ×èß·o§×Çiê»ÛOÛ fÖôixz¸¯+«ª9xø¨¡÷EÆÅ,êêê ëÏ÷Ç¥‘Q/O/´Ú2 ‹ŠpQHÚß}ó¿“§Ï Õjy`Öt†GHMǹsf°nÓ—œOL":j”YºèèHär9i™huZ’SÒ˜8>d0>f,sòHHI!/_úC==z.ææQRZÊ·NáÖ)“xæñ…¼ðÊs>1‘ó0Öqþƒ³™ù«{Íêjzž•“ƒZ­ftÔ(n2 €{î¼£Y€únùw¢P¸àªt5^+]”(•Ê.©«°€2ûþûèãß²ø##+›ƒ‡¯ë5éX_OAQ1Aý ìŸŸŠºÚ+vË(-+ _@€Ñ/d@0UÕ5­âûxyJVv.ç“Ð440v´483!f _Åý“s I—âáînì––•IåôkùÅ D&“Q]sÙ¬ eÛ"•U„ µ{ÝêšË¼¹b…EÆ>_AQY±šeK_Ã߯sWØ9/Àî÷Ãvc±6¸grÔ¿?¾>¾üñùg[%7 > Jå @qq)ãÆDu1€ý­>ó±ÑÑddeóÕž½R3Uaaøx{sö|µµuDGE¢+¤r|¥rŠŠJŒy^ÌÎC¯×d(ÇVŸÕÂß_%ýÁ–••›‡Ùº×.fùêâ[¶ô5Þ|gEE,_õ®\Ö©õqä= ÀB"80ôÌ,þ½ÿ?èt:ªª«IMÏ@®¦ÏÖ\VG Í#Ž5ÍVÇÐÇÛ½w)iääæqèÈ÷Èår&MoµÜqÍýº´ÌL‚é×W²žr¹œñc¢)¯¨¤áêUbš-#À°ÐP¼½<ùéÌYûâ’2öìÝÀ”IÛ¼O…‹ô›]U#Yä°ÐP<ÜÝ9uæGŸ ¸´ÔáÉ ]ANnC‡ –¬J…¿JŲ¥¯1tÈ`ròò;½>h‚v³Ÿ¶NÛ&P¡óÂ3OòÞßÖ°~ó6m‹¥©© •Šk>"$¨?þ*I)©,~áeÖò>‘#Gp*þ,o®\Í“ aú½?gæ´_²÷ÛüiùJ@Ò¢¿&tð@¬=óaxxx Ñhk|Ç'1>f GŸ`Lt¤1ÌË˃%O,䓵ŸóÉÚ Æø·Ý2™i÷Üe¥œ–ëQÃÑÉdìØó5…ÅÅüñù%,ZðkÖ}±…׬`èàAÆ×Ýíï$në&“+©nþ*_>\ù¶™_gamÈÔtÚ™aýŸ;Òz'Ÿf7%+=ùÃΪdWràЪ/_fÖôûðpo„©ª®æàác ÄmSn1ú×]©'!)™òŠJ‚û14tˆqt­¼¢’“?ÅãííÍm?›ŒÒÅ…“§ÏRQQÁèÈ‘ HÓÉ22/âêªdÔÈá„·YÇïŽý@yE%“ÆÅ6tˆY]öí?ˆ‹BÁÜÙ3Z¥++/'1%MÃÂB9<–ž™ÅùÄd&ÄŒ! @Ð…ˆ> @Ð…ˆ> @Ð… ]ˆ„º  E4A‚.Äi X˜Ÿs=ë!ôJœà-wÜ@º†ÊŠ2ê5ètÚëV1 »"—+ððð O¿@¼};¶‚¾CŸ¤(/)B]]EðàP¼}T(bÏAÏG«ÕRW«¦¤0M=}Û^.ÖN °N]ƒººŠðÈ1¸¸ˆOËz …•Ÿ?ÞÞ>d¦$àîáét^NÂTV”<8TˆOÐkQ¸¸4(”ªò2§ópZ= šz¼¼}»ý—‚‰·/…¹YN§wÚê´:Ñçôz ZÎéôâ= @Ð… ]ˆ @Ð…tpS À¡C AÇMÐë€V«%%5•¯÷þ‹m±;øþǹzí— ضc§1niY_ïý—CùÆíÝKzF†Ýx5j5ë?ßĵæ2M9sþ<ß8àà:!Àr1;›…‹ŸféÛË8u:žs ¬úà#Þ\¶€üüKlÝaŒäè1Þ}ï}jkkmeiäëÿÛKZF¦Ýx—kjXgC€gÏžã›ýÛqG‚ÎDLcé•,þÝó,yò ~ýÐ\㮸 YEkÌ›û ÷þâ|||:«š‚nL- ³Ú÷ ÷ɧŸòó©w0Þ\$íµ„)r“떰¢B¾=pÐ,®N§åøÉlÛ±“ÓgâÑhê­–wðСVi­ï%féoV^QÎ?ÿýo¾ŠÛCaQ¡Ñ¿©©‘|¹…¦¦FŽ;Æö_ëÒРáÐá#lÛ±“„ä¤.öÝË9h‚v€c?üȬ™÷·+e“T£Ñðìï_bí†Ï¹TPÀšµëÙÿŸC­Ò>zŒÕ|DTdÇ6;9{î<‹?Cjjéé™<öäSü@cc#kÖ®ã¹ß¿Ì¦/·p!1777*++Y¸ø~wˆ’Ò^ýï?³ñ›;T„u’Ò²2®Ô×3xà 6Ÿƒ!ÌÖqkìNÜ\ÝøôãL¶ôjovÉié,{wï¯\ÁÀ­Ê3\¶~#®J¥YXBR2^^^èõ ÓéxgÕjž~âqfÏ”vKŠŠÅš¿¯gÒú‰Æ|î¾s*óç=dÌcÍÚõŒŒˆàí7—ðàìÙüæ·OðÄ¢…=+mDÐIikj???§ó9tä‹ÜL|¦”–•ñÙ†üá¹ß1~\L›yyxxàêêjægºÅtQq1— ihh`ß7ßÒÖ×¹ùyfin»õgf×§NÇ3õöÛi”v¶®8†xŠN20$.fg3ÀÎþ}mQXTLß>þ6ß:…Z­fäÈvóZôÈoðöön埔œ€º®€êšã9Àã Û¶dµuu\©«£¨¤Äè÷ÈÃÛ­À>b&Œ“(rbÆŽaËöÜqÛ­¤°|VÒµ——'eVÂ%æÌ˜ÁOñgx}é›lÞ°oo/;y[+Gr!ÁALz;‘#,mm0Gb@pÃÃyôáùvîIÐ^Ä Lxù…HHJâý¿}Bcc£Y˜Î°DE&³ùJ :2ŠîÛ×ß™ –¾þ J¥’·V¬èÐúK•¯/1cÇðÅæ­íÊ箩SÙ¹{W®\qºluD´„ÊÇï­bù»«8|äÑQ‘(•JRÒÒ‰Å[zƒÑQ£¸¬VóÉšÏxèÁ9­òXòÔ“<ûâXò∉Ž&%-{~7³MFW=<ÜÜÜ ¹œ ãÆ› æ(•JîŸ6Áƒ¡Ñh`îœÙ¨:øE°žByië6nÚךéÖÔ†í©[áôñgNû0rìÄë{'ÁMHÊ…x&ülj'ï–y ‚v"a‚.DP èB„‚.D̺§(—ËÑê´(lÌaz:Öæ<^GhoJã¼&wêkÕN,ôêÔjÜÝ=ÁÉ‚ö¨·8ý}T”—¢kcš•@ГÑj›(-.ÄǿؚìkGŽX@ÓŒŒoõ}T*¼|Tdg¤¢®©éÐ繂› ­N‡º¦šìŒ4|UþøH3‚ÌôÑÕ®5t´hš¹Ð*•J|ý»¸R]QFqA®Í ÅAOB.—ãîî‰_@?¼}|QJ‹ µÍ®Í©g–Ø µ_˜ ÐÓËû%ÀpE𮿂dQ VÕÚ47àfÅ (ƒš¦™]4X ÝÇ8bMÅg(ô,ÒÜP¤y¢®Íy)ôLL¨EÒÂ5¤ùž¤¹ŸMÀ6Åšõ´ˆÇÔú m®Ò"4]³Ÿ¢ÙÉâôL z0X;ƒš,¡¥åk%ȶ, µ¦§Ahü”´X?!@AOÅÒ š KhX†d­)j•ö4A›vÍÄß` ÖÏ @ §b*@ƒM…Ø„ùò£6±'@S“+k.ÌL_Ló = kƒ’Á5š â´ûbÞ^”æBhÎÐào(À`õ„ø½[o }?[£¡Vq´ jeXˆOб&BS1Úž¶#³r4›5á  z–ßo4ÑòÜ2n+ì Ffqn)6K«'(è X¾Z°öQÕ6_?pD0–qlY;!>AoÂÑÉ×m6CÛ#[q…ð½[sh.¨³â¢Z#¾!@ ›ü?¥K&”j%IEND®B`‚././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gtk4/images/layout_box.png0000664000000000000000000001410415074674453022335 0ustar00rootroot‰PNG  IHDRàdŸ &tEXtCreation Timejue 08 dic 2022 22:10:48——R,¤IDATxœíw|”EþÇß»›„ôBI H‡„н£¢ °‹w–óÇyè‡DDÏ;,€ ¥Då8šT)! -½÷Fz#ìîïÍnv7»ÙMM™÷¾ž×>;3ÏÌ<ó<ŸýÎÌ3ó @ @ ®9’n§@ÐUPvfd!cq! zÆ„×!A¶W$úÇIÌôºúSšégm‡!¡IZÙoo:AWÀØ”­ì:®UÚ" }aI´6©ÞocBºúbÓÞz¿õÛÄ\qZx†6!BAOÀøF6}qjo+32aÌâÉ´¾e@_ ?à ôiŠ[PÐÑR#PTE@ oÚZßÚÇJ0!BSÔŸÚ©Eg8ÃvþòXàä€yHpC)'èHP*ʲˆÈ Û›7o \A%N Í"T ѤM E¿Ê©-«¦Ípž´¨ÞÚÔ £ÆX5TÖ)YzÚÚÐ’iCÐÐt"}J;y^¢@ÐÝÑžiL|-,¡9CÑ ¼– ý :h‹ÏЄƒ´öÐг@íÈ{%dW(µuu:î%ee„ì åä™0³â)+/'dW(§Ã#5n'N‡²+”Êêê6ç+,"’]¡DÇÆë¸§¤¥³gÿAtjëêÙÊÁ#GÛœ–6 É)„ì %%-Ãh˜ìÜ©TŠß˜Ñš8ª®\!*:†ââRúø0qü8¤RÕrBr £bxøþ{ILN!#;‡ Iã[Í󥘔J¥Ñ0]A}ˆOHâŸ~Ìò,A"‘ðIÏÌb ·wG¢n—&Ú*ÀæDºv9w:ÙY¹TVVi~çå¨v´þÃ""ùüËõÔÕ×#‘¨Šê©y2çÁû[m´Üö:Ì·?üHcc£Æû¾;oçÅgžn‘§ ~ã8tô8 )xpçRŒÊú-œ?å«×páR óžMCC)ié ¿qöö TYÎUkÿMyE¥&¾QÇñÞ;ÃÖ¶‰‰É„ì %>!‰K1± 4Ð`žO…åó¯6põêU£çÕUxïí¿²tÅGdfåðÏ#‘HÈÈÊÆ½–½½¸3òÛ&!ŠiDfòÞªOZõ¯®®á?¾ÅÁÞžÏV¾L&ãýUŸðãŽÝÜyÛ,³ÒÈÍÏgã÷ÛЯoþyW¯^eíº¯Ù{ðw¦à?vŒNxµã“’¸eÆ4¢bcqvvf¢¿C}“”’BMM iY4662Áo|þÕF®ÔÔòÖëbë·ü@L\»÷ìå‰ÇѤ‘œ–ÎsO?‰›‹3#‡#-#S'uõõ|óÝV”J%o½þgúxó}ÈÏœ»pɬs¾ÞôëÛ—KßQ‰0;€ýûñÁÒ%¸÷ïÝóÓn*»Ú_Û5æÁ{ïÆÞÎV󻤴ŒCG«[_$¥¦P]]ƒÇPwþ8­êu°w@./$7/+™ª¨ÕáµQ6}Â"Î!—ËyøÁ{1\UuœóÐý¬ßü£cð;Zç8?¿1H¥R’’‘+äÄÆ%0yÒÀ¤ ãIMÏ$*.ŽÌ,Õ6ÞoJ”¤fdRpù23¦3-8€—Ÿ]Àkoý‹ÑÑÌìaMç=2›î¹C'¯Úû)ééTVV2nìh¦pÛÍ3š¨ì’÷‰Lf…µæ·µ•5ÖÖÖÉ«°€f2û¾»èëÖ<ù#)%CGk~×ÔÖª¾kjÈÉËÀÓÃOw\]]¨®ºb2Ë…E è×Oãæãí@iYy‹ðN êKJZ£c¨­«cü8UçLÀv„þÆ…¨òó/cgk«i^.,T¥3 ùßËÓ‰DBYy…NVÖ­ß"Å%¥ âkòüºeå,ûðcrró4m¾œ¼<Þýp5,]‚›ëõa×~v½?¶k‹¡Î=­}OwwœœYüê+-× ‘6 ‹‹3ùù—™èï@Jj:ÞîË|¼ŸI)iìØ½@UMUÂð¡CqrtäüÅ(ªªªñ;™T¦JÇY•N^^&ÎÔ´L”J%žêtŒµYõÜÝ\T7laa‘®Ÿ±sµ0ËW¯Ñˆïƒ¥KX¶âcròòXþñg¬YùÁuÍ9Ïfà;x^$&§ð¿¿£P((-+#>1©L5|¶¼¢RÓS(kêq,o²:ê6Þ®={‰KH"=#“ÃÇþ@*•0É`º›Úu ÉÉxyx0 ¿ÊzJ¥R&ùûQT\B]}=š,#À¾¾8:Ø~î“&øsüôüýÆhüìXôܾøf_|³Q~ú” î¾íé4ÿ=b‰„ŸvÿBn~>‹_]ÄÂùsY¿e+Ÿ¯û€!ƒigtµû$tÛf­_ª¼¹¹8³fåû:n× C]¦ÚÃÎÔóÿlQÍwrjÚ‚Sc×\¯LZ’ƒ‡QVQÁƒ÷Þ…ms'LiY‡Žž` ·'Óƒ§hÜ«¯ÔKQq žâ{ƒ¦w­¨¸„°ðH™>5k++Â"ÎS\\̸1£â{ N–”œŠ5£GÀÇË«Õ<9q’¢â'N`ètò²÷À!¬d2æÌ¾¿Åq…EEDÇ%PW[ÇC}5b¸Æ/19…‹Ñ±LðgØÐ!:Ç%%§—˜Ä >Lð -=“ØÄDú¹¹0‰#ÇOâãíÉØÑ£Ì-ênͰ‘cÿCõr¦* ¨Cwf|‹3B€A'Ð^ŠNÀ‚ˆ6 @`AD/¨@`A:0F tÑ,ˆh D´ "(XÑ #Xt ETA Òn ˜›•Þ™ùz%íà”·P]YNIq!u5µ(òNËXWG*•aggGß8:›7‹º·–UO£=×Þz%EQA•e¥x öÅÑÉ™¬÷¬Ù"—Ë©®ª¤ 7“ºÚú{´>e¨7—UO£­×¾5Ú-ÀêÊr*ËJ6Æ+«Þ÷j™L†‹«ŽŽN$ÇEakgoôß°·—UOÃеo/íî„)).Äk°o¯¿¡dVVxò¥´¨ÐhQV=s®½)Ú}GÔÕÖààèÜåß„|=ptr&7#Ũ¿(«ž‹©koŠv[@…\!Ú1MÈd2ä …QQV=S×Þâ9 @`A„ "(XvˉNóe%hI‡(:õÌG”•À¯‚9vœ°³áý6lÚLQq±Yñœˆä؉šßÙ99üøÓÏ’Çž‚\.'6.Ž_ÿ»—­ÛCøýÈÊ++MØ 6mÖ¬­(®‹.àácÇ8}ö¬A¿õ›6kV 2EXx8GŽ5 0++›m!?uJ{q ,xþEÞûð#ÎFD’’šJÈŽ]<ôè\ªªªLGÐNY¿i3•U*¡‹ë¢‹šÑ ÈËÏçOo¼É⿼Î÷Ü£ãW__OŸ>},”3Aè„i±Ð½á‘‘¤¤¤áííÍÌ›¦XÄØ·Š¨ØXbcãé×·/Ó‚ƒpttì„s0Ë5W¯ýœﻇî¹»E>úô±iáfªŒ²sr‰8‰‚ñòôÔñ/))átx8µWj˜¬YÕI÷:§gdp6"ggg¦M ÆÕÙ…BÁæ-?pç·1h`órØÇNüƒƒ=s&<‚úú:¦M™‚OÇÖv·(¯‚š‹B¡à­¿/å› ›(*)fãwßñúâ·Ú4¼kÕ§kXöþ 2³²Ø²mO<ó!‘_wü„T*åêÕ«<úÄSœ:s–éSƒUá´ò¤ÿ}æìYŽýq’Ÿ·~“£#r¹œ×ÿ•u_¯gÅ{ïv‰˜8M Àìœ\ðöñÑäáüÅ‹œ»pQfÔˆá̘>Ýd•••óÉÚñïÏ>e\ÓZ†ß|»‰>]CèOÛ±²²bõgkxrþã,|ò RRÓxâ™gQ6]G¥ìíøný×888 P(øëßÿÁ_}ÍšUqǬYìúõW½ð‚æø+ÕÕLš„\®`ÅÇ«yé¹g™ý€jµ§±cF³îë nh}]îJ—°€VÖÖØÙÛ·Ø´ ‹ˆdРì;p½ûösð÷ø¹¸‘™iVÇOžâÎ[gáÔT’Éd<9w.áçÎwúùt%Ôk¡W”7/qÝPß@uUÕUU>zŒ§N¦Ë(òÂy|¼¼4âxjþã‘“CII IÉÌ™ý Æð æª¤[[;Õú‡OÍ›GdS³n¾™Ô´t .pâÔ)n¾y&2™Œ¼ü|²sr©««cï¾ýìÝ·ŸÒ²r2²Ì»º"]¢ÆoÌ^|ö™î65/¦XU]ECÃUò 4nÓ§Oc‚¿¿Yi\fâxݰÞÞÞTTT9¢gàááNŸ>}HIKgð AO "xJ®þD¶µ2R(ä\¦o¿¾:þöö¸ººPRRJMm-666mnWûøxSWWÇ•+Wpss%`âDNœ:ÅÜ9ðÇÉS¼üüsTVWPV^®ÙxvÁ‚6¥×•è0¦âR5Ü}¼<É%ŸŸ]hâXë»öus#¯ _Ç¿¬¬w÷VÒîL,S•H`jPßoÝÆ¬™7!‘è/ ÙÜYÕZI¥ú¹¹’Ÿ_ ãߨØHUU5ÞÞžH%R(-+¥¯›[‹ø]§’²Rpp°”Ü~ë,Ž?Îm·Ì$'7—ÉQß3gÞĘ‘#œG÷¢KTAÍá–38NBR²A‰D‚BÞ¨í€\ÞüÞ•À€‰:|„ââ[èo{˜yÓ´k–ç®Â¯¾BJZ«>ýŒ††¿ÚšZ;©2š0ÞŸœÜ\Ni~n»gï>†øÆËÓw÷ ôñaÛöæç|Å%Íq©©©­¡¬¬¹J¼û—ߘ1µù:Üzó .EE³ïÐïÌœq“f"³‹³3Æû³åûm=fne—¨‚šÃä€IÌó0¯¼ö÷Ý{7NŽ„EDðÙª•ôusc¼¿?ËW}ÌÆï¶ðÜ‚§7v4••|±î+}ä!îºãv9‚_â–3HÏ̤ºªšÿ¬ýÔÒ§vÍññöæ«/Öòîò•Ìž;ÿ±cqpp 6>¹\ΒŪžJSeäãíÍ¢žãí.ãö[g¡h”~þ<Ÿ®\D"A"‘ðÖ›o°dé2RÓÓñòòäÂÅKØØØèäçjÃU¾ø2Ó§“K~A>ë>o^pÙÅÅ…ñ~ãøö»ïYù¾nÙßÞ|“7ÿ¶„—^} É\.¤¯«+^ôÒ5.ÅkC»—¨>wæÄš1ã;Þótôø ììì lá·qówÌ~à~4­±Ÿ@tl ¥’1#Gà7n‰¥RIXDùùÜw÷]ôéÓ‡äÔ4Î_¸ÀÍ3nÂÓÃ¥RÉ™ðp2Ò3ðññaê” 7G{‰»ÉhÿIýâ£ÎÓeÕQêëë‰OH$)%+++|f¼¿ŸÎdasÊ(1)™‹QQ8;9„››«ŽNn.aX[Y3sútNž>Í-3gâääHvNé™Y¸¹ºƒ»û¦ã ×é¶û×ßørýzöÿúK‹WyTWWs6"‚ܼ|ôïÏ´à)¸¸tìíd!îR$Sg^ß5â;K€=…î ÀîÄ_~EyEËÞyÛÒY1IGØ…:az:¢¬ÌE©Trøè1ÿåuzz¹u›NAï!&.ŽŠÊJ¦öüZC·é„ôüÆŽåØÿY:×a bù± ½QVC´[€R©¹BŽL*Œ¨B!ךÕQV=S×Þm=R3©ËÖÎŽšªkû:ƒîBue%¶¶Æ×eÕsѺö¦&¶Ä” Ïj¥“K?Š rQÈ{÷2[ry#—ósqrëk4Œ(«ž‰Þµ7<Ù„ ͱ€Ú)š6¥“‹ N.¤%ÅSY^Þ¡×swGä •åe¤%%àìâ†S+ëÄõö²êi¹ö:úh jÒšÛÔŽ\È­­­qvë‡Ôʆ²âBòs2Pô¢K*•bkkk¿8:9cmmm4lo/«ž†‘k/oÚôEØ*ƨ4°éÐÞÁñMÀ°A5\Í •EU[UCÃÜ‚îŠZPj4¢fÖÔbX€ú[ ̱€ÚâS'zÕØP;TãDmšâ’!(è™h PŽJ ¨Æ{Ö¢û©=îÓ,+hH€JšÅ£mýÔ‰^êiš¢ÉMÖ´IâôLÔzP[;µêš¾ÕT[Bã³›hͪzª…¦˜ÚÍšfë'(è©è$uTm šÜ UE Ò–*h#*5h¹«-¢Úú©(ôT´¨¡¶Ñ~Ô*¦¨mr%M î?€vç‹a=C’jÁ]ÕúV‹ÓäƒySUPš¡)Bµ»:µÕâôŒ=P·ýŒõ†ÄÜ*¨Ztúu`!>AoĵÅhRxjZŒÄÀ·¶Ø OPÐÐ×¢Zˆúûúa[`J0½}}±é[=!@Ao@ÿÑ‚¶µ3ôàݨ%4G0úaŒY;!>AoÂÜÁ×­VCÛ"ca…ð½™Ö^én’öŠGˆN h‰xï@ @ Œòÿ¹;,ªË¦IEND®B`‚././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gtk4/images/layout_center.png0000664000000000000000000001662515074674453023037 0ustar00rootroot‰PNG  IHDR¬dÚÁsBIT|dˆtEXtSoftwaregnome-screenshotï¿>&tEXtCreation Timejue 08 dic 2022 22:12:52ÄPBøõIDATxœíÝy\TåÇñÏv@ÙQET\p-MKË6³ÔlOï­l»­÷f‹Ù¢mZ™-jjÙª¦¥fšÙ¾jî Š²(ÊŽ"( ÃÌÜ?†g`H~ï×ë¼€sÎ<ç™q<ßyÎóÌs@!„B!„B!„B!„Bœ3¥•”)„¢õ14gaÍ.öÊàBˆöÉ^P5)À*5§4p›Bˆ¶«f ¸­AÎ5Ll“RÇï=ŽBˆÖÅV8êøÝÖãêt.AR3ˆ‹EUão{Á%„¢íªN–‹¾Æß5÷¯WCÃÄVH™‚ÊÖ"¡%„í‹­°ÒÛYj†™åãírl@%쵨,~:¾@GÀ p®.[K!ÚËà©Î%@pÐU/z‹Ÿ–U¨'´ê ¬šaejA™BÊð¢¾\¹bâ€øþ“PðÁ %„íš‚Á 7œØ¾c÷ò‰“&}¤§1†™ÂÙÐ2W½¡U_°Ô¼hTjÀwÀ€W­Xöž¢ iôBÑf xì¸ñ÷%$$ìŠ-Æà2µºl]"¬¥®À²l]™ZVŽÕ‹àÑê•Ë>4tiQ!D;¥ T]=î†;·¥@%ÆÐªÂºo ì„V}e«e儱ª÷‘C)+@ZVB!B9Ùõf c—)´lµ´jQÙ+µÆï¦Ð2] ô[öùÇã‘°BÑ`ŸÏ>^z=ÆzjŒ™â€õ¨r°Ó˜ªoZ%ËKjŒ-+W [ú¡”/ðirý…B´½¾¨K×î7É@9Æ––©O«æ +uõ=Ùh .E1x7ï´†B!Ú:E¥òÁØØQc=øBE=#ú=¬šå†^†® !„8WpÃú’ i‰:5¤…U3°'i\ !„h$'Îæ‰e`™–stabï² C³TY!D{d™%5§ô³ËV ËÖíAj†–ª™ïË%„¢ý°œÞÏ^XÕji5dj&[Ý:H^ !„h$˰²5aºMöËÖ˜xËÐ’¢^UUU>r”#”•UàOŸ^=qqqnéªÕ²{o"Éiiæ¿==<éL¯Ø¥ùßîZ­–¯Ö­·¹Í×Ç›Ë/ÙìÇlSÓØ“H|ß¾DE„·tuDëU3OlåÍ9 k·|°e!  HKÔ%9õ﾿˜Ìì«õQ‘¼>ëùf9ƲU«Ñ骸ý¦›\Ö®½ ¬Û¸©Öú˜îѼðÔ8995ù–*µZ–¹Ææ¶¨ˆ.Œ¾P+9•å_®ÁÛÛ›H ,Ñxºwâ¹ÌÖ^cD–°-3+›§_˜…¢(ÜpÝ5ôŠéÀá£Ð\ï~þ…J­–Ûo𨠥ëô¿‡ Ÿ8$§0wþ"La×Þèß Ç¨}¼ @ž~ü«-jµ#îÿ/[7mÕ¸›ï$¦{4O=ú¼¼¼(9uŠÙsßa_ÒAÖ.ÿ¸)ÅÛ»ƒ½]´V. »Þ[ò:ާ˜AñýÌëûÆõ²ÚÏ`0°w_™x{kßgãåÂ?6ÿMU•Ž!ãÙ¶sÅ'KˆëKXçP¾^¿‘òŠ ô:=+¾ZK ¿?#† mP¹§NŸæ²K†±}×N–”2røEæ:9::âââL߸^\îW_¯7^¶uufOÂ~<=Üп/®..uþ›/,"a_§ËËè-­¯6¢Sh¦ðìK¯1ó™i(ŠÂs/Í&ýh¡ÁÁM)ºQr®uö òáJØPrê“SèÌ þýì¾O*µZfÎ~ƒÄýPƒÁ€Ÿ_æ¼ø<Þ/~ûk ‰û“X¶ê+ ŽàààÀŒi×3–µ6RQq€_®!®g,#.Ú r÷'ä—ßÿ$%í0ŽŽŽŒºdØÙŠU7Μ©$95 ///z÷èa~ø‰>]FUÕÙ»úòQÜ=ùv‚زu;G3³ &:*‚¹ï,ädI s_™eýZTÿ®ÕjÉÎɵzm|4šzËÊ?VÀ}>^öx..μðÔ4ºu¤¨°˜_®á·?7“›—oÞ§Wl**ÎzèyÝýwOáò‘#Xµv?ýú……hµZ‚yå¹gÐh¼j½NoßÁ[óQq挹¿ï¶I?öÛÿø¢ÕxþÉÿ2}Ö+ÍÈâÙY¯¡( G22ñïØ‘O>Þ9pNÁUß÷°„8'™YÙ„†Ôýékõº $î?ÀÄqcYöÁBî˜4‘‚‚BV³Á¼Ï™3• Ï볞ãŠËF¢ÓéX·ÁØÏ´tþÛøxkpwwcí²yáé'\nyEåå ÿŽÏ{}}+ƒ4±„ •••€1êzìNH0î¯Õòõ†TTT‘•eõ¸Q#†Ó)4¿Žlúéròój•kùwCË}ô©t 3?Þ´eÈÀxBƒƒ¨ªªbçÞDöîÛÏó¯Îá•çŸáïí;Ñét\?ö*¢»F0~Ü5,Zú){÷Ñ+6†Èˆ.\3ærÖ}ûG3³èÓ+–ËG´[gÆ“+G]fµ-¢Kg ê-kÔÈádåäp %g'E!'7·úù÷‰Œ£_\o¶îØÅÏ¿ÿÁàñDEFÑ%œu7‘ì8:½•ÊøùÕ[£á⡃¸{òmìܽ—ĤƒVåšžCÊ¡4N*# Ÿ?6ÿ €»›;:Ý1²srèÖ5ÊÞ[@´Ž8©Ï~¨S;ªQ«Õ-’rãEѬLý1GŽfPUU…££í·XYYyùù¨Õj.2ˆÈ.á6÷÷ôôD¥R¡«ÒÕyü†–k¯^Æ f`¼±¯é†±Ws网œšFñÉòàסƒyÿà ŠN›×Ý<áz¾ûñg*++¹iÂõu‹×xi˜4~œÝíöÊÒjµÌ™7Ÿí»vÛ½¡¡Á(Š‚®Jo·,oÓÝ€Œû¨T*4^æ×Ì¿P©Tœ,)±¹½¬¼Üø³¬Œ¬êK›þøãí-wjíNŸdÆK¯‘•cî³ÊÊÉá¹—fóâôiæ>Óó¥ñ% ,aCB‚‚ÈÎÍeíúï˜pí~Œ€€2³ssÙ¥ôéÝÓzc;žšï5‹j†Û]®ß]]\ $=#“Ò’RsNnn>}{¤J 8Àßü¸MÕ°jÍ:¦ÿï±Ú/@ÛÙ+koÂ~¶ïÚÍ•£.ãž)·ðËoÖý<ë:¦×ãÈ‘Lôz=þýj—e€@ã¥N/O/ð>ûÏS´J3g¿i«§O`Ƭ×ÈÊÉaækoðæË/ž×úH–hvS§ÜÀç+¿ä÷?`çžRÒóý/¿²;!€¡âøxù/D¯×“t0…ÒÒÒÇÓÓ“²²2’¦ Ó隥\½^‡^¯§¼¢‚¿¶nçHf'!ÁAôŽíÀWßl é` éGŽòÓ¯ R©Ðß82'/e_®!:*‚þ}ãØ¹'?·lµ{<­VKvn®ÕbdRWY¦–MfNåååìK:@•®îÖgC/*bÃ÷?’›wŒÕë¿`@¿8ª[¦EÅÆexçNœšÆ·›~D¯×Stâ’S›¥.¢e¥9J—°ÎÆÖ”FƒFËӧÑ%¬3éG3Î{}špIP>: ÛzÅvgÚ#²péÇüüûüüûæmýûÆÑ·wOF JÂþ$~ýs3÷<ü8jµ­V˽SîàŠQ#©¿9—ÆÒÏ–óÌÌ—ñïØ‘÷çÍib¹ðÚ[ïZýíééÉã܇J¥Ð3¦׎¹œo¾ûžgf¾ /«Ýyó„wE¯×ñöÂ%TUUqï”;puu%a_K>ýŒ¸Þ±xº»×z¹ùù<øß§¬ŽÕ%œ×^|¶Î²úöŽÅËË‹}I¸õîûQ©Txzº[”m«ùØð&Ö’?3ÿÞ=º+W_10…¢(|±z-Ù¹¹<þà½ügê¿™3ï=òK—­ ªª †Þ›ûÌ"Ο5Ÿ/µøËøþðÑxñæË/X­;_l½›,§a2ÝÿÊãýK<«—ÁiÉûß<_•­Syy9)‡“‘™ƒƒ¡!AôŒénîÜH=t˜CéGaá„u³lÞJN^WŽiþÂâª5ëpusåš+F›¿/é i‡ÓñõÑpñÁæ²Ï¥\€= ûHN;;ÔÛÉIM€Ÿ}ãzÕúRÚátRRáä¤&¦{4!AÆ~¬Ü¼cü¾y þ~\r±ñ;a[¶í #+›¸ž=èÝÕ\†V«eõ7ßÚ|Ý|}¼éSoY'Nžäïm;1 ÄõêÁñ‚"2ss¸æŠÑœ(.æûŸ£SH0C a’S:0ÞÜ×øí¦)=}𝋢(Üòï{ñòðä‘§’œ’F`€?ñ}ãpp8{ƒ†”ÔC$%§Ð)4„þ}Œ:N.#aß~ ŽàG—ð°E&Z‡¨n±¥ÕKPõ‡k}²’ÀB˜™ká¼9-]ц56°dÐ…¢6ùÿ-.@Ò‡%„°Aþ‹ |Ka¶lÉ‚–®‚v5a¦ !„âü‘>,!„­‚ôa !„hd¦ !„­‚–BˆVA]!„hš0èB"K!Äù#—…B´ naeg¤7g=„Bˆ:5:° 3ÞÖûTI1…ÇQQVŽ^ß<÷ã¹P©T¸ººâ뀇—ÜMUѼÚâù´9Ï›Mšš© /‡’EuÇÃScu ‚¶H§Óqª´„¼ì£T”—Ñ1 ¨¥«$„h#Úêù´9Ï›¬S%Å”œ("ªGoÛÇ”„h¼}ððð$5)W7ii !š¬-ŸOm7«Ñƒ. #¨sx›{qÂÁÑ‘ÀNákéª!Ú€öp>mŽóf£_Šò2Ü=¼0´Óáíž^dIkéj!Ú€ör>mêy³Ñ-,½Nßf®±6†ƒƒ:½¾¥«!„hÚËù´©çMù–BˆVAK!D« %„¢Uhâ”¶ÝA(„çœOëÓ¤ÀjãZ„⼑óiý.ˆAÿyyùìØ½›ÂÂB|;øÒ·woBCBZºZ¢Ñét¤¤¦’švˆÓ§ËèÔ)„ññ8;9µtÕ„hŸýC‡×ZÄ5WŽiT™z½ž>ú˜I&àååÙÔ*6I‹÷a-_¹Š›'OáÏÍ›ÉÍËã—_gòÝS)>y€¿¶ü͆ï65ù8z½ž7ß~‡'Š›\–h{§§3ùžû˜1s[wìdOb"sæ¾Íó³^j–òõz=o½ûž¼ÿÄ?ê§_å·?ÿ¢ôÔ)«¥¼¼¼ÑeVUU±èÃ¥””–4cM§E[Xyùù¼õî{|úᢣ¢Ìëõz=*•1K÷ï'3+‹«Ç\Ñäã-_¹Šñã®ÃÇÇ»Ée‰¶ãøñBî~à!¦þk Ç_¢(æm:]óM@ºbÕW\ÝXyÿ‰T¿>q<öÐZºÿˆtqèðaÔj5‘]­ÊR©ÀÀÞÄDvïÞÃÉÒR¸”Ý»qÑÐ! ö$$’š–†^¯§_ß>V·æ›o>t(™Ù9$%`ø°‹Øôý¬üj5Þ wÿkr“ê.ÚŽw¼Ï¥Ã‡qã„jm«ùeÎm;wr(í0ÁÁA »h¨ùƒÕÖ;éàãCUU{÷áææÊ¥#Gàîê ÀGŸ~À—«× Ñh¸uÒ¸VoK;t˜Ý{öâæîƈaãîî@fV6&3h`<¿ÿµG®¼|ô?ö:ˆ–ÖX‹¥¶Ì¬,Ò¥[tW6oÝŠöL%_4”à ë i Ù¼må§Ëˆï߯FÙ-§E[X]ÂÃÐjµ,úp)ÿºóŽÚ}Š‚¢((ŠñÄ¡¨ŒŸ|?ùl?ÿþ;ÑQQÍÈ`Þ{ ˜ñô“æÿÌk¿þ†ï¾ûü‚ºFE2h`<ªêJ¥jß( ÷Ç_1wÎkuî£×ëyjÆ Ñ»g,ø‘Õk¿æ­×g£( Û¶mçÛï¿'8(ˆ˜nÑìÚ“ÀgËVðÉ‹pvv¶ûþ[þÅ*¾\û5Ç]Dff6ï/ù¥‹ÐÁ×—ÌÌLæ/^Ì’>"( €˜îÝÿÑ×A´}™<7ëe:øúÒ¿o²ssygá">Z´€Èˆ÷'ñØOÒ'®î,ùè“®õY-:J0(0ˆgžøo/XÈʯÖ0úÒ‘Ü4q"]ÂÃèÛ“>q½ÉÌÊbÊ·›yÛ-7sÇm·šËyû½ù¬Xù%cFWú4€7óß~Ëü 8<,œù‹3~Üu„uî,#rùÇŽqº¼œÎBëÜï»~ä`r2k¾X†J¥B«Õrãmw²eë6†@˜ÞxÅØçuº¬Œ1c¯çÏÍ[¸läî¸åf.þ€Æ]GX§Ndeç0ñ–}ô!BƒŒž›ùË¿XŃ÷MàDÑ æÏ›Kl˜ê%ˆf9'`÷ž½Ì{w¾Õê1W\NtT8::òÙ‡Kpvv`ÊÔ{Yµæk¦=ö(³ßx“[o¾‰;o½0^¸eò †–ÉØâ£¯½ú*F_v)ëÖo`íúõ¬ýf=£/ÉóÓŸ±;s±)„Š‹‹ÉÉÏG£ÑÌzà!ƒ™÷žŠ3g(+/ÇÛÛ~ßÒ¶í;éÂÆï0¯óÖh8rô¨9°<Ý=ÌÛÜÝÜèÛƒœ¼<»eîڳƋ„}ûHØ·EQ‘ž‘aÞG£ÑHX‰sâ¨Vãêf} G‹V½“Zm+€¡ƒ±ÿÀAÀx)ð`J*óç½eÞ^߇¹ó©Å ÀÅÅ…'ŒçÆ ãÙ²u+O<=õ72îÚkmîŸìϾ8“Ê3•ÄÄtçTiéy®±h+Bƒƒqttäpzz­ëø–JN•R©Õ’k@ L\¯^vãêæVçìÛ¥§N¡ X•LxçÎçø,„8«WÜ=erƒ÷w³xŸæ;†““õ<ªe\p3] 4>q½9rähòÏþþÎüDGEòßG`ûÎìØµÛÆþ¶ßò‡âÂáàà@ŸÞ½ø|ÅJ.:Ôî~!Adçæq×ä;›íØÁA”•—ó¯;n—«‚æ=/ÕW–­s¥>>TVVRt¢_Ÿû¶ü¹³Eÿ—œ.+£¸Øú{)'KKI;œN÷n]P;©É;V`µOÁñBœÎ6iÕ{,EQP«Õµ. ñè$aß~Þxû´Z­Õ6}õ­.6Œ¿·n#9%µQǰõþë߯Š¢°jõÚÆW^ˆfäïïGhHŸ/ÿ¼îxaa ÖÈZ‹^ܶcϾ0‹îÑÑ„†† ×騲m;úõãòQ£V¥Rñ¿GfÚôJO'((Ý{öâtÌöbk|·b±¨ª÷qÔ€sõ:õ®)Wø7éàáaaÜ0öZ:øúàääDpH0wÜr3“&N0yÓ¯cG.2„òòr‚ƒƒ ëÜ™Ø1ô¬îˆîÙ#†Ç~'''zÆÆ V)ÄtëFßVÇ»dø0<ÜÝqrr"6¦éÙù9øØï÷­Ghp0㮽†118©ôàê«Æ0iü æËuC d`|ÎTTâììÌ5WŽ!¬sgã{UQèDxX˜¹L…¨ˆü¸døÅx¸»ã¬v"2¢ DFtáòQ—¢R©¨ÒéÏàA䊂ÆË‹^±=Zä5çÏñü\šz>ã#OOOÔjµÕâ­ÑÐ5* ã@ó¹Òø üý‰ŠˆŒá6úÒ‘¨Tøûùsÿ=÷Ð)4„nÑÝš%¸ òsXôÁÒM@PY½h*@_½Ø¼ö¨ØYg +SP¹n€gõ2xç–ßßìßäÊ·fI{wÓ»_ý; !D$좽œO“öî ÿá¥ÕKPupÕê4»à]!Dû$çÓúÈÐ$!„­‚–BˆVAK!D« wBˆ €œOë×èÀR©Tèô:Úé7ôõzÌN „híå|ÚÔóæ¹>Ò<‡‡‹«+eÀ([Ê©’\\ÜêßQ!êÑ^ΧçͺoÜeG}e¨ñÓ¼ÞSÓ‚¼lôÍxGÖÖB§«"?7Oß–®Š¢ hçÓçÍZ™Rã§M iaYdþ²§Fƒ»§†Ã)().FW=çZ[¦Óë))>Áᔃxi|ðôÒ´t•„m@[>ŸÚ9oZåIõ®õ¶¶Ú‡eY¸ЩÕj¼|: rtâÄñcäf1OÚV©T*\\Üðîà‡‡§jµº¥«$„hÚòùÔÎySW½Ô9SMöË`c± ,7wGWÀ ãôMŽ[l¦V›­iŸ„B´}¦2åFÆi—*rlVÍ¥–†´°,ÃÊtÐ]çtÅ8Ï SuYH` !D{gX:ŒÙQ‰q¾ÀrŒs6hÂ[K¶ËÀÙ°±l]™ªÎp6˜ôÕëª +!„hïLùajM™²£¢ú§)°L--{wÝ5««…eëR )˜LdZ§ælëJK!DÍé’ ©¥eº­ˆ­Kƒ6Ë%Á*ŒTi±ÞÔâ2µ®L%„BX–)´,ƒ« ëÛ‰Ô©¾À²lÒ)ÕëÄ´layóG!„í—­A{¦€ÒZü4…Y½_$®ï’ Õ¡º@ÓzÓL­* +!„5Ùin껲7ZЦ†^4…TÍk’VB!êb+´,ëޠ2©+`?-ÃÉVPI` !„°d9“…epÕü½æ¾µÔ0Jßk†SÍV•–BK5‡ª[¶¦l}QØnK«!Ss{­) +!„¶4t²Û:/ žKÈØÛW‚J!DCØ ¤Í%ØØ°‘BÑre!„B!„B!„BÑêý·¸=Mܘ,IEND®B`‚././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gtk4/images/layout_flowbox.png0000664000000000000000000002124415074674453023230 0ustar00rootroot‰PNG  IHDRHÏÌÝsBIT|dˆtEXtSoftwaregnome-screenshotï¿>&tEXtCreation Timejue 08 dic 2022 22:17:47šÿw IDATxœíÝ{xå/ðïÌH¶$ë;qçâ8Wr'wÒÒöœ¶Xh¹,h{ÚtO{Î.tËnÓž‡P(„Òð즻lÏÓÝgéžrh!- m(÷rJ¤P.uŒã8÷‹ïŽíȲ$;žÑùC–#+zeæyl? à €~$›§‚sM2Õ(Çl’c5²ÌSêôÆèP±iÓ¦ÍOì~ì) B#"’(ô^uÍu7×ÕÕ½ ÀY$ejV™í”û<¹dúì15st ?J7nÜxñS¿xü?ùª ]yõ_nÝ·oß›ú "Ù$‡0úÚ$ h’c5Èl3Ç$¯1®9v¸i7À™#9•ÒS»hÉçìCòeªIf›IžGUÍø}ªI¦N­+ûÙ#×Í‘ˆ-QþÓGþ÷µH. »‘ìaFße&‹c½L0ýÔÚäÌÑ à‚£‡›~®å–ÇODd£„at/X²ì&ÄœI¦®If.ÚŒ"šAÙW®S²\Q0MV""»(ªZŽäd.}™yÏvV¹äH}œß }¼•‡ˆ&€ç7È1{X®Õçl7†§­bK}W!"";•à\ÿJo©GÖ†–ÏâÙN³5öG"š@Îõ®^"¢¢IoŽÙÞP'«\÷Af»2½8ÑD‘Ù¿²õ·óún> iˆh)è½jͼ›Ïèï±?ÑÄ"úD¡|îƒë@DDNWPÏ2û.<#á’ˆ& S’oS6I¼ðÊïÐÓÛ›uÛM×]‹Æƒ‡ð~Ý>lZ·‹ÖÚ2†æÖV¼þÆÞ‘¯½¥TUUbý…kPRRbË1Ós+Š‚˜S= K—,†ªz‚D”d¡Aré$Ï¿ô Ž?‘uÛM×]ƒš°û—O£|Z‹ηe §š[°û—OŸ÷ýi¡ ¸ç.TÏš)ý˜¢Ü5óæâ–¯lŲ –J?&MœAN2÷Þyʧï»Ð]yÙ%Øú…›pâÄIüø§ccö¼ð¾ºõ ¶s×÷¢´´­­íxñÕ×ðÖ;ïážïÿ~øßnj鶗 wÍç¶bù²¥¸ã_G0„#<øƒA}C#~õø#ãsÙ¥ØßØ„!]Ïë¸'›[ðÿö¾…i¡ .¿ä0|y ‹ÌǦõë²æžUY ŸÏ‡9³ª±qÝZüã„×ߨ‹Gwÿ߸å¿ìwôø ìo:·Ë…µ«W¡rÆô‘cÔÕ€ë¯þ Þ««GsK ÌŸÕ+—#‰àý?ïC¸¯×]ˆYUU£ŽÝÚÖ†ÆFİtñB,Y´(Ïÿ[SÛ¼¹s°¿± wíØ‰ûî¼ Š¢àîï=ˆ£ÇO`îìÙŽè1œAN2­míˆÇã#_ý~¬û665áû?øôž |oْŸçŽoÃëõ`÷“O£zVÕHƒÜó‹xõ÷ÀŠeK±zå€ß<ÿþø§wpÙ'?žõ®ÿªªââÍ›ò:îìYUxó­·qüä)Ì=K/Ä~ø¯8ãìÈûy¸áÚ«ñú{ÑtèàÈ÷Ýý <õëç‰DžÒRÜù­¿Çê•+p é {â)¼öúhikù™O~ì£x·®=½g’5~þ¾ÿÝ»° ¦ðÛ—^Á} CCC#?s套à¿}ù‹yuªºçöoaûŽpüä)ÜuÿN(Š‚c'NbæŒøÎíßïá(ü6r¨í÷=€¯}óö‘ǯŸ)ë~CCCø§=Œþh ÿãÖ[ðÐÎû±jÅ24<„§~½U••˜?o.ZÛÚqf¸‘ý¹¾Š¢ ±ébÃM¸á@-X0ê´þ7/¼Œ¶~ŸÝúU¼ðÊïP>mfLŸž×q5MÃ×ÿú+PUÿþÈ£Øýô3hïìÄ—?£©k˜sªgÁår¡½£ º®£¾¡O>»ëÖ¬Æ#?z;¶ßÁ³gñ“Çvú¹™•Ó±ó»ßÁW¾”¼ðÊï_Ç•—} Þ{7¶lÚˆA<÷ÂË’‹RÿŸŸaFEv~÷;رýL//Çž_FÝ yuªš^QÛï@õ¬™8~òŽ8‰ÊÓqïöÛ0sÆŒñ 2Áÿõ_ÊUW\Ž›®»fä±zŲóöI ÃÇŽ£­½[6mÀ‡·lƼysð×õ%Àûûö!6o\Øð Nµ¶àtw7>ñ±‹aêêp¢¹áp›Ö_8ªþ’E ð—W]‰k?s6®_‹ÓÝÝØö?ïB8Ò—×q-\€O_~)ŽŸ<…§žù Ö®^‰K/ùxÎÜç}_TU…Ç㪩xwß>@ii ž{éÔïß¿ßã'›GÕÚ´q=–.YˆO_þ©‘¿¤ŸúøÇ°dñ\õ§-ííH ½o¿]×qíUW`é’…X¹â\wͧ‡³ÔûŸ‰‰ðŸ¦¹Pâ>w‡ƒÛå†Ûí–~œBñ{’¹úÊËP‘y 2‹öŽ@e幩«gUAQ”‘ÓÉÍ×ቧŸEã&t÷ôÀçóáó7\ß½þÞßWÞ3Éý6®[;ªöÒÅ‹pãu׌|}ûÝ;pàà!ÔÕ7À0Œ1 Ÿ»þZ<ÿò«ÄM×_ E1wŸo×én bÁüä©p4ôôž¦%ßkeÍÊå£þrf*/¡£« FâÜ×`è: ½£3™exv $¯@wOö[®èœžÞ3øÎý;qª¹%yÍÀ©–Ü}ÿƒ¸wûø/6lSV(”\5li9w½íðÑãH$˜U•<•]T[‹Šòrìo:„ÖöN\¸j*ʧaéâÅx¯nú£Q”O›†µ59µdÑ8xgúú0w¸ä:.¼ðJ²9ÀO?‹íßÞf*ß3Ï=ؼ>Ù¼gͬ¬\vþËM×›ª%’z[ÛÚ±îÂÕ€C‡fWÉ¿¥i²¹ïÁ]#ÍñÞí·¾³c'Nµ´à¾ÿˆ]Ü;Î#´r 2óc·ùßÇÿ_4-ùoawO/ͯ…¿Ì‡·Þy¿û¿@kkžzv`˦@P `ó†u8|ôê÷ïÇú × à¢ ëÐÖÞ·ßy›Ö­…’ñÞ%F"C70tvšðÇ?½ UU±|éÒ¼ŽÛÒچǞxK/Ćuâ÷ëð‡7þ˜3wgW7::»PßЈýûO°çù—0wÎl\}å_ `ó†õÐ4 Ͻø2ö7 àäÉfœ<Ù<ºÖXÏiÚ÷Ö¬\xòÙ=hØß„£Gã•×^‡ªªØ´aýøÿ™pøãè±ãX0¿&9[ …P áÞí·aÁüšä½­vüý0‰3È)bùÒ%P?êWhnmÅ7ÿöfüÍÝŠ‡þíÇxèßÙïâ‹6ãò´éÍÖáù—_ÅÐÐÖ­IÎ’6mX‹Gÿ9bñ86¬_{Þ±ö<ÿö¤-¹\.|ñ¦° fä<®axè_ÆÐÐþ毶Âëõ¢®¾?úS\¸feeYóýýíÛG}ýáÍñÕ/qätººª _ùÒçñ>Ž;ïûÜn7Ξ=‹‹·\„o}ýf³O'`ÕòeøÌå—â×Ï¿ˆ;ïû€äuÏ­Ÿ»µÃYIìéŸýä¼ï•‡BØõ½ñŸ9¦d»°“þÞ©éò ù¡7áÇ–Ã>ØU¬AÒØ^|å5ôœ9ƒ«®¸ ^'ë>ÆþM˜7w6¬]hïìD}C#â±8-¬Å²¥KFýÌÐО|v¼®ºâ²‘ïÿê7¿ÅÀà ®¾òrxJK$Wuÿðæ[#û¨ªŠÊéX¹|ÙÈý†)¢ã¶¶uà÷o¼‰ª™•øÏù0à·þ„“§šqáªç/•;u¼Ù³f¢f^ æÍ©Îú´wt¢¡± }‘jæÍÅ¢óðûqàà!¼¿ïlX»‹.¼üÚïqº»g$c,dzϽ€Ó§ã“ÿé##59Цƒ‡á.qcŲ¥˜SýØ4~]°r€½ú†QqŒþø×óæ›lD4éÚ >ŶpZOD4!ðFq""¾›ˆH€owFD$ÀSl""6H""®b p‘†ˆH€‹4DD¼ID$ÀID$ÀID$ÀID$Pøm> .ÒÑäÆ$‘$‘@Á§ØÍ'ŽÊ‘ãÜ /úè'eŽƒˆÈqxŠMD$ÀID$ õc_#á^œîê@<ƒaè2KLU5x½^TTVÁ åõ3Ìaæ`;dæÐuCCCp¹\#ý[i ²³­ážnT×ÔÂY”Lº®#ÒF[óqÄcQ̨Êý‘œÌa/æ`;¤çˆÇà•H~lñ¸7ÈH¸ážn,^±.—ÔI©eš¦!4­~êàñú„ÿR2‡ý˜ƒ9ìžãpc=UCY h¹®”k§»:P]Së¸'-æraÖ¼Ztwv÷aŽâag™L9ªæÎGwW§”zR’ÆcQ”ùƒŽù¡?Dó±CÂíÌQ\Ìá,“%G™?€X¿”ZR¤¡yçG%2'äSsn×4 ºa·ç›á#f‡fNpaÎͲr¸£'LÍŒ³¾šœÛe刴ì3=63ü³WçÜ.+Ǿ7kzlf¬þÐ_äÜ.+Ç??x·é±™ñwßþnÎícå0ƒ·ù °A °A H\ŽrÂ…[c`y˜Cn «˜Ã,i Ò [2ÆO Åúa,¡5œ0æ‡9Ìã)6‘$‘$‘il©asÈ­asÈ­aUñÆÀ$‘@qW±m^þå*¶ÜNsÈÃæqID$ÀID$ÀE[jXÅrkXÅrkXÅE"¢qÇID$ÀUlj8a Ì!sÈ­1‘ÆÀ$‘il©asÈ­asÈ­aiˆˆÆ$‘$‘ßQ܆NsÈÃrkL¤1HiªªB7thjî i‰.çü e:ÔcÌ7Çožì¡eÈý'@VŽXIuA£Ë_qrxf.+htù+NŽå›.)htù+NޝmÛ^Ðèòg-‡Rªx¼^DûÂ2JÙ*Ããñ ·3Gq1‡³L–ý}}(͑à ) 2šŽÎ¶fº.£œ-t}í­Í”W÷aŽâag™L9:ÚZ˜V.¥ž¤BY „#Mûîí…n2ÊJ¡½=8ÒÔˆ`¨`H¸/sØ9˜Ãé9ÁiðçÈaF¶ÿ)ÃÉk”n>áÇ–hdWúÅb1Dúú ÷"ÂpÈ“§ª*<|Áü ¼^oÎý™Ã^ÌÁvHφ (çZ[ii)|eþmöè~DÄœ0À@òâæ¨ œÒV±½^/\.<> ]G Ë]Eªið”–Âív¹?sØ‹9˜Ã™9¤Ô•øRCÀívçõ$;s8 s8ËdÉ‘Þ(ND$ÀID$ÀID$ÀID$ u‘&îÅé®Ä£1†3n&UU ^¯•UyßÅöaæ°C!9ò!­Av¶µ ÜÓêšZø!hš&«´%º®#ÒF[óqÄcQ̨Êýúcæ°s0‡Òs Äcð‡ä¼’FJƒŒ„{îéÆâkàrI”Z¦iBÓÊá÷p°¡¯Oø/ sØ9˜Ãé97ÖCQ5”‚–ëJ¹yº«Õ5µŽ{ÒÒi.fÍ«Ewg‡pæ(æp–É”£jî|twuJ©'%i<E™?蘻êEü šngŽâbg™,9Êü Ää¼µ¢”ièF^×"JJJdNhpp0çvMÓr¾À>ß÷—4=63î\’s;sŒ¶½ÿÓc3cGÙ†œÛeåøÛúgLÍŒ®º:çvY9®|èNÓc3cÏ­÷çÜ>V3x›‘$‘$‘€Äå('\¸å£Ë­asÈ­as˜ÅO5´¡†ÆÀò0‡Üi <Å&"`ƒ$"`ƒ$"à"-5¬b¹5¬b¹5¬*Þ8ƒ$"à*¶ 5œ0æ‡9äÖ˜Hcà ’ˆH€ ’ˆH€‹4¶Ô°Š9äÖ°Š9äÖ°Š‹4DD㎠’ˆH€«Ø6Ôp˜Cæ[c"3H"".ÒØRÃ*æ[Ã*æ[Ã*.Ò;6H""6H""®bÛPà c`y˜Cn‰4) RUUè†MÍ=!Få|˜w¡ C‡šcŒùæ¸-Z+yd™rÿ `ŽÑî)]SÐèòWœÿ´ìŠ‚F—¿âäxæ–{ œ Ör˜!¥ŠÇëE´/,£”­"á0<Ÿp;ss8ËdÉÑßׇÒ9ÌÒ ¡éèlk†¡ë2ÊÙBׇÐÞÚŒ@y…pæ(æp–É”££­iåRêIj!”B8Ò´áÞ^è†!£¬ºa ÜÛƒ#M†Ê†„û2‡ý˜ƒ9ìž#œŽf(‚ï)H6O7€ÀðcK´?²+ý‡b±"}}ˆ†{Ga8äÉSU¾`þ@^¯7çþÌa/æ`;¤çCP”s­­´´¾2ÿ6{ô ?¢âÎ` yqsÔNi«Ø^¯.— Ÿ†®#á„å.Š¢@Õ4xJKáv»ÇÜŸ9ìÅÌa‡ÌRêJ|©!àv»óz’Ž9œ…9œe²äÈo'"`ƒ$"`ƒ$"`ƒ$"ºH ÷âtWâÑ Ã7“ªª¯×‹ŠÊª¼ïbû0sØ¡ùÖ ;ÛZîéFuM-ü4M“UÚ]×é £­ù8â±(fTUçÜŸ9ìÅÌa‡ôñü!9¯¤‘Ò #á^„{º±xŸ\R'¥–iš†Ð´røýl¨ƒÇëþ Ãöcæ°CzŽÃõPT e åºR®Ažîê@uM­ãž´tšË…YójÑÝÙ!܇9Ї9œe2娚;Ý]RêIIEQæ:æ®z ˆæc‡„Û™£¸˜ÃY&KŽ219o­(¥Aº‘×µˆhI‰ŒÃ ùsn×4-ç ì§ZŽ–~{ߟsvYYÎí²r¼Y_ozlf|hÕªœÛeåØùÐC¦ÇfÆm·Þšs»¬g‡Nš›n×¼œÛÇÊaoó!¢I'uÀêåç^L "*ªi(--µ^GÂXˆˆ%!é[â Ò nùÁèrkXÅrkXÅfñS m¨á„10‡<Ì!·ÆDO±‰ˆØ ‰ˆØ ‰ˆ¸HcK «˜Cn «˜Cn «Š7Î ‰ˆ¸ŠmC 'Œ9äa¹5&Ò8ƒ$"`ƒ$"à"-5¬b¹5¬b¹5¬â" Ѹcƒ$"à*¶ 5œ0æ‡9äÖ˜Hcà ’ˆH€‹4¶Ô°Š9äÖ°Š9äÖ°Š‹4DD㎠’ˆH€ ’ˆH€«Ø6Ôp˜Cæ[c"AJƒTUº¡CSsOHK¢ö~óX C‡šcŒS-ÇÌR{?ß{¬‹é²rlZvAA£Ë_qr|ó–› ]þŠ“CÁ¬‚F—?k9ÌRÅãõ"Ú–QÊV‘pO¸9Š‹9œeªä0CJƒ „¦£³­†®Ë(g ]B{k3åÂ}˜£x˜ÃY¦R3$5ÈÊ!iÚpo/tIŸI+ƒn÷öàHS#‚¡r‚!á¾Ìa?æ`;˜Éa†"øž‚dótpðð ?¶Dû#»Ò(‹!Òׇh¸ñx†Cž ]G Ë]Eªið”–Âív¹?sØ‹9˜ÃfsäKâK ·Û-upã…9œ…9œe²äÈo'"`ƒ$"`ƒ$"`ƒ$"ºH ÷âtWâÑ Ã7“ªª¯×‹ŠÊ*øó¼7Š9ìÃÌa‡BräCZƒìlkA¸§Õ5µðBÐ4MViKt]G¤/Œ¶æãˆÇ¢˜QUsæ°s0‡ÌæÈ—” ÷"ÜÓÅ+ÖÀå’:)µLÓ4„¦•Ãïà`C<^Ÿð_æ°s0‡Ìä0CÊ5ÈÓ]¨®©uÜ“–Ns¹0k^-º;;„û0Gñ0‡³L¥fHIEQæ:æ®z ˆæc‡„Û™£¸˜ÃY¦J3¤4HC7òºáî|[Æá„ÎVnʹ]Ó´œ/°Ÿj9"‡^5=63ü‹?‘s»¬û^ý™é±™±ú_ȹ]VŽÞ±ÍôØÌø»í»rn—•£¤´ÔôØÌȹ}¬fð6""6H""6H""‰ËQN¸pËF—[Ã*æ[Ã*æ0‹ŸjhC 'Œ9äa¹5&ÒxŠMD$ÀID$ÀID$ÀE[jXÅrkXÅrkXU¼1pID$ÀUlj8a Ì!sÈ­1‘ÆÀ$‘$‘il©asÈ­asÈ­aiˆˆÆ$‘W±m¨á„10‡<Ì!·ÆDgDD\¤±¥†UÌ!·†UÌ!·†U\¤!"wlDDlDD\Ŷ¡†ÆÀò0‡Üi R¤ªªÐ šš{B+_+ãp9ä~æ C‡šcŒS-‡§ö£.Åɱüc74ºü'Ç×nßYÐèòWœÑþHA£ËŸµfH©âñzí Ë(e«H8 Ç'ÜÎÅÅÎ2Ur˜!¥ABÓÑÙÖ C×e”³…®¡½µò á>ÌQ<Ìá,S)‡’deŽ4íG¸·ºaÈ(+…n÷öàHS#‚¡r‚!á¾Ìa?æ`;˜Éa†"øž‚dótpðð ?¶Dû#»Ò(‹!Òׇh¸ñx†Cž ]G Ë]Eªið”–Âív¹?sØ‹9˜ÃfsäKâK ·Û-upã…9œ…9œe²äÈo'"`ƒ$"`ƒ$"`ƒ$"ºH ÷âtWâÑ Ã7“ªª¯×‹ŠÊ*øó¼7Š9ìÃÌa‡BräCZƒìlkA¸§Õ5µðBÐ4MViKt]G¤/Œ¶æãˆÇ¢˜QUsæ°s0‡ÌæÈ—” ÷"ÜÓÅ+ÖÀå’:)µLÓ4„¦•Ãïà`C<^Ÿð_æ°s0‡Ìä0CÊ5ÈÓ]¨®©uÜ“–Ns¹0k^-º;;„û0Gñ0‡³L¥fHIEQæ:æ®z ˆæc‡„Û™£¸˜ÃY¦J3¤4HC7òºá×Ë8œÐÙજÛ5MËùû|s””–˜›ƒƒ9·3Çh%¥ý¦ÇfÆà@YÎíòrØû÷cp X?2=63n͹}¬fð6""6H""6H""‰ËQN¸pËF—[Ã*æ[Ã*æ0‹ŸjhC 'Œ9äa¹5&ÒxŠMD$ÀID$ÀID$ÀE[jXÅrkXÅrkXU¼1pID$ÀUlj8a Ì!sÈ­1‘ÆÀ$‘$‘il©asÈ­asÈ­aiˆˆÆ$‘W±m¨á„10‡<Ì!·ÆDgDD\¤±¥†UÌ!·†UÌ!·†U\¤!"wlDDlDD\Ŷ¡†ÆÀò0‡Üi R¤ªªÐ šš{Bó] ãp9ä~æ C‡šcŒùæˆöÛû9ÌcaŽÑ¢ýö~¾wñþ\M–¿74ºüYËa†”*¯Ѿ°ŒR¶Š„Ãðx|ÂíÌQ\Ìá,S%‡Rd 4mÍ0t]F9[èúÚ[›(¯îÃÅÃÎ2•r˜!©A†PáHÓ~„{{¡†Œ²Rè†poŽ45"*G îËöcæ°ƒ™f(‚ï)H6O7€ÀðcK´?²+ý‡b±"}}ˆ†{Ga8äÉSU¾`þ@^¯7çþÌa/æ`;Œ•ÃWæß`/€¾áG@ÀYC $/nŽºÀ)mÛëõÂårÁãóÁÐu$œ°Ü@Q¨šOi)Ün÷˜û3‡½˜ƒ9ì`6G¾$¾Ôp»ÝR7^˜ÃY˜ÃY&KŽ|˜½<±‰XøIDAT™@–i(‘ÃÔ»Æj‰Œ_3¿OD4ˆzXÎ^–Ï 2½s3‰ˆ&ŠlýkÌ>–ï)vzq}øAD4Q¤ú–©Ižh‘&‘å1ªAúÊüßàP‚ä­@.$nªéf»…ˆˆÈ©†—êSCHÞÂ3 †ì 2óqž|V±Ó›cê ï"y_¤É{$K†ki`ƒ$¢âKo:’½jÉ{cHÞ÷˜~Ïc^³Èl 2sÍ-}ö˜:èY8×áïiÃlŽDT|©~•š-¦zU|ø×TƒLÍ$3gŽç5Ì\3Èl§Ö©F˜j€©ï¹qnöÈIDã!sB—:ÅNÍ$‡¿—íT;+3§ØCH6ÀÁ´ï§f”©ÙcªA‡ô™j’ér£_Z˜ÓX 2}ʪ Ý¡ÓgpIDã#Û¢rª!žMû5Õ<Ǽq|¬Sl 8wkOú9~jÖÈæHDN ºó&uíQ´šU¾§Ø©¦˜yŽÏæHDN“­I¦7Ë1cJ®†¦dù5½fkŒlD4ÞÒ_)“Þ(3Ÿ¹ïyÆjhJÆï3›a欑 ’ˆÆ[æ­;é³Ål7† g’ù4´Ì}D³E6G"rŠ|ßœ"çi¶™¦&Ú—‘ˆœJÔóz-v¡ÍM‘ˆ&¾ 9ÊÿH]¶çWD5IEND®B`‚././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gtk4/images/layout_grid.png0000664000000000000000000002363615074674453022504 0ustar00rootroot‰PNG  IHDR,¨Z+ÓsBIT|dˆtEXtSoftwaregnome-screenshotï¿>&tEXtCreation Timejue 08 dic 2022 22:15:32ÝÝÇ IDATxœíÝw|TUÚÀñßÌdBÊ”L*„$$! †é *" XAQP¬¸nyÕ]W,¬®e×]uEeõu}w¤ (E@e-¤B %¡†’NH1@™™÷)Ì$“ÂdR†<ßÏç~’¹sï¹gÎÜ<9÷Ü{Ÿ B!„B!„B!„ð…—”)„ðNfOæ‰àR_¸„è¸ê TÍ `î•Úë)šøžâÊV; ™›ø^“\n0q˜ üîîv„ÞÇUp27ð»«õt9¤v R8LÊZ¯ë \Bˆ+[íàä8™j½®½|£šL\)[ r5IТãq¬LõLµƒ™ãúõòiB%êëQ©~ª€` ЬeKÀ¢ãp <5@P%€Ñ:™~:®« ‘ ÕXÀª¬l=([ò4@ŠeŸß;xÐÀ)(0`–%D‡§Àl6™KRwîYzï”)+£À,ÁLÁ¥ e \­ÆKíC@Ç@¥‚R(лýÁ„W43”Þ9qÒÿìÛ·oP \ĸl½.W‡ˆu4°{W¶ž•uòtƒ ñå²%sÍæ&Z !:0ŠšÛ&ÞýÈþýû·ç€j,A«ç±-¨'h5°\õ¬|±ŒQõ;yüÈç =+!DS)Jb»÷¸ØeŒË´\õ´êPÖWj­ßmAËv(¶dñ‚IH°B\³á³óîÂr‚N%¦¨p¾ªêéL5v[ã¡ KÏʸêÄñ#_(ÀÐìú !:³ÉT×£×}Àa KOË6¦U{ÞICcO®Î Ú—A¡0yö¶F!DG P* X:;jœß•4r¦°©×aÕX˜äÒ!„;Ì çCBÛç jJ«vÀò|¥s%„h_.ÅÇ€e›.kÐݦ¾ÃB•Gª,„è¨cIí[úê媇å*=Lí ¥ôp^.!DÇâx{_}ÁªNO«)·æ¸ºÑY%ñJÑ ŽÁÊU—ê X®®‰p Z2àÞFL&§²³9••Mqq ½ž^Wõ KDDƒëe9ÊŠ5_3yâ®êÑÝå2ß®[Ï/eeÜ7é®:ïíIÛÏácÇ\®7rĵtéÜðöÛÊŠ5ßà£R1ñö[Úº*ÂYíxâ*Þ\Öe Ž+;¢ÒÁj}YÙ9|øñŽ;^罿¼ø×ôëSïºÛRRÙ¹{/1]»Ò³ž€õßuë9•ÍkwÚ>¾úö{—ë%ÄÇѹ¬å«×àïçÇ Xí[¹ó.'[C­y²ZSAa!Ͻü/ÖpËØÑ ¸¦/Z­–³g‹8q˜Ä«{ÒÐwr×·Ù%‚aƒ5¸œ…«÷-ó{h*ýkÆÐÐ&”ÙÖÚ{ýÚ§‰÷?ÂÕ½zòâ3¿G§ÓPvþ<3ÿù!Ò±z邿__ãz¹{Ó²¶²?]HUU5Oüz7ßtã¥7z$pÝð¡ö—‡Žcï¾Üuû­>zŒ“YÙ DiÙ9J)ãìÙ³é-;žÉdbçž4róò‰‰Ælnü:,4„訮uæ·n=¥eç¸nø¢"#1™L¬úæ[.^¼È„[ÇÑ©S'Òátv5/Ò­[4I}zÛ×ÿiÛÏÔÔ>d)»vqîÜy’úö!ºk$yù¤8ˆÊ‡k‡" À¾Ž}®¾Š{ör±ú"“’ ið3TVV±gß~Μ)$**’IýP(d—v%:ª+‡ŽðÊoó·?Ï@¡PðÚ39qê4Q‘‘Í)Ú­¿Ü€ui#ò«ÕTTT°;ma¡!ŒyCƒmøðQ>_±ŠŒCGH;p€¸è(2Ožâó«Ðiµ$ÄÇSUUÍkoÍäБ£u i ü¢¢brróì¯UJ%#"Ðh4ügîBÌàﯼȺ ›X´tãFÂßÏŸ?žÃúM?9•uíÐÁ¼ðôSlÚºýÓùì‹ V«sã ¬Û¸‰ššV~õ5üã |}}Ù´u;GŽCåãCIi)þþþ¼òüt{õtù™²ssùÛÛ³((,D¡P`6›˜”ÄË/<#AË…¿üé9^þû[œ:Í+…BÁÉÓY„‡†ò꟞õD¸¬F—´0^àtv.1]£P*-—Îí;˜Nú¡#öe AzÆe}4ó=ô½Ž«z$yò”S™ß|¿ŽCGŽ2ðš~<úÀýdž<ÉG³çQ]]Ý`]æ,\ìô:$8˜OÿõO®6”M[¶“º{ß®[Ïâå+ˆ cÚ÷pëØ1 ê ñqÝ8[Ṫʶ”TŽ8AB\UUÕŒ3”ë‡áÛuX¿é'~Ú¾§÷k‚ô:f/\Ìé¬l¶§îdäˆkËáɽïäÆë¯eÓÖí,ûr ³,âŸoýÍeýÿ3w……¼òützöLà£OæòsêNvîÙËàýý.:šà`þþò‹– •• XzÙ¯¿<ƒðÐÐV¯ÛË,]¬VsîÂyÀÒæ¶vß{à _®ùƾL\·n}£ýý)wOàŽ[ÆÚß·Í·•±gÿ~îºó6¢ºv!ªkV~µ–ÓYÙ.¿[ÛœÆÝõÒ¡€¿¿¿}ùßýêadâãy Q*•üiúÓtòóÅŒ™øønDEuaÿÁ Ïb ¿ €ìÜ<ºÇÅÚË=ò:¢£º2åßôAú ®»ÖrÈ{Ó #˜¿ø òò œê8vÔHÂÂB¸oÒD’7oåÄ©Ó\(¿`?t´}îêêjÒA«Ñp43“£™™¨T–ð§²³4àš¦)ˆJ僯Ú×þZí£F­V·I –ˆŽ²ˆSYY˜L&”J%wß~+ão…Ñdäžy¡Î:>ꆿڢ¢"{囹F Âð!ƒ\¾l0pûø±,_õýú$Ò»×Uö÷ö¤ígæÿ¢S'_úõî±Æ€ÉhtYVPeœÍño"((£Éäb P(„…‡ræìY~);ç°**ª0™LÔd[k %× Jlttã¾*)ý…Wßx›ìœ\û˜Uvn.¯½1“×_ž!¨u3L¹°¤ƒÕj‚Cˆ £ °ï~ÜÈ­cG@`@&Ç?ÞúžGÝùAz=yùg8s¦ðÒ zC¹ë+×Ayy9¬ãTû¤säh&=âX¼l%UUÕü{Ö;éu|ùõZËø™«zÖWwWõqxm2™8yê4J¥’àà:uÖë´øùuââÅ‹<ñø4üýü.Sð·™³ìÁêõ—gðêßß¶Ž¾Ç¬7_oÕú4v/¡h ¿}ìaæ,øŒ9 >#íÀAdb¥Ãaáåè“xµ¥¼…‹ÉÎÍeÇ®=œ),lt½ââròòœ¦Êª*æ~¶„¢âî›4³ÙÌG³çb´ö ÊË+0›Í;žIEe%‡] ö»iÙª5äðÕ¿çÂ…r’úôÆW­@¥RQ^YAU•elîÚ!C¨©©á?sPYUEEe%»öîóX]®4'Nž"®[Œ¥7¥×cÐëyýåÄu‹áĩӭ^ŸfÊ¿£ÖÔ¿_žûÃÌYðkø‘µ?üh/"<Œ)wO éO7sç-ãø9uû¦óûç_B¥RÙ¥3YÙ9 ¬s-†EÎó^~î(” ÖoÚÂÐA™r÷ŠŠKX·q_~½–{'ÞÁÈë†óùÊÕ¼ñÞû( ‚ Aµêéê‘v®Þ«»Î†Í[ø1y3`9,}ìÁûìïõ¾ª';vïåÁß<Á»‡î»‡SYYlÞº-ÛSKÏìÃwÞ$*²K½Ÿ»£ZµxžÃ+K›ô:f½ùW§y­¥ƒî¢µ];t0ý“úrôx&§³sðUûÙ™ž ÝñññÁ \Õ3)“&Ò£{œÓwT{~``3_…»öRVVF¿>‰(UJ¶lßáò»íŸÔ—€Àï@—ÈÎL?Ä”I=òzÌÀƒS&l@©Tb4™˜|÷ºÇq*+›Îáá HêËêµßÑ-63pýðát‹C§Ób”*S&MD§ÕÚëÓ-:š)“&Ò»×UNu|íOÏq*;M@û'¡Õhìï?óÔïØ´e;F“ &½^ÇÛ¯¿ÂÞýÈÉÉC§ÓC—βO{W×@8Þ7hKØç‡%á–Ö: ;vøà¬Öª¤®¼ùÞûìÜÆÇ¼KXhËŠö%áªÞÓŸ±<=çPTâœ*¹Îˆ© º ïÕ„âÊ"cXâ «£ë°„×zéÙ§Ûº ¢•É »ÂkÈ–ÂkÈ–ÂkÈ•îB¯!Ká5dÐ]á5š1è.!KѺäPá5Üîaåœ>áÉz!D£ÜXC¯ Àù²RŠÎž¡²¼“ÉuöHÑtJ¥ ‚Ã"Ð蜳9J[ oÔÐ>}¹šukNa~.e%Åt‰‰E£Õ£R©šUF£‘óçÊÈÏ9EeE9¡–MÒÖÂ[Õ·O»Ãí€u¾¬”²’bûáã#·$zŠJ¥Bd@£Ñr4}~þ€YÚZx-×û´{ÜÞû‹Îž¡KL¬üµ•£c)*Èì0K[ ¯ç¸O»Ëí¿€ÊŠr5º&=-X¸G£Õ‘sòfÒÖâŠ`Û§ÝåvÀ2M2ŽÒÂT*•ý‘VÒÖâJà¸O»C®ÃBx XB¯!Ká5šyÚI[´µÍ XrÒªõH[ ÑNB±!yÇ33ðññ!<<œÇ¤oÞeü­©¼¼‚5ß|Ãø›Çb j|Ñ$Þ¾oœ=[ÄÞ}iäœ!®[7®> …ÂÕã@ES´‹1¬õÉÉlÞº•òŠ ÏžeÙŠ•Ü1é^Òöïor&“‰Yÿû!%%¥Nó¿X¾‚´<]e§í®þúîšrŸuû%-¶­ŽÈ›÷/¿úš©Ó¦ñÍwßsøèQ^~ýoüþÙç05ã´~G×.zXý“’xúÉ'쯧Ïx‘9óðá{ï6¹Œ¥Ë–3iâ †K=œ7nDíëKRŸ>­/@Uu5Ó~ó[Ôj_þòòKüñù߆ðÎ} ¦kW–ΟGHˆå©Ô'Ob꣱=e#†k‘m^éÚÉ »™ÚÃ=êFœïê䫿¥ž§OâÕÖ®~K=Ô³£byç¾0h ­>–zÆv‹¡{|,§³²1|¨çš¨i‡„®¤Ê ŸÃ¾õÉIݽÛi™y‹Qp¦¥õJp¥Ri¿*\©PZ*P©Tö±ƒÃGŽ2õái¬ON&ãÐa~óÔøøÓ¹örÞ±ƒ'Ÿ™ÎÌY³8•Í’/–óÈã¿¥ªªªN=mÁJ´oÙ7\)<[LxX˜›Ÿ\´³„fØ0OæÎ //ŸmÛfÕ²/.mÃúO¶Î6­ó~`*ÿ÷Él&Mœ@·˜n3šå«V1bØ0îšp§½Îo½û“ï™Ä#Làö[ná©éÏ2ö¦›ˆ‹3ôNLdÖ?ÞàÂ… Ü|Ç6oÝÆ˜Q£þ(®êèö,á´olOI¡ºªŠ¡ƒuÜï³™ÚeK§Ó¢ÑhyéÕ׸pá‚GË..)á`zw[wR€AЫGvíÙcŸ§ ÔØ ¤oïÞäæå{´.âòyë¾QYYÉûÿúˆ§ÞO`` GëÝ‘´›A÷¾‰‰üzÚ£ö׿zôî™úk¾YËÔ)“=¶¼ü||}}Ñj4Nó###)*®ÿ _@`€dKh#W¾ñ··ÞÆd°÷Ü„{šÙÃ2{hª[žVHÿ~ýÈÉÍÌ( ***\¬×Ðëºe‡ TWWST\ä´\qI ‘]:×[w?GK´MÇšê~~oÛ7fÏÇôtÞøË+(•ŠËZ÷ÊœÜ×. ÁríÌéì,º'ÎÏ©©ö÷«ªª0/]Ï¢P(P«Õœ9ãTN'ßNNóÂÃÈŽêÊ’Ï—Ùç8y’CG3tð –ú8ƒ¼ißXº|+V¯æ_ÿ|×~yƒp_»9$LÛ·Ÿ>ž @Ee{÷î#$$”;nÀ„;ncÅêÕüþÙçéÅŽÎg… Æ fæ¬5òn7–¸ØX®6„Oç/¤²ªŠþIIŒ¼~3ž}†~•Ì“'ˆˆˆ`Óæ-<ýÄrö¦òÖ}ãû×óþ‡1dð V­ùÚ>_«Ó2í¡›Ñ"—«¬p ‡Ii]ÆP¬SÔoŸ6.,"Ò#•P(h4T**•Šððpn¿e<=üJ¥¥¨Óé?f,f³™ÐÐ0~÷ø¯è™@÷îñX¯yÃõhñõõ¥{|<š@ }{÷&..–š‹éGhh(]##7v >>j‚ôA<þè£ :Ä© ¢£"éÓÍaŽ‚„øx"Â#êÿÀ€k®ÁÏÏÏ#íPX €§ÚÚÛxó¾QPXHt×®D„‡£V«íS@` }[¸åگ‚\>ùtÞ÷@6Pm.5€É:¹î%’¶¢K©Tb4Q)¥“ÖRL&£ýÔ½´µ¸8îÓîp{M?ÊÏ•¹½aѸóeeøùH[‹+†mŸv—ÛK«¡0?“ÑèöÆEýŒÆ òrЂ¥­ÅÁqŸv—Û‡„Z½ž‹Õ•dÉ ¼K:²x€ÑdâBÙ/äå ÓÐê,[¶Þª¾}Ún,µZ΂ÒÇ—’³gÈË>)Éõ=@©Tâç@PH­µZ m-¼V}û´[e5§"þþþ¨Õ*Œf£œÅò³Ù2À®V«ñ÷÷·Ï—¶Þª¾}Úͺ¬¡0?—²’bºÄÄ¢Ñêíù²…ûŒF#çÏ•‘ŸsŠšê*B#ºÒÖÂ{Õ·O»Ãí€u¾¬”²’bûáãÓn²Ôx=•J…>È€F£åhú>üü³´µðZ®÷i÷¸½÷=C—˜Xùj!*:GÇRT‡Ya–¶^ÏqŸv—Û•åh´Þñ¸po¥ÕéÉ9y ³5:É)/¼žF«#çä1·×w;`™Œ&Gia*• £õl ´µ¸8îÓî|XB¯!7? !¼†\.-„ðrÚÉkHwV X^B¿…€%Ú¹ É›8ž™ €áááŒ>Œ ½÷]Rc4Y´d)£FÞ@·˜˜¶®ŽW’1,Ñ®­ONfóÖ­”WTPxö,ËV¬äŽI÷’¶“Ë0™LÌúß)))ušÿÅò¤8àé*×kÎü|ôñ'œ XÂë¤Ê _Ÿ>ö×ë“7’º{·Ó2ó-¢àL!Jë]J¥Ò~Ç€R¡´þT R©P(,A?|ä(SžÆúäd2æ7Oý?k/÷ç;xò™éÌœ5‹ÓYÙ,ùb9<þ[ªªªê­ïý›ǑԷ/ÍýƒíèdÐÝKtس„fØ0OæÎ //ŸmÛfÕ²/.µ‰õw6²Î{ø©üß'³™4q‚}°ûæ1£Y¾j#† ã® wZ7Ã[ï¾Çä{&ñÈS¸ý–[xjú³Œ½é&âbcÁ ½™õ·¸pá7ß1Í[·1fÔ¨:ÕOÙ‘ÊÎÝ»Yøé{ýÌ®ê*š¤™=¬¶îZv„I8Òé´h4Z^zõ5.\¸àѲ‹KJ8˜žÁÝÖ0hàzõèÁ®={ìó4ûïôíݛܼü:å•;Ï3ßáÕ—^¤“¯/ ª¹¤‡%Ú½¾‰‰üzÚ£ö׿zôî™úk¾YËÔ)“=¶¼ü||}}Ñj4Nó###)*.©w½€À—™4Þ™5 ???RRw’’º€’ÒRÖoÜÈñ'˜4qzÎcõï$`yŽþ¯ùÒç×jé߯9¹9€…BAEEuÛ¨vOµ¾^«e^ˆÁ@uu5EÅE„_z²KqI Ç ©µníßë–ݳgbb¢1kœæ›L&ë<éE_.¹ùYx“ÉÄéì,†@Dx8[¶o·¿_UU…Ñx)…‰B¡@­VSpæŒÓ›|;QpæŒýuxxÑQ]Yòù2~ÿÄï8qò$‡ŽæõWÿ|Ùõ|èþûêÌ[·~#cGfäõ#.»(Xþˆ<@¥R¡2pU~).â|Ù/ÒÎ-ÄU[»«],K‚¶lºw, Ú~¶¦˜…†´9ª?AÛöy¶mC_~6„ü‚ª««æ¥ìH »µîžPtö ]bbññiâ+ŠÊLJÎѱž‘vnaŽmí®6¿Òl Ú>´…X´™´=W+A›e4^¡Àš íýf$h ­õyjÿn¦öç]úÅ2Ö~÷}ûö!8È@ÆáCdeçòâóÓÑk5kŸÊŠr5ºK…û4Z9'aV íÜÂlmí®6ÿWrÓ(çma¡¡Œ¾ñR‚6€è¨(>_0ŸÍ[, ÚyðvïM#<üRÈ7_·&h«¨´ìM2™è¨(NgefO2hKÎ#e‡%AÛ”I–m6C‡ ¦¢Òùðsܘ1t‰¯S÷gþð#—0°ÿ5 <È£cW&£IOZJ¥²_*"íܲÛÚÍJà×ûI*×Òîµ ÷0´kreÛ¿;vn ûw§¸À¯]Ža !„+°„^£ÍǰDSÉ@pëvnÏ$`y 9qÕ:¤Û7 XȆäMµ’%†{U²Äå_®¢´Ô9çYÏ=yýumT#×¼½mŽ;FzÆ!*++¹úê^-–¦ér4k Ël–©¥'OZŸœÌæ­[)¯¨pH–x¯W$KX¸d ™'OQ^QaŸª«Ï¢ÑÚ¼½«ª«yý·xú¹çIIM%eçNž}áOuR<µH3,òIDATéau0u“%¾Èœù øð½w›\ÆÒeË]$KÜØ¢É*Ë+˜:e2}{'¶Ø6<Å›Ûyμù²bÉb§ä”í,¯á¡\>µ.m»/\¸Àò•_2çßào¯¯Â~ÅfÛ®f^Ö`–©Å§–å-ÉF#ÕÕÕ$oÞÂÂÅKY·~ƒÇÓµ$oiçc'NàççG|\,Ó3XºlÉ›·´›ükÒÃò=Ybee5®¹†Üü|T*_­ý/ï¼ÿÿœù6‰½zá)½ssó áíYï“yâ ñÝY´d)+׬áƒwfÚƒd[‘ G;0oJ–àÏ>ü€—g¼À‹Ï=Ë‹п_?Þ|»é*i+ÞÔÎÆšŽÏ$.&†Oþõ!/Lÿ#‹æÎaÿƒlݶݣuw‡¬Æ–,ñ×ÓåO=É¢¹s8rìk¾YëÑí´T²D¥RÉý“'sôøqäJó4omçÐÐPüüü˜|Ï$û¼`ƒÁpøèQÏUÜM°¼†'ÇÃ.ÍÓj­És³C²ÄÚë5ôºnÙ!ƒ5Yb‘Ór–d‰ë­ÏåLJ•e,G­öi‘¶éˆíÛ-šòòrrórëlWèáö¹|°:8K²Ä,º'¶d‰©ö÷›Ÿ,q™}^s’%þrîœÓãÖÌf3+WÅ5Iý¼"áž·´sDx8C‡ bö¼öyÅ%%ìÚ³‡þý“X³u´ÿoZx”%YâlÀ1Yb¨5Y"ÉŸ¯•,ÑB¡PX“%~ÐŒd‰auê՘ɛøà£3°Á†`Ò32(¯¨äƒwg6¿QZ€·¶3ÀsOÿ'ÿø,ÿÏSÄÇŲíç&ß3‰ž ÍjOp•­LsN,—òbu²NQ¿}|Ú¸°Î‘­UÏ«° €°ˆæ·µB¡@£Ñ R©P©T„‡‡sû-ãyìá‡ì×étŒ3³ÙLhh¿{üWôLH {÷x¬×팼áz4øúúÒ=>M †¾½{KÍÅ‹t#44”®‘‘Œ;5Aú ôQ†u|f£‚è¨HºÅts˜£ !>žˆð§º÷êÙ“ëF\K'??üýü5r$|êI C³Û °Àòü€ŽÞÎzž[Çä§“ŸM½ñcÇ4»]l rùäÓyßÙ@µur̃eË…UG³ø%& ô؇®¥§í 1I’%¶¤ô4K¢Diç–—ž¶Óí~rHè5š7X)šJÚ¹=kû'? !Dµ‹§æ!DSÈe B¯!cX^B¿[‡´sûævÀR*•M&TJ餵“Éh? n4¥­[ˆ´sëqlkw\îšöëëýüý)?Wæö†EãΗ•á瀴uË’vn=¶¶ÆÍ{u XæZ?íóµú ós0—³=ÑDFc y9h ÁH[·içÖãØÖ¸ˆ)µ~ºÔ”CBÇ‚ìW¡jõz.VW’y$ƒð.QêtÒ•ö£ÉÄ…²_(ÈËA§7 ÕY\ míYÒέ§ž¶vŠ'ÖEím5u ˱p#`T«Õè !(}|)9{†¼ì“í&+¡7S*•øù†F«C­VH[{˜´së©§­Ö©Á[qj«/`¹Ê á°5Ïþ€/–Ûw|°bÚþ%µmjB!D[² [ܨÁrÛM5Pë€Õhš¦ÖÞèn,÷úc¹ÏÐ×Z– XBç€eÄ;ª±Ü/XåÞÁ&ÝðìÈUÀ2s)Ø8ö®l½Tq)0™¬óTÖI+!Ä¥øaëMÙbG¥õ§-`ÙzZ®²:i¨‡åêPИlÉ6OÍ¥Þ•,!ÔíðØ m=-[ZW‡†.]Î!a –€Tí0ßÖã²õ®lK!À9`Ù‚–càªÁ9Lƒ XŽ]:…uCà1Û“ÿ !:6W'ílê¢ÃO[0kôBÒÆ ±nk¶ù¶ ØzU¬„®Ôw¥m쪾³….5õФj“J°B4ÆUÐr ^*›†ŒÂÅOÇàä*PIÀBÔæê™e&¿×^¶ŽÆŒ¢Ö﵃Sí^•,!Dmõ=ÑÕëÚË;iJ€©½L}½) VBˆú4õfç /'ÈÔ·¬*!DSÕšt/¡»ÁF‚”¢¹$¿«B!„B!„¸âü?¸Ö_Á‚HIEND®B`‚././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gtk4/images/layout_headerbar.png0000664000000000000000000001613615074674453023471 0ustar00rootroot‰PNG  IHDR¬wQ´sBIT|dˆtEXtSoftwaregnome-screenshotï¿>&tEXtCreation Timejue 08 dic 2022 22:14:47ˆJØê¾IDATxœíÝy|Se¢‡ñ_––Ò…¶PZ–ʾƒ²É""‚²) ¨¨è8Îr¯:sïuÜ÷gtÁQ\FFD6dAdkKYl‹º'¹¤IÓ4)iiiÞöùòɧô¤999…óä=ç$‘PcCæ 0«.gVq 6ÂMS°PQÀjÿÛYB¼ÐxùÉâu!©iL…ÉRÍßk{?³Š“«š¿º]µjÿY|.V¿ïƒ… ÐxùÇÉ÷âôûÞÿçO+Ô˜Š”'T.D š–@±r¹øÇÌ÷öAÙCXˆ`#*›ÏW›¤–’’$µÔ¬|Þ šßð”I*–”/阤L ñ¼ßn8ûdÙrå?®©“'ªyT”wzN^ž–~¶B©íÚêüáÃêå¾—,]¦ãùùºfúåg4Ïc$«Å¢øøõêÞUÒRëb1½²²³µzͺ€×õìÞ]çôëS§÷WWÞýà#Ùm6M½tbC/JƒrþµºÝ†ÏWÕñ’4 g¬úíþ²+t0#CƒTqq±V¬Z­'ž~F/>÷ŒôëÒ<œN§žñ%Ýtà JLLðN_°ðõìÕSúö­¯Å¯%óŸK-YºLûÔÅVó¨Š<æääjþ;ïiØ:øyõrßÿ^ºL32uÍôig4Ïcð7eòýìúkÏhÞ¾2³iþ;ï¼nÚ¥uN¿Þuv_uiáû¨yT”¦^:¡¡¥‰0»PWÂv„%Iç ;~}«÷û»î¹WŸ=G~æéçñÖÛ 5}ÚÔJÁútùrEDF†a°NfÿõϲZ¤µ6éå¿ÏÖ‡‹—èªË§(.&¦NïgÔˆaºúò)•¦ÅÆÆÖé} ~4¦‘Ò´koT¯žÝuï·«E‹’¤ü“'5ë¹?ë›;õþ[sx Ï$XÕF¿.žTý¯!ƒjÉÒ¥ÞiŸ­X¥øq4ð\ïÏÌþç\Mž8^­“’ôúœ7$Io¿»H ññºþÚZ±ús>rT«×¬QNNŽÆŽ­Î:I’ŽççëË/7(ïxžú÷í«Þ½zzçûå†j™˜¨²2‡¶lÛªèèhs¡b¢£ëà±ú<äÆÂÿ#Ø\§ÿ“«­ÛwèTAzwï®.Ó½×ÈÈÔî={•ò¤RZ'iÈ sQñf N§S7oѡÇ•ž–Vñ"Ëçÿî‡)½CuNï¨ ›7«y³(Q±»2ÒnWtt´Æ_4F-YªŒÌ,9K’Ë}ß;vîÒÁ¬,••–ªc‡4 è[± oõšu:yê”ÆŽ¥ _}­OœÐ˜Q#+í&õ,g‹ØX¥µo_enúz‹vïÙ§î];kà€þÞùfeÖ𡃕־Ýi—¡ÌáÐð!ƒõå¦M:qâ¤ôë«´öí”}øˆ¶|³]v›]#άèòÇ;wïÑw»v벉ãõ寝t,'W½{vS×òÿ#•ø¬g—Ë¥-ßìÐÁŒ %ÄÇkèàŠ2ú=ðÂè?ãYZ”´Ôöúvç.ýáÑ'õÈÿÝ#‹Å¢þ8KûTj»va±JÂz„åoÇÎoÕßgT´lÅr¥¥¦V Öëÿü§¨ÖII²–¿ZÝjµz_¹nµXË¿Zd³Ùd±¸ù}·k·îüŸß«oŸÞj¥ÿúŠn¸îÝüóŸI’Ö­_¯ÅK>Qû¶mÕ«gO}õõ½1÷-Í}ýïjfôÌú‘‘‘¥ü'¼ßÊ>\ågÖmبçÿòŠŠŠ‹½¿‡ëg\©éS.ÕòÕ_è…—_©ôómÛ$ë™GRtt´Š‹KôÀã³´s×î ËPÝü%iáû*¥uký˜Ÿ¯ã?æ«wÏî•‚å‘}ø¨Žýðƒúõ饸x÷3Ï—^ý‡–­\]éçFœ7DÿsÇm’¤•kÖjûŽZ¾úsíÚ³Wv»]ãF ¸œ'O(+;»Ò´6ÉÉJm×N³žQ‘ö½ôÜ,Ï;®çþò7¥µo§+§^Ò2lÛ¾Co.xG9¹¹’¤ˆˆ»ð-]¾Reee’¤wÿõ/½ðÄcŠŒŒÔw»vëõ¹óõÙªÏu #S’û#/nšy­¦LpùKJKõȬg´mû·²X,r¹\jݺ•žzøA%”¯/„¿ÿ[Ý÷èã:‘©?<ö¤,‹öÌPrR’îÿýÝ ½x’ê)Xur†KÚ¶}‡^ùÇlIRvöa­Y»Nï½½ bþåÏÖ«Ü_ù´ŸÌ¼NyåUMŸ6U;t$]2n¬¾÷žF¦Ë§Nñ.ïãO?£«¯œ®g^'IºtâDÝv×ݺø¢‹Ô)=]rI}z÷Ö³O<.I:uê”.¹lªV}±FãÆŒ©ƒܸ<øÄSÕ^òd^|õ5ÅDGë™?>$›Í¦‡žxJó.Ò%cÇh`ÿ~ºýW¿P÷ÎUæthÞÛ‹´á«ÍúÏò•š6y¢>úd©vîÚ­Açô×Og^«½û÷ë¥W_WIIIHó÷ìÖ;‘©!ÏÕ˜Q#•˜Pù„žoù,’Ê9NuëÚE.—K‹E“.§Á瞣Î:ꇜ\ýùo¯iÍ—´gß>ïh¤°¨H……Eúï[nVTófŠŒŒ ¸.V~±F+¿XSiÚ_Ÿ›¥6))šyÕtýãÍ·4oá"ÌÈÅbÑßz³ìv{HËP\\¢ ãÎÓ¨áCõñÒÏ´låj­^»Vwüê—Jˆo¡Wߘ«ƒ™Z»a£Fá½ÿ¤¤Vúíí·ê`f¦^xùU½¹`¡FVeIÒ¢kÛöouÕ´)ºbÊd}üɧzcÁB-ú×â:=æw6…º :jt­æ¿~õÊZÝ®>µjÙRÞw¯7Z’Ô:©•¾ï%'%5ðÒ¹Õ:X®³<>lÑ"N±±qúßûÐ<¬˜:<Ž›—§í;¾ÕŸ|Ž 4P=»uӦ͛ÝÁ’Sq\!&&Fýúô 8r¨­³½NëÓ”IÝÜç,ÁÜ<-]¾²ü9†K»¾ß£“' ”Ò9Ù{¦\LtŒŽ£Ê:tH=ºuÕ…çЮ={”™uXññq’¤¬CÙrÉ¥ÍÛ¶I’.Ÿ2Y©íÛ*µ}[½ûábÌÈ yþ’­ßßu»¬V÷ÈÛ÷wpÙ¤ñŠ´ÛUPX¤ÕkÖjÑÉ*iæŒ+Õ¹sG¥¦¶Õ¶íßêØ9jÕ*Q‡Qæ¡lué”îÇ¿¾YÒ;V™·¯n]:kÐ9ý+M‹‰‰•K.Mžp±V­Y§%K—I’®»zºÒ;¦É%WÈË0vôùJKm¯WLÓ²•«•Ÿ óG¸O|¹è‚‘š=w²‘«ü$Z¬ëf\]g÷“}ø°"##çw »]»vÊÉÍ z»è˜èÆüæ”gdêäñj™˜èý~מ½Zº¼âYeAa¡ûkA2¹w‡µIIV›”d%$ÄëØ±=ðø,åääj@¿¾²ÛÝ»t÷§gçääHRàc+!ÌßÃjµycåoúe“¼ÇvÎíßW=ñ´¾Ü¸I3g\©Í[¶iÖ /ªY³HõïÓGŽ2‡$ÉépTšG(QѽKgÍrf£ÕjÕ ×^¥›¥æQQš6¹â̼P—Á#!¡|÷œËwšûd$‡Óànm’[K’ŽŸø1àõ’¤ÃGŽ(¢üãùÃÏ«ÍÆ*GJµ•wüGÝÿØ“ÊÌ:ä>f%)óÐ!=ðØ,=|ß=G×g[=«.7âóŠ‹Ñ¹ýû+ëP–$÷®™ÂÂÂ÷ç†ÿ•çÝ*1Q%%%ÊÉÍQ«–-½×ææåiø°¡~·õÿ{°y£:m’“%I-âZèîÛo©r½çYÿoók6D»öìÕÚõ½×'ÄÇ+ûðQ=vLi©UOX8Ýükª[—Î’¤ãù'%Is¾«ââ½üÜSJˆo¡E.®öxÚ™øè㥒ܻò©¦•¿þél-Ã÷ûH’’“Z¼>%%EYÙš0î"Ó¿±œyÛôþO?2ëYo¬¾ïIÒý>©ÌC‡ôÈ“ÏèÙÇnà%<ýÇ‹ç r©GN§S33Ôµ‹{wNJr²ÖmØà½¾¸¸Øû \r,ŽˆˆÐ‘£G+ͧYd³JÓ’“[+-µ½æÍÛ;mßþýÚ¹ë;7dp}=œª‚­S“.Õ=ŸëÒ;¤©mJŠ¾Û½Gÿ^ò©œ§rsóôíÎÝ’K*,pöîÛ¯’’RmýfG¥Û÷íÝK’ô÷9s•™uHë7nÖÑ£ÇBžµËZÎápÊép*/ï¸}¸X’Ô·WÉ%œ*”ËåÒž={UXX¤ï<¡e=øýÌÉ“§”u(»Ò%ÿÇ|É%­Xõ…6|µYÆ]¤Ä„½õÎ{:rähí—ÁšOûxégÚw C›·lÓ¶í;§]»H.÷Ç^ª¸¨DrI#ÊÿÌ™·@ÇŽåÈépjÇ·»t"ÿDÃÿ{<“Ãáâ,=î}û¨SÇîÑT|¼ããõð}÷¨SÇî×%†Á:ë]‚[¶nÓK{U’TXT¨¯¿ÞªV­’tÙ$÷n‘©—MÖ;￯Ûïþ:¦¥jýƯ*ÝÞb±hØÐ!šõì 3úM±:¥§kİ¡zmö**.Ö¹hô¨‘ºçî;uÏÿݯ½û÷)%%E+W}®;n½UÉ­?«Ä™±Ùlºýæ_è©^Ô«o¼©×çÍWYY™ããõÚKÏkÔˆóôéÊUZô¯Åzï£+..®ÒgM™8Aë6lÒÖí;tûïþW6›MíÚ¶QFfVHó÷œ5XŸÜ|[¥ïÓRÛë—7^/I}þpÍ÷}=öŒ{^-}^çWS+׬ÕÊ5k+M›6y‚.›8A¯ýs®ZµLÔ×ÍPÏÝôüKÓ˯Íу÷þ®N—Áß÷ûöë®{ÿ É}fám7Ýà=%¿OîZÿÕ׺þ¿nÕÓ>¨ GÔÖí;´âó5ú¯;îVDD„JKKõ«›nÔøqû„¤¡£.¬ÕíÖ¯^Q§ËQÞ›;»Ê´Äøx=ûdžYyÔË;]ÔÅa‹.¼ÐûÖL’”””¤‹FÖ¹xï#µ}ªÞš=[«¾øB‘‘úÉÌ™ÚüõµnÝÚ» =ô þ³ôS)*ª¹\.éÚ«¯Vjjª2f¨uR+¹\ÒAƒ5oÎëúrÃF•••éê+¦«SzGï|†¢¢¢ÂJmüØqj“’\‡ï;ŽOïjfÂØ1ÊûñG5o%ßÇ“Ô*A×LŸ¦Ôvm¼Ó{õèª?=õGmùf»Žý£¶)­Õ)½£,©oïžzú±µuÛvÅÆÆjè s´vý¦òÓ¤]Ši®YÿA6}­üü|õïÛ[V›UŸ¯]Òü%—®œz™lV«ü×»ç1xÄÄD«}Û¶зwùñ.—f\1UݺtÒŒL¥$'kà€~ú`ñ¥§wäÒÇ©k§tÅ·ˆ­2öíR‚¾+Gn]•‘•©K'\¢~½{)ªY¤F¦¼¼ã*..Vn^n—Áf³êšéÓç]¦ô´T]3}šúôìQi96óE6‹T™£LúöQ»6¿·;oû•V}¾VeN§âb£e±HwÜòKMºd¬¾ß·_.¹Ô¹cºÒ;¤}ìᮾM×lþf®Ãúèi¦ï‡5Ú%EHŠ’-)®ü2ìûï¶?h†ÇssÔ{ÀYÜÖHìØ²Q -[5ôb ‰û`ñÍž·@¿¹ùsÁȆ^œN۰ƺ]èÒ£Ï]’ÖI:Q~)T$©TR™$§ì@<ƒÓÚk-c­!\„ëᜳ'|}ø,IëýIœEõô^‚¨Ö)Ø”I4¥ü¤&þ=† ~^aûñ"Më€?¶ áû^‚Ð@؆…§º–Å"‡ÓQ~º0Bát:Bz]€³ L¶alªªó³mV› Nä+.¾î^ÄØØÌÏ—Õjcà„pÙ†±]¨ªÎOº°Úì:v8K1±qÞÏ£BpG™ŽdgÉj·³«á° c»XŸt!«Õª½»¾UrÛTÅ´hÑàCëpäp:u*ÿGÉÎR³¨ær¹<¯“ÐrÆv¡zu~ Ën·«¨¨XN—K‡³Ê‘áàf ‹lV›dµ¨´´TQQ|j1tÆv¡Zõr–`TT3••ÙT\\,I|fT‹E²ZÕ¬Y³>3 ÀÙÓPÛ0¶ Õ«·5b·ÛYáŒÅ6,üpp `„ÚŸÖÎn>ÀYÄ `‚0B­w fÜW—Ë@µj¬óF­Ëå Zì`Œ@°F X#,€À `‚0Á`Œ@°F X#,€À `‚0Á`Œ@°F X#,€À `‚0Á`Œ@°F X#,€À `‚0Á`Œ@°F X#,€À `‚0Á`Œ@°F X#,€À `‚0Á`Œ@°F X#,€À `‚0Á`Œ@°F X#,€À `‚0Á`Œ@°F X#,€À `‚0Á`Œ@°F X#,€À `‚0Á`Œ@°F X#,€À `‚0Á`Œ@°F X#,€À `‚0Á`Œ@°F X#,€À `‚0Á`Œ@°F X#,€À `‚0Á`Œ@°F X#,€À `‚0Á`Œ@°F X#,€À `‚0Á`Œ@°F X#,€À `‚0Á`Œ@°F X#,€À `‚0Á`Œ@°F X#,€À `‚0Á`Œ@°F X#,€À `‚0Á`Œ@°F X#,€À `‚0Á`Œ@°F X#,€À `‚0Á`Œ@°F X#,€À `‚0Á`Œ@°F X#,€À `‚0Á`Œ@°F¨i°\>j£V-9]°\~_ý§PSÁšRm[BaùÎÈY~!X€Ú Ô“Óv%Ô]‚¾3w”_¨ OGj4²™î p©¬è˜Ø;%5—))¢|^VUDÐR›G0ž'@žn”I*•T"©Pƒå©"X°üïØÿN¿’-w°¢äŽ–]’M š:ß`9änG‰¤"¹ƒU wKÊTƒQV `¹TßÑ•çNK%«"LÎòi¶ò‹EÄ š:O?<£)O;ŠÊ¿z‚åiù¬ª¬ºV ]ž0y‚䙡ŠÑÁøx<»=#­’òiv T“]‚er©ÄgºgÄå]y‚€o°<Ñò W™*v Öj— ÿy†t–ò;’*Ó÷d ‹aŸ´ç T©ÏWOÌNûBâÓíTùH§²ûî“ôŒªˆÀ_°3Í=Ç®‚-P¨»=‘òß'I¬Õ -ßx6TÕÆà«oœ…Š`|ù¾“…o¸üÿîÿ³Uœ.0¿¿ûÇÉTE°¾üOU÷Mz¡pБV(ñÿ™`£)b$Ô7»­v·`M"ìg  Á‚Ò{ Ö66D p&øÔïÿõèâzßõmIEND®B`‚././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gtk4/images/layout_listbox.png0000664000000000000000000004315115074674453023235 0ustar00rootroot‰PNG  IHDR¬8?ÇùsBIT|dˆtEXtSoftwaregnome-screenshotï¿>&tEXtCreation Timejue 08 dic 2022 22:16:34ô × IDATxœìÝy\åþÀñÏ9À‘EAqÃ5T,1Ó\Ó\S3K»Y¶Ø­¼f‹¦¹¤•]íª¥WË_–i7ArW\Ss—RQQÁ Tvg~ G@váè÷ík^rfyæ;3z¾<Ï<3!„B!„B!„B!„BˆRÓ˜H™B!LR‘…UDr)ª I\Bñh**Q•+•5©Ü»¦„Ë„B<¼îMHJ —•Hi“Ia‰IsŸŸËº!„¦¥°ä¤Üçç¶»¯Ò$’{‘&ߤ½çsQ‰K!ÄÃëÞä”2ÜóùÞõ‹UÒdRX’ÊKT…M’´„âÑRX²21Ý›Ìòo_$óQTÊ,ßßf€àØ–wË–„%„†ü‰Gd·k@sw2äû;ÿ¶ŠIZÅ%¬{“U^ */I™6€w௿<×Þï±áh¨" J!iÅ $=öçêç†Î©ä&3 '­¼ÄUlÒ*.±ÜÛ˜?QYíÛ·ï°æ—Ußh4Ø—ùÀ„B<´H~và7Nžñù“–t¸Ķ»IJNfpÿgÐétFËnݺÍâïÀ¯]žîÚ¥Lå_¾r…}©Ÿ­,­pvvâ±Ö­ 쯢ä€F£¡Žƒnõ\hÒØ­¶¸Vz! ÷æ“ÂòM©ºµçß8!@#,ñ lÙ¾‹˜ èÓ«÷$ˆès|ôÞÛØÙÙp;%…/ç/$ìL¿­^Qžâ‹Á¾Hem&AQåpýæM._¹¢ÎKOOç÷?´~¿ÿq€˜ q¬Û¸…ôŒ ²³²ù%è7öì;`T–™V‹ÎÂïF^ôïÝ}NŽñþRSùãÐaÖmÜÂñ?Ob0ä>ñr<¿ýÆÖ»Ôu#ÎFóKÐo ý³Èø]ê:áV¯~íÚðñÄw xÜŸŒŒL~ú%Ðh½˜ qlÙÉö]¿síú £}ü¼ƒÁÀñ?O²~ÓVNr¿Töþq[CHHL,°ï+ WÙ¹g/›¶nçì¹sEŸdñHs¯ïFxDŸ|ö·oßæÎ;L›õag"¨ïêZž¢Ë”CJû–õ¿w",ñ ò:Ì›7’ù%0˜Ç;¶ç‰Ž¸’p•IÓfpçÎ4 Š¢Ð´±7ŸOÿ„ß6m!##€_ƒiíÛ‚®7.óîÏ'NF«ÕòD‡ö꼈¨(>Ÿ¿ä[·ÕÕ›6öæÓ&áêìÌÁÃG¹pñõë¹âãíÅü…K¸uû6óçÌ*úÿÊ=Ç4lÐö8DTôYuþO¿üÊÚ ›sWW¬,-™<ñ]Z¶hNdäYVýº–={Ÿ –Ó½K¡'O’”|ënkø|ú'x6hÀ–í;ùþ§Uèõzu›gz>Í«c^,ö2ˆG˧Ndʬ9\ˆ»Ä'³¾@£Ñw‘ºŽŽLýð_‘J•¸ä¯xhìÙ¿Ÿ;wîðQ# üñ{¾_4ŸwÞÀÿ}»€Úµì©YÓšßV­`úÇ“Œ¶Ý¸mÃFå¹ÑcÙ¶s7µkÕ±Nôz=_/þŽÔ´tÞÿç›,øâ3|›7%âl4k7lÂÌÌŒ·Ç½‚V«eÙŠŸø%x‰×®1fäðRÝs«ç‚¹¹9‰W¯“““CØ™‚Öo¢m«–¬X¼€YS>"+;›Výb´]]§:|1}*¯¼”Û|¹sï>žéÕƒ/gLÿ½™™YlÞ¶ÈídòÝ?ãèàÀÓ§2kÊGÔ©]›M!;8yúL™Ï½x8Õqp`Ö”¨çR— /w'Ç:̘òux½hѼ Cö»{,aU~½åOõûcffŽÎâïOæXXX”«Ì²’ÅC£W·®¤ÞIaëÎÝl؆-!têàÇûï¼…Fsÿ–ïF 2Pýüá´YDžædØõ^•“Óß¿QÖsqF£Ñ¨ÍnÏÄÖ»ÈÊÊbÄÐAÅîó^×oÜ$++ φ¹Mwiii$%ßÂÌ,÷å2­Z43úò¸WíÚö\½~ƒò÷gÃÝûq‰W¯åËÝÚ#€›k=n&%—*^ñðKJ¾ÅÔϾàÒåxõžÕ¥øx¦}ö%3¦|@íZv„©²',¹‡%¤û œ}w™™ÖŒç `èÀg‰‰ãß‹sðÈ1bã.áÙÀPŠ*çžù½<‰<Í­Ûw¨÷ =>>A]çÜù (Š‚‹s]uÞ¶»É `Mðz¦¼?¡TÇ´nóV:´k ¸89ТiF Zô¶…SaÃà)`·zåJ"m[µ ú\ ®ùŽE€™_ÎS“ÕŒ)0uÖ\ŠgæÿfÞì4¹‡%LÂ¥ËW¸xé²:ݹs§À:gÏçÈñ?ÉÈÌÄÉ©¹¿Yê,°µµ%--3QäÜÓЀ‚Á`@¯×Åáã¡hµZš5ñ¡‘‡65­9r<”Ý{÷s%á*k7lÀ¿½ñ ¬ ÆÇÛ‹ÇÚ¶æø_'Ùðð}éÚ›\½~°ð÷›¶n§¾›+žé@¿v˜™™±9dg"¢Ôã/«V-š´ag"¢ˆ‰½ÀÎ=ûÐjµ´¬]™Ë§˜Ø x6l[›²·§¶½=3¦|€gÃjÜ©M‚ò«˜xp>žñ™ÑçG¸Õ+|ßBTï&-&‡€;w§4 㑇 4vKÂBñ@•5aI§ !„&Aîa !„0 ÒKP!„I(s KêWB!$¹‡%„Â$È=,!„&Aîa !„0 ’°„B˜ét!„Â$”£Ó…¤,!„Ž4 !„0 e®a]Ž‹©È8„Bˆû*sÂêн"ãB!îKš…B˜IXB!L‚$,!„&A–B“ K!„I„%„Â$HÂBa$a !„0 ’°„B˜IXB!L‚$,!„&A–B“ K!„I„%„Â$HÂBa$a !„0 ’°„B˜IXB!L‚$,!„&A–B“ K!„I„%„Â$HÂBaÌ«:€¢Ô°®YÕ!!Ä#)=-µªC(”Ô°„B˜IXB!L‚$,!„&A–B“Pm;]&11‘%K–о}{úöí[ÕáT˜ÌÌLþïÿþáÇS»víowãÆ -Z¤~¶³³£E‹tìØ{{ûʵX»wïæøñã4iÒ„~ýú¡Ñh ]oÆ „††YN¿~ý¨[·.Û¶mcìØ±•®„˜T kÕªUÌŸ?Ÿ?ü°ÔÛFEE1uêÔJˆªt ï½÷W¯^UçEFFòÆo°oß¾R•uýúu>ýôSINNæØ±c¼ýöÛøøøT®˜ÊbæÌ™üãÿ &&†7ß|“·ß~»ÈuÓÒÒHNN&99™ððp>ýôSõsrr2™™™3nÜ8’““Ë—âáPد¿š»“–ܘ`X¶w'ÿ´Ô”y•XaÝÚ;vìÈÈ‘#y÷Ýw‰ŒŒÄÇǧÄåíܹ“Q£FqåÊ•Š ³Ôrrr077'""‚&Mš¨ópqq)UY‘‘‘4mÚ”äädµF¥( óçÏgÒ¤I9r„víÚ•9¦Ò0 ØÚÚ²gÏÚ·oÏîÝ»0`·oß.vÛÇãïï¢(ʼvíÎÎÎeŠIˆêâæõk\K¸Lzz*ŠA)ðo½2h4ZÌÌÍ037ÇÖÖ'gllíJ´mewk·®i38ܹ;¥@6  €rwR™L“àùóçù믿رc?üðAAA|ôÑGêò   xê©§ÔysæÌᥗ^àÇ$%%…éÓ§ãèèÈ[o½¥®Í®]»Ðh4ôèÑuÙ²eË:t( ""‚-ZлwoîܹÃÖ­[¹xñ"O>ù$=ö˜ºÍµk× áòå˸»»3hÐ ¬¬¬˜={6‹-ÂÑÑ‘‰'¢ÓéøïÿË?ÿùO£&Á£GrðàAêׯOçΩ[·n±çI£Ñ0aÂöîݡ~HHHH™bªY3÷†“'Oòûï¿cggÇÀ‹ljLNN&--æÍ›‡»»{±ñÞϹsçØ¸q#ï½÷P¶kpùòeBBBHOO§wïÞxyy•+.!JêzB<×®&’£Ï¶–u]ÜÐYZa¡³ ;+›¬Ì nßNæNÒMÌu–Ô´µ­„¦( †99zRRîtýæ:n ½¨UÛ¡ÜåW“i\½z5]»vÅÖÖ–>}úhò d×®]FófϞͥK—ÐjsÕÜÜ333uü‘ǜÇŒ¯¯/›6mR—/]º”¦M›²lÙ2¢££yþùç8p ?þ87n䨱ctêÔ‰ÀÀ@²²²ðóó#88˜°°0&L˜@‡ÈÌÌP÷mff†¹¹¹ºÍ§Ÿ~ÊÍ›7Õý¾ÿþû :”3gÎðßÿþ×(9—Ę1c8|øp™c˜7oƒ "66–   |}}IHH(t8;;³iÓ&&OžÌG}Ä’%KJó½¢¢¢˜7ïïŠ|i¯Àž={èØ±#G%44”Ç{Œ;v”+.!Š“““Ctø)._ÄÑÉ™&¾mqs÷ÀÖ¾–VVhµfhµfXZYak_ 7wš´lKG'’o\';3³Èû¿%¥Ñh037Cgi‰­µÐétÄž :< ƒÁPAG[µò7Z‘Ûè4|NÀ{i©)JeN÷òõõU-Z¤(Š¢ìÛ·O”˜˜uùˆ#”)S¦mccc£:tHQEÙ±c‡âââb´<11Q±³³S<¨Îûä“Owww%++KQEñóóS¾úê+uùÏ?ÿ¬JDD„:ïµ×^S:wî¬~ÎÉÉQ¾qã†bii©lÚ´IQEÑëõ¶OIIQ%::ZQEÙ»w¯âìì¬Ü¼y³ÀyÈ/""B”äääËNž<©Jbbb™bŠŽŽVt:¥Î9r¤òþûïÏ /¼ Ê믿^lìù:tH Ì߸q£R¿~}õsi¯ENNŽâíí­,[¶L]¾téR¥}ûö%ŽMˆÒJMMQΜ8®œ ?¥d¤¥)Y™™¥šÒÓÒ”¨3§”ð“*qçÏ**xŠ=¥œ =¢„ýyTÉÊÌ,ô*ûûxïn.ñ½›[œîæ«»¹GK!·¬L¢†FXXýû÷ S§NÔ®]›µk×–«ÜÝ»wãåå…¿¿¿:ïý÷ßçÒ¥Kœ={VW«V-õç^½z`aa¡ÎëÙ³'.\P?kµZrrrçôéÓxzzrñâÅǵfÍž{î¹Rõ,ŒF£ÁÖÖ¶L1íÙ³GGG8ÀŠ+X±bZ­–ðððB×ÿâ‹/8vì:tàÆF÷ÔþøãrG~¥¹111DGG“––¦ÃÕ«W‹<!Ê+''‡ ÑÔ¬iKC/´ùZsJÊÌÌ F>X[[“šr§Ü5­{i4ìjÕF«Õuæ¤IÕ´LâÖêÕ«±±±aáÂ…ê<[[[™0aB™Ë½páBú¶¶¶899‘ ÞÉÏÆÆÀ¨ÙÆÆÆèó¼yóX¼x1mÚ´¡Aƒ¤¦–îæùóçéÔ©S©¶¹×¹sçððð FeŠ))) FCll¬:ÏÛÛ›¦M›X÷ÚµkL™2…'Nàè舿¿?cÇŽå»ï¾cÅŠÌ›7“'OVø¼â®ERRW¯^U˜2eJ…Æ!Dž˜È3Xè,©çÞ°ÜeÕs÷ ö\™™èt–±š¶öÜNNâ|Ô¼›úVxù•Á$Ö/¿üB=Ô/(ÈýMúûï¿çòå˸¹¹¡ÑhJœ¾²³³IJJÂÓÓ³L±FFFòñÇsþüy\]]8räH©Ê°··'>>¾LûϳbÅ õYµ²ÄäééIJJ S¦L1ºçW˜ØØXt:šàwíÚE·nÝ>|8ûöícåÊ•ž¬J"ï8??¿¾ñh¹žOzz>Í[UX™îˆ:sCÅ',[ûZ$]¿Æ­¤›Ø›@GŒjß$xäÈbccY´hÓ¦MS§o¾ù{{{‚ƒƒpwwW{Ĥ§§“““£~¶²²"))‰””u^@@çÎcóæÍê¼åË—Ó¬Y3£ž‚¥‘—hòzàeeeýv¯ÕjÑét÷mŽó÷÷gÍš5e~þháÂ…ìÛ·3f”9¦§žz Fcô`rQ¼½½ÉÊÊâ÷ßÀÃÃÀÀ@‚ƒƒ133£cÇŽe:ŽòªS§Ì™3çt#¶kWp®W­™–¿{d—o23Óâ\Ï´Ô;•³F£ÁÚÆ†Kqç+¥üŠVíkX«W¯¦{÷îjÍ N§càÀ2~üxÆŽË·ß~K¯^½ðññ)ЬuëÖ8880`Àüüü˜5k^^^Ìœ9“¡C‡2lØ0ôz=»ví"88¸Ì5‚:àììÌOÿüó*‰G<œn^OD¯ÏÆÞ¡ý»Q-G¯\ÆÒJ™YÅe[ZÕ -%…Ô”ÛÔ´)ÙsZU¥°¶ Æ›ñ÷Ä–w§ú“'Ü«2³°Ð¹ÍMÆ £AƒÖñòò"++‹€€Õ/KWWWfÍšE›6mhÙ²%vvvèt:FŒANNnnn4kÖ :wîLŸ>}ÈÎÎÆ××—¯¾úÊèáYFÃc=F½zõÔÏZ­–®]»ª÷‡4 têÔ NÇ‹/¾ˆ Lœ8‘~ýúáéé©&ÝAƒaoo••­Zµ¢V­Z˜™™©eš››3fÌ6lHFFmÚ´aܸqê³Qùc³¶¶ÆÚÚNG³fÍxõÕW™:uªÑCÈe‰ÉÞÞž–-[2räH´Z-ÙÙÙôèу޽{u}ÏÓ¹sgzôèÁ;wðööfúôéŒ9’Q£FÑ®]»¿pÜ{vvvtíÚµÀü:uê¨÷óJ{- ·Ù÷å—_ÆÑÑ‘””Z¶lÉèÑ£±¶¶.2!JëÂù³ØØØak_«ø•KI£Ñ•™IVF:]¥”Ÿ““ƒ^ŸM­ÚuÐggWø~òûlöìmÀ% ëî”ÿἇ† ÆZļjù¦ !„¨Žþ:ú <¼±±«œwx޹̕‹qØUÒ}¦¬¬ ²22iÞ:÷¡ûêú¦‹jK!ª;CŽ‚Î²r:FètVäô•V¾™Ö½>«Òʯ(Õþ–BT ff~ÿ*¹¹†œÊ{^Jk¦5ê¤V]I K!Ê©²Úx }\M #­Ô°„¢œ@¯ÏBgfU)åë³3ËôÖŒ’2ää`VHgªêFjXBQN­–¬ÌÊ»”••…VSy +Ç ÇÜÌ¢ø«XõO©äävÁtss£{÷îe~¸·,.^¼øÀF¿=xð ÉÉÉôéÓ§Ò÷%„(?+«ܹLÍŽ7UZ)·’1ÓUÞ×uvF&5í«÷3X`"5¬ÀÀ@Ö­[Grr2×®]cõêÕ4iÒ„üñÅð G¿;w.“'O.ñúÕe4e€ pàÀªCˆªN]WîÜJ®”7ª(ŠÂíÛ·ÐYTN/DÈÌÌÄÉ©tÈV“HXO>ù$óçÏgáÂ…ìØ±ƒ3fðÏþó½rgüøñÄÇǽ-¼²üüóÏìÞ½»Äë_¼x‘eË–UbD%·fÍN:UÕañ@ÕqrÂÌÜ‚[7¯SQ¯eÊ›’“®caa¹Eå4Ùe¦§aa©ÃÚÆ¶RʯHÕþMÛ$hccCïÞ½Õyµk×fþüùŒ?^}kÁåË— âàÁƒÔ©S§Àðaaaüú믄……Ñ A–.]ª-Dbb¢ÑKoçÌ™ƒ——vvvDGG¤¾AaÙ²e¸ººrâÄ ©[·®ú*¤;vðÛo¿‘˜˜ˆÑkžŽ=JPP¡¡¡äääàêêZà5P{öì!22’fÍš©ûjÔ¨»wïfݺu\½z•&Mš Ñh¸|ù2óæÍãĉdggsúôi:tè –UT,Û·oçêÕ«ddd°jÕ*222pssã›o¾Á××—ÀÀ@BBBÐjµÔ¯_ß(¾¢ÎóÏ?ÿÌÚµk¹uëgÏžÅÉÉ©À(ÉlÞ¼™ 6púôi\]]Õ!Pò$''³~ýzvíÚ…™™ÎÎÎêœ111qâÄ lmmÕs^žó^’k"ÄýhµZ²ôÙ\O¼B-'´ÚŠù÷““càÒ…sXY×,ô 3å¥( wn%ÑÐÓ«»o‹êû¦ “©aÝëðáÃxzzâèè?²ìâÅ‹éÒ¥ ¡¡¡¬_¿oooþýï«Ë‹±¸°ÑoGŒÁèÑ£Ù¿?ééé ÌÔ©S¹rå 3fÌ wïÞj-púôéôïߟ°°0Ž9¤I“ ýb 1ëkéÒ¥4k֌ŋsþüyÆÇèÑ£Õå…¦\\,!!!¼óÎ;<õÔSìܹ“Ë—/“••Å;ï¼CëÖ­Ùºu+'OžäÉ'Ÿäûï¿W÷u¿óœ‡V«ÅÜܼÐc6lß|ó ‘‘‘|ýõ×4iÒ„¨¨(uyxx8mÚ´á§Ÿ~âäÉ“¼ð êØdtèÐ}ûö±mÛ6† R¢c½ßy/é5¢8.õܰ´ªA|\L…•w+ëšÅŽ˜PVwn%ackooj/JµqxĈŠ¿¿¿òé§Ÿ*S§NU^|ñE¥qãÆÊÑ£GE)~dÙ+W®(ÖÖÖF# /X°Àh4ÛâF,.lôÛ¡C‡*z½^·ýÚø¿ IDATbÅ ÅÝÝ]Ý733SñððPGö­[·®TÔ@¥ª‰'*£F2Ú×ܹsÕÏ[¶l1M¸°Ñ”‹‹eâĉŠrõêUu›¼‘óΫ¢(Ê| 4kÖLQ”’àÛ¹sgeÉ’%E[þ‘óŽ-ÿ(ÆÝºuS>ûì³Û%%%)Êþýû ,+Ïy/é5¢$nß¾­œþë˜s6¼Üßçφ+gN„*Qáa>êð…óg•Ó'Ž+a-ðRQªïˆÃ&ÑK@¯×“‘‘ANN«V­"88XãèÞ‘e£‘ewïÞÑÈÂ>>>厩wïÞF¿ùlß¾ÆóÓO?©ó §oß¾¸ºº²dÉêÖ­Ëã?®ÖHJ"óf·nÝÐétÄÆÆhr+i,ûw''§ûî«wïÞ,X°(þ<—DÞ1ÇÆÆ’@£FÔaMn޼ɮ]»øõ×_ l·k×.\]]yâ‰'J}¬÷;ïå¹&BÜËÖÖg×$ÆÇq1ö<® <0+å¿©ƒø¸rôzÌÌuXVð+Ÿ”»Í€Ÿæ­Lêß¼ÉDÚ¹sgæÌ™Ã—_~ÉóÏ?Ï×_­.Ë?²lll,±±±èõzudÙ¸¸8£·—W–¤¤$233Õbccéׯ;wr;$Ô­[—îÝ»ãííÍòåËË´N‡N§»o‡“âb))[[ÛBGð-ì<—ÄÎ;iÞ¼9ãÆcõêÕj“+䎴lnnN:u lwþüù"¯ayÎ{E]!ò88:âæá¢(œò4 Acn¥UÅ%+ÈHO#éÆU¬jXÓ¼U»Jyû{e2™V~~ø!-[¶dÿþýtîܹؑe]\\ Œ,|¯²ŒX|/OOObbb˜6mZ¡Ë½½½Y¹r%‹-bÕªU¼þúë4nܘ€€€rí·,±”µL(ß¾£Fâ›o¾QÇÔúä“OˆŽŽrGZÖëõ\»v­@Íï~£0—ç¼?Èk" {{{,,¼¹q5¤×¹–˜€­=¶vö˜ëtX˜ç&Šl}ÙY™¤Ü¾ÅÛ·±°°À²FMÀ:_'ˆ²PCN9=Ù™dffba©Ã³q3ìk™æ=+“©aå×¢E   Ž¨[ÜȲDGG,|ï—_q#—Ä AƒØºu+¡¡¡….7r_^Y«V-Þxã \]]‰‹‹+Õ> SØhÊÅÅR%Á×ÊʪÈÑ”ó’QÞÈÇ€Ñ@’8;;ÚE¿cÇŽ„‡‡óÇXVžó^Y×Dkkk\Ýâî僃“3©))\Š=Ïù¨p"OÿEäé¿8y†¸óÑ\KLàö­dnܸÎ䛤ÞNæzâ•rM7¯'rçV2Yé™XÛÚáÓ¼%-Zû™l²­a|ôÑGtìØ‘ƒÒ©S§ûŽ,ëååÅ'Ÿ|Â!C>|8ƒ­[·µ 7bqItëÖñãÇÓµkWÆŒƒ½½=Û·ogݺu8::âååE§Nðòò"44½^OÏž=Ë}. Mù~±8;;—y_ÅàÛ§OfΜIzz:]ºtaÀ€ê¶æææ 0€1cÆ0pà@bbb8yò$ݺuÀ‚ÿüç?Œ=šS§NáææÆîÝ»ùé§ŸhÕªo¿ý6}úôaôèÑdeeñçŸrøðá2Ÿ÷œœœJ»&B˜™™akkKÍš5q¬ë‚^¯Ç`0¨¿(iµZµW­N§3©ûIUÁ$žÃÒh44oÞooouž››uêÔÁÊÊ ŸbG–}òÉ'éÞ½;z½žvíÚ1dÈ6oÞÌ„ €ÜÚÃýF,.nôÛ<½{÷æé§Ÿ&==5jðòË/Ó´iS´Z-ƒ ÂÌÌ ½^¿¿? .4zŽ(ÿñ6jÔH}«°}i4î;šrQ±h4šûÈ+3ÿÈÇyólmméÒ¥ Pü¾:u¢E‹deeáëë‹›››Ñ± <˜  Óé:t(“&M¢víÚ4oÞ___†ŠÁ`ÀÚښѣGãçç‡F£¡OŸ><ñĤ§§ãîîÎ{ï½§6–å¼—æšQFMJ–––XYYaee…¥¥%:®ÈÇ@ªJu}ë‘q8ï½€E5_ !Ä£JFB!ÊA–B“ðÈ&¬^½zIs B˜G6a !„0-Õ¶[{Ä©?«:!„x$5lTþW×U†j›°š¶l[Õ!!Ä#©²{ –•4 !„0 ’°„B˜„jÛ$(„¢t ±Ñ$Ä_"+3£DÛXZZáìZï¦ÕþÕP’°„â!AjÊóï‚e¾—LßOfF:‘§O—OóJް|L"aV`¾‡‡‡ÑPñeuöìY6nÜÈ{ï½WèòììlfÏžÍ?ÿùO£Á KëðáÃlݺ•çž{N}wÞÃàâŋꫮJcõêÕ¸¸¸ðÔSOÍ¿qã‹-bÊ”)e|çÎܾ}›Aƒ•i{!LQbü%Úù”8YXZÕ I‹Ö„ÚWíVõ®ÿÝȺuëHNN6šò§QQQQÌ›Wô«³²²øôÓO¹yóf¹ö3{ölæÏŸÏ’%KJ½mTTS§N-×þ+Baq3nÜ8’““KUÖªU«ØµkWùׯ_çÓO?E¯×—9Î;v°víÚ­[]έå•™™¥UéÇѲ´ªAf ›«’I$,È}Ûúüùó¦·Þz«ªÃ*±äädBBB˜6mk×®-Ѥù]¼x±Ðq¢´Ââ?~<ñññÔªU«Š¢*Ÿêrn…÷gM‚Å9{ö,ááá´mÛ–­[·’‘‘A¿~ýÔr®]»FHH—/_ÆÝÝAƒ $NHHôí۷СÚó;yò$¿ÿþ;vvv 8{{û"×]»v-mÛ¶eôèÑLœ8‘C‡©C•üûßÿfðàÁjÌW®\aùòåLž<™Ë—/óã?’’’ÂôéÓqtt4JÖäðáø¸¸Ð§O5Žììl/^ÌË/¿Ìúõë¹víO>ù$mÛ¶%..Ž;vžžÎ€¨_¿¾Z^DDû÷ï'))‰Ö­[«ãCǹsç 4©æääBDD­ZµÂßߟš5ËöþeË–1lØ0Ž9©S§hÖ¬½{÷.0ÃÎ;ù믿ðôô,P;+í1å)Í5BT.“©aÝOTT/½ô=zôàøñãlܸ___õ¾WVV~~~Æ„ èС™™™j 4ˆððpþóŸÿЪU+ÂÃËÜç¼yó4h±±±áëëk4zî½V¯^Mÿþýqpp cÇŽ-ÿꫯ8þ¼ú9>>žY³f©Ÿóz›Ý×yã75j‘‘‘|ñÅ´iÓ†˜˜õ¸ßyçÚ´iÃöíÛ9räþþþŒ3†¾}ûrôèQñõõ%66€C‡Ñ·o_öîÝËüÁàÁƒ7nÜ}㸷I555•§Ÿ~š©S§röìY>þøcV¯^]ä¹)ÎÒ¥KiÓ¦ sçÎ%<<œ—^z‰Q£F­ó /0vìXΞ=Ëܹsùúë¯Õee9&(ý5B}OOO£·µ×¬Y;;; wXëýë_…vسgŽŽŽ8p€+V°bÅ ´Zm‘5²5kÖРAZ´h@ß¾}‰%44´Ìç`ݺu >\½wdnn΄ عs§Ñzùï-õêÕ ½^ot®zöìÉ… Ôf¶ÔÔTNœ8¹¹9Š¢péÒ¥ǵfÍÆŽ[¡Ït4hÐ@ýÙÇLJ=z°wï^6mÚdt4 7V×/Ë1•ö !*ŸÉÜÃò÷÷gÚ´i%^ßÖÖÖ¨cüyóX¼x1mÚ´¡Aƒ¤¦Þÿ]Y5"--Û·oèZ””„F£1JˆÞÞÞ4mڴвV¯^••ï¿ÿ>ûpŸV«%00víÚ•ø˜îuáÂuèú<^^^\¿~œœœB·±±±)ÐáÃÆÆFíá—™™É믿ΡC‡ð÷÷W‡ /óçÏãââRìzfffdee˜o0Ðh4÷Mxîîî\»v Èí4ñä“O¹nYŽ©´×XQùL&a•Gdd$ü1çÏŸÇÕÕ€#GŽÜw›ÄÄDìíí±³³+Ü<==III)ÑsB.\ààÁƒ¼ûî»ØØØ¨ó»uëFPP³gÏrkÅ%Ñ{9;;}¡æÅíîî^æç—~øáN:ʼn'Ðétäää0wîÜR•aooO|||±ëyyyqöìÙó/\¸€§§§Q ú^ …Ÿ‡üÊrL¥¹ÆBˆÃdšË#ïË3¯W`VVIIIFëܹs‡«W¯ªŸ—,YB¿~ý€¿›”òzž=õÔSh4-ZTì¾ÿ÷¿ÿѤIæÍ›Ç´iÓÔiöìÙDEE©CÜÝÝ 1Š'?+++’’’Œž=ëÖ­¿üò‹QrXºt)Ï>ûl±q%>>­V‹N§(ÐÉ °8îåïïÏ÷ßÁ`¸ï¾úõëdž 8|ø°:/++‹ùóç3xð`£u7lØ Ö /]ºÄŽ;èÝ»7{=V¯^mtîý¹´ÇTšk,„x0L¦†µwï^µI-O£Fxýõ׋ݶC‡8;;óÄOЭ[7öïß_àK+33“öíÛóÌ3ÏpöìYbccÕ{AÖÖÖ´mÛ–É“'3~üxºvíÊ·ß~ËØ±c9tèÍš5ãøñãŒ=ºÀíêÕ«yñÅ ÄÔ¾}{<==Õ^zï¼ócÆŒ!55FSàþYëÖ­qpp`À€øùù1kÖ,^xáþ÷¿ÿѾ}{Hxx¸ú¼WY 0€Ù³góÔSOáããÃîÝ»ºÿǽfÍšÅSO=E×®]éܹ3GeøðáÞ„Ñ­[7&MšD×®]éÙ³'ŽŽŽìÛ·///¦OŸn´îöíÛiß¾=;vdýúõ¼÷Þ{ê=Á^x•+WªçáܹsœKFF 6¤~ýú´lÙ’‘#G¢ÕjÉÎΦGôîÝsó¿ÈÈÈàÆüãÿP;täçé鉕•mÚ´¡eË–ôêÕ‹ôôtZ·nÍÂ… ±µµåñÇr;Œ1‚œœÜÜÜhÖ¬:ŽçŸžæÍ›£×ëéÓ§Ÿþ¹º/Fƒ™™]»vU;Yh4 œ+///š5kF½zõ:t(fff4jÔˆÏ?ÿœ&MšÐ¶m[¬­­‹Œ#ÿùwrrb̘1ØÚÚ¢×ëéÕ«C† 1:7yºwïΠAƒ¨Q£uêÔaܸqLž<Ù¨9pÙ²e|ðÁtïÞNÇ„ x饗ÔåZ­–‘#GÒ¸qcEaÈ!L˜0‡2“……E‰®±ÕÉ•K¨ë⊹yÑÍé…ÉÌHçZB<îÐggWFxªÏfÏÞ\²îNÙ€0Ü }³Bnƒ'«¼DeX“ÛíÐðOKM)ú]F †uÙ2ŸöíÛóúë¯óÊ+¯Tu(BTkÑa¤¥¦Ð¤Eë¿¢)ïå·Ö5mñnšÛjQÙ8Z×´™îÜÒ€ Œ—Â=‰K~UBˆ‡D}o.Æœ%ôо¿ÐÒÒ GçzÔ¿[»ªÎ$a !ÄCÂÊÊŠ†šàÚÀ«Äï+Õh4XXX¨’ª3IX¢Ú;zôhU‡ „ÉÈ»Çÿ0z$ºµ !„0}Õ¶†qêϪA!I ùTu…ª¶ «ºž0!„UCš…B˜IXB!L‚$,!„&A–B“ K!„I„%„Â$HÂBa$a !„0 ’°„B˜IXB!L‚$,!„&A–B“ K!„I„%„Â$HÂBa$a !„0 ’°„B˜IXB!L‚$,!„&A–B“ K!„I„%„Â$HÂBaÌ«:€¢Ô°®YÕ!!Ä#)=-µªC(”Ô°„B˜IXB!L‚$,!„&A–B“ K!„I„%„Â$HÂBaªísXB˜šk×®ÂåË—qwwgРAXYYUuXB<4¤†%DÈÊÊÂÏÏàà`˜0a:t 33³ªCâ¡!5,!*€N§#&&­6÷wÀ›7oâêêÊÎ;éÛ·oG'ÄÃA–D«Õ’““CTTׯ_ÇÓÓ“‹/VuXB<4$a QAæÍ›ÇâÅ‹iÓ¦ 4 5µz¾MS% Kˆ ÉÇÌùóçquuàÈ‘#U•ét!DˆP{fee‘””T•! ñБ– C‡8;;óÄOЭ[7öïßOBBBU‡%ÄCE– fÍš?~œ_ý½^Ïo¼Áõë×±µµ­êЄxhH¢‚8::òæ›oVuB<´ä–B“ K!„I„%„Â$HÂBa$a !„0 ’°„B˜IXB!L‚$,!„&A–B“ KˆrúßÿþÇ™3gª: !z’°„(§7ß|“ï¾û®ªÃâ¡'¢¢¢°³³«ê0„xèI¢œÖ®]‹ŸŸmÛ¶ ..Ž-[¶ššJ«V­èÔ©5kÖ¬â(…0}Ò$(D9-]º”ÐÐPvìØA‹-صk111L:• .Tq„B<¤†%DZ¶l/¿ü2 ,¨êP„xèH Kˆ äêêʦM›X»v-éééUŽIXBT 3f0lØ0^}õU\\\øøãÉÈȨ간x(H¢ÙÚÚ2gή\¹ÂÏ?ÿÌ?þÈܹs«:,! ’°„¨@ƒNG¿~ýèÖ­qqqU•ét!D:t(iii´jÕŠÄÄD‚ƒƒÙ´iSU‡%ÄCAjXB”Ók¯½F»víX¾|9¯¼ò ŽŽŽtèÐ'NÐ¥K—*ŽPˆ‡ƒ¦ˆyr“™9`XÖ€íÝÉ?-5e^eVÃZ´Bˆªž–Z©å[×´™îÜÒ€ Ð@¹;©¤†%„Â$HÂBa$a !„0 ’°„B˜IXB!L‚$,!„&A–B“ K!„I„%„Â$È»Å#+((zõêU`ÙŋٶmcÇŽ-SÙÇgãÆh4\\\èÒ¥ M›6-WÌB<ʤ†%YlݺµÐeÁÁÁŒ7ŽäääbËY°`0šwìØ1¾ùæRRRHJJbݺuøúú2o^¥¾ÑLˆ‡š$,! 1~üxâãã©U«V±ë®Y³†S§N˜ïææÆÜ¹s™?>›6mâË/¿ä“O>Q‡ B”Ž$,! qîÜ9V­Z¥~6 lÚ´‰¹sç²råJ"""øù矉‹‹cãÆLŸ>Ó§OYf·nÝHOO'--M§×ëÙ°aóæÍcóæÍFÉìßÿþ7‡V?gff2kÖ,¢¢¢*òP…0’°„(DTT”Ú|g0èÙ³'“&MâÒ¥KüöÛo,Z´­V«þmnnŽFSعŽ=J«V­°±±àÖ­[0gÎ"##yõÕWéÙ³'z½ FEFFŸþ97n¤Q£F•vÜBTgÒéBˆbDFF²{÷nprr2ZöüóÏóí·ßÒ·o_Æg´,!!éÓ§žžÎþó¶mÛ¦.Ÿ3glذ­VKbb"-[¶äûï¿gܸqŒ?žŸþ™/¾ø‚‘#Gòõ×_sèÐ!ÌÌÌ*ÿ …¨†¤†%D1177gÖ¬YDFF–© 333Ú¶mË?þñÂÂÂX·n¯½öšZKsvvfôèÑìܹÈ­µ-]º”¯¾úŠ^xO>ù„&MšTÌA a‚$a Q '''6oÞ̉'hÚ´)ìÛ·¯Øí\\\˜6mÓ¦Mã³Ï>ã?þ Q£F|üñÇ\¸pggg£m¼¼¼HHHP?·nÝš!C†Ë;ï¼S±&„‰‘„%D tïÞ={öC«V­èÛ·/ééé¥*C£ÑпΟ?äÖ¨bccÖILLÄÓÓSýÏæÍ›©Q£Ë—//÷qaÊ$a Q EQP”Ü‘º=<<ø×¿þEJJ 7oÞÀÊÊŠ‹/–¨¬3gÎЪU+ ·×à¢E‹ÈÎÎ 55••+Wòì³Ïªë¿öÚk¼òÊ+,_¾œI“&_‘‡&„I‘Nâ‘¶{÷nÞ~ûm£yy%ò„††2dÈzô胃[¶l¡gÏž¸¹¹ЧOfΜIzz:]ºtaÀ€@níè£> ++‹Ó§OÅîÝ»˜1c]»v¥C‡°}ûvžxâ † À?üÀ™3gX³f 5jÔ _¿~¼õÖ[Wê9¢º’„%YC‡U;@ägff†&Là±Ç#00£Grûömf̘AÿþýÕõ'L˜@ãÆ‰ŠŠÂÕÕ???Þ|óMu:uê@ß¾}Ñét@îƒÅ¡¡¡lÞ¼™øøx–,Y“O>©n“œœÌêÕ«©Q£óæÍãÛo¿åÚµkz+ ñ((ì¡ÍÝIKnB³¬kÀöî䟖šR©ï˜©a]³2‹BQ„ô´ÔJ-ߺ¦Íàpçî”dÙ€0ÊÝI%÷°„B˜IXB!L‚$,!„&A–B“ K!„I„%„Â$HÂBa$a !„0 ’°„B˜IXBTSçÎcþüùU†Õ†$,!*Á‚ 8pà@¹ÊˆŽŽfÞ¼J}š&E–•`Íš5œ:uªªÃâ¡"ok<ƒÁÀ–-[8sæ õêÕÃÏϦM›ªË£££Ùµk†=zàáá¡.[¶lýúõãܹs9r„pèÐ!âââØ¸q# :”-ZpùòeBBBHOO§wïÞxyyÅÆž={°¶¶¦fMy´ùI K<Ò ={ödÒ¤I\ºt‰ß~ûE‹©ËüñGüq>Lpp0¾¾¾lÚ´I]¾téRFŒÁèÑ£Ù¿?éééhµ¹ÿ­´Z-æææh4¹ƒ"ìÙ³‡Ž;rôèQBCCyì±Çرc‡ZÖâÅ‹éÒ¥ ¡¡¡¬_¿žÑ£G? ³ „iáEÄ#-<<___ Œ1uõêU7n̶mÛð÷÷`êÔ©üðÜ;w Ú·o‡‡¿üò fffê¶Œ5ŠqãÆ¹‰±I“&|ðÁŒ;È­-[¶Œ#GŽ@£Fعs§º¯… òå—_–x4c!*Š /"D5äè船¹9³fÍ"22ÒhÙîÝ»ñòòRÀûï¿Ï¥K—8{ö¬:¯wïÞFɪ0111DGG“––ÆŠ+X±bW¯^%<<\ݗѾ|||*â…xhHÂ4'''6oÞ̉'hÚ´)ìÛ·€ .àììl´¾­­-NNN$$$”j?III@n­-66–ØØXôz=S¦LàâÅ‹¸¸¸TÀ ñð’Nâ‘×½{wºwïNll,sçÎ¥oß¾\½zgggbccÖÍÎÎ&)) OOÏRí#oýâççW`yaûB“–x¤)Š‚¢ä6“{xxð¯ý‹””nÞ¼I@@çÎcóæÍêúË—/§Y³fF= ceeetï©N:0gÎuùm´¯øøør©a‰GZhh(C† ¡G888°eËzö쉛›3gÎdèС 6 ½^Ï®]»V{þ¥OŸ>Ìœ9“ôôtºt逸æ›oxæ™gèÒ¥ O?ý4qqq899ñùçŸã)òsDZIDATååÅ'Ÿ|Â!C>|8ƒýû÷?ˆS „É^‚â‘wìØ1Ž=ÊíÛ·iÒ¤ ýû÷7êDÊþýû©]»6½zõ¢nݺê²eË–áççGÛ¶m ”»a⢢èÒ¥ íÛ· 99™bbbpuu¥OŸ>8::ªÛù·aÀ1JG‚ÞN_¬‚µ8ýð)Éû$¿$9Îõ&›ÎŽyt¯¨tc™ä)Éc’/V»^˜ V{áö¢&Yd¬wYGëm’y àgWë[ÖíxLòu°î³nÉ2LYcÁZe›zº*}Jò5›0=ÇæÃšE¬~v¥eš*íxK°Ê¤ÕNV/¶mÂÛ ,a*A*ÇN²™® €và)[‚eÒzŽm Ž:dKp™u«ãeâ*ÓU ÔÁ*ѪõÌf[ð¨-Áöbe¤› J~,f}³Å,&,ÆoÚ+zªKÌv~‘x×–`†‹$›[Ùë=É2U‰­©;ÍËgWSw ŽÚwK°DªÝ“+¶‹V¯¡*¶f6òXÇi,T‚@­þ%‹:\íóöµ/ì ̬yÞÆ©ª €Z{«z=M}QxrÒÚ'0ík¦¦)±`̾?v»u[ðÈL½V¨ØÇTöú-Ácc#RüþëÝûm 2»š?¤IEND®B`‚././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gtk4/images/layout_notebook.png0000664000000000000000000002255615074674453023377 0ustar00rootroot‰PNG  IHDR@{ZYpsBIT|dˆtEXtSoftwaregnome-screenshotï¿>&tEXtCreation Timejue 08 dic 2022 22:18:57Û‡V IDATxœíÝwX×ÂÇñï,, Aª€ˆˆ½€Šbï=暘¢ÑXc’›®yS)šb®¹¦hŒ1EMLLbì½DJQªHAAzÝ}ÿXvÝ]–.ˆ—óñ™‡Ý©gÇáÇ9sfg@AAAAAát¬S@y'Wv'ªºuˆ áN©.øˆ )ýå¤:NA¨ý€SÖqZÔ7œ TÃë†nGÁPØ)kxmh¹Õ'˜ôƒMÒdzï« BA„úÐ;íA¡÷^þZÕ5œ …ž:ø "Ah,C᧨fÐGíå«e\‡BTWã3Òúi´ì+À´rÝ"Ah(í +J€\ È**…ÖOíe%j ÁÚP?üÔ5z¸ ”¡ Bu­ÐP“¸ŠšP»ö§®ùW&€•ŸŸ_ÀŽ_·|§TÖ©)-‚pÇHHåSfük^XXØi (E‚åèž„jB°¶4Tó3Auޝ÷µ¸èm j~‚ Ü-R¶{ç.a¨ÎªCÐPM° YukÕ{­AuÓ×~ËÏ›g"ÂO„»JióÓæM÷£ê€•£Ê(#t¯Bj*{µ}M»é+GUókt‹þE›F—_¡” ÅM.>Q@ªš úœ ~§ˆŽšÎÝêùU¡$)­ïì×’AêO’ÉlPUÆäèv†È¨¥'¸®×ê`[âRAZ¥´E· ¬þBFêRÔ@cÀDTþAhAL¸OÚ¨êÕ ¢V]3ØèŽYáÎÐÎ&ý¯äVËP ÐÐí¬ôCPv‡ïK(‚ÐÚ_Ï­.üªÔëòU8C7>0ù'B ¢~†nÈbPuhèílU ùù…\ ##3‹¶mÚÐÉÕ•®Þ^Èd2®DÇðÛ_3kÆ}tíÒ¹ÉÊðÛ_»062bÆÔIõ^6%-“AÈdFÌœ>#£Ûg0nܼÉÁ£ÇñòôÀ¯_ß;YdÙ99ì?|Nä׿ɶËÅÐ0üúõÃËÓ½ÆyÕûÅooúöêÑ%l¼A¤¦¥1yÂ8¬,,îvqZ ý|2”_õº F{aí•H€ÔZ*€ÁgùïúêŒ_0ç¦O™D`ðYÎ]¸ˆ›‹ ÞM€Ûÿü‹6ffÜ×€LJIcëo —ËuB4óF6[ûƒ‰cGã[ÇŒŒŽ!0è ƒúÒÃǧNËܸ™ÃÖßþ`Ìða lÊŒŠaëo`mmMçZP{¿è›1u}Zh?ȹ :ÄK€j ºi}î£7î?snåòù—ß —óļ9töt'3ë&×<Prÿ´É8wpÄ€ͳO²ÛËlû}ÃakcS9EÿBµKHJbçÞýØ;ØÑçk½ËдûÉÐÍ‚kžwØfÝ?]gŠ……E–¿Ûêò[–Ì£›7Ë_x+++róóY½æ Â/GòçÖÍY}uw¬¯VCobÐ*šÀѱq”––2 _¦L€7 2H3OFf&9·rÉÊʺ‘1±„†GðÀ}Ó¹NJj*îèÕ£¹ùù\¼Fn^~ýúàä訚mQQ1L›<àsȼq“î]»àåéQcù”J%—Â/“˜˜„µu;úõÇÌÔ´Úù;8‘š–Î÷?må¥g—Ô¸î´ôë\ŽŒ¤¸¸ï.žté¬ªÝÆ]½ÆÙ ¹FAA!cGÇζ=Y7n~™‚¢Bº{{W©…)%%Ã"HHHÄÕÅ…þ}{!Iº‡STL±qW133¥gn8ÚÛëLÏ+( 4,œ¬¬›¸º¸Ð¯OOd2Ã4äåå±ûÀaŒd2fL„\.¯2•¥]]ªŒ?ñ1qñx{yÒ¿OoN‘’–Îà~trs%!1™˜¸«äæçãhoÇß~˜Tn£% wKGW®DFóæû«xïÿ^C’$Þ~5ñ ‰¸:;7fÕ Ê¤úàíÜ[xÄ¢­9çB.²çÀa†Œ…E[y¢¢bØöÛXYZâåéITT [~ÝÁ±¤¦§kæ3|BCÉιÀÛ¶óÑ»oâáæFTT ›~ÞÆ‘ÿ” €$IÌŸýÓ'OÐ-Tå~/-+ã½ÕŸqI’P*•ØÛÛòñŠw°ngep™ÑÇ|.„“ÁŒ5Š^=ºBYe¾½³ñÇ-”——k&M?–'ŒØ«ñœ« À —B¹p)”¾=»c×¾=AgÏñù—ë).)фڜ‡`æô©šuŸ æÈñ4ëõ÷óeÙ‹Ï©6¯TòŸ¯×sìd fº‰\Î3O.`DÀ"££ùhÍäÜÊÕÌãÓÅ‹w–¿Š™™Ö/|eåè‹o6ræ|Ï~¹±Ü`E4?¿”Ô4]æäà€«³3«?ÿ/&ÆrÖ­YMNvkÖ}CGg˜>•£'NñŸ¯Öë,×ÁÉOW¾KÛ¶m›çXPÖóX¸ËÞYö2o¬ü„ÄdÞ\¹ I’¸–˜„ƒo-{éNäJ½‚°¶ë[5o/úöîIII)ë7ýÀ¼§—òñÚu$¥¤Öº¬ƒ½-«Þ}‹…sgpøÄI¦LÇêoã?À’’Röì?¤³Œ-_¬þ€Wž[‚ÜØ˜Ÿ~Ù®ù%Ñ·cçnÂ"®ðàŒélÙø5szÌÌìø{wµe’$O-˜‡L&cý÷?PQQQež”´4¾ýágìÚ·gÕ»o±òåØÚذûÀ!B#.3aÌ(ž^ø8 çÎæÏ-›ññö&?¿ÿn؈yÛ¶¬ûô#¾Z³'G{¶lßA^AÁíýbgǧ+ßeå›Ë±·³%èÜyÎ^àÈñ“;ˆoßÞ|ññ‡<»xå|³éGò (//ç󯾥 °ˆWž[ÂÚUïÓ³»‘1±?÷þÃG9s>ß>}¸oòÄj÷ËñS<óÒ2!3+ G{{f?8“¼‚¶lßÁ×›6#Iÿ^²cccú÷îųO-â‹Õ°æ£÷пié×9pô¸Îú[â±p·Ø¶oÏÊ7–ÓÁÉ„¤d®%&aogËŠ7^ÃÁήÙËÓàT¶‚’Lâ­×^bÙ‹ÏâíåIEE§‚ÎðükÿÇÉÓAšùô÷À¿þxwñdêÄqšÿØq£†ÓÅ˃î› @jF†Î2ƒàêêÌÿ ñHiYѱqšéÚÛ TýÿÚ½—Üü<““«|íÿ5O7&ŽMRJ*ïÛú zÞ ³ç©¨¨àþé“ñîâIî]™9CUÞ‹aáz뻽\t\,ùù…XÛ´ãd`ÇNžÂ¼­9¤¤¦j–ëÚÅ OÏNôèÖ•îŸ@ØåH”(ù'ø æ>Š«KFÊà¾GܵÒ32ðàËÿtìèÂâùs+˦óy“SSùî§-´·±áù%‹@ªz̪uéìÉÃ3gè ææ(Q2eâ8¼<=Øwð0—#£yhæ Ü;uD‰«v–Œ:„üÂ|bãâi×΀”Ô´{,´„FFƘÈM4ŸCn,G.—7j %ndZ I’äçË ?_ÒÒ3øù×ß8t–;w3tð ÚWØØ´ãzV–¦µic£º‹˜Â@ LÍÉAuÞ+'Ïð_}u¯tzF†æ¼ÖÐÁƒèìá^kyf?ø/NŸeÛï²ôÉ…:Ó2®g`ok«çâÜ€›Ù9Õ®³°¨HS®äÊæ¤“£NŽX[·#?¯ Ê2ÎNN€ê€ŒŒªÛvîP¹íœ[äWÖ$íío×:89"IR•ÚÑ™s!”””ÒÑÙssójË àÝÙ“‡fÎ08M&“ñØ#òöû«icfÆŒ)·k’™™7xûÃÕܸq“>½zbl¬º¼¨¢Bap]ÐòŽ…æ–s‹·Þ_ErJªæœ_rj*o¿¿šo¼†uóÞa¯áØ ÎêëàèÈœYr*è,·ró ?¡´¦NHC·f¬f™¸ølí Nwtt$)%‰cFÓ·wϪ۩ŽÚ¶iËüÙðÙº¯ùù×ßt¦µ«ž?ÿÞÿ¦O­a§Pã>Ûµ÷ EÅÅìÞwHsÑî‡HKÏàåçž!`Тc¯rú̹ÛëkÊcAkž wÁ{«?ӄߊ7^à­•«HNMå½UŸòÙ+šµ<â` ÒÒ¯óþ§Ÿsàè1¯Dr>ä›~Þ @7ï.w|{{!>1‰Ð0Â".cii©¹¸ÚÈȈÂâ"JJJ2À€Í[!3ë …‚Ë‘ÑäååÕi[ÆøÓ»GwÒÒ¯ëŒïÝ£;¿ÿ½›Ë‘ÑÄ_Kàð±“Èd2øª®ß³´T]{q™’’R înéàèHTL,{öB¡Pp3;›+Q1:ëˆ "2ŠøÄ$;@ÿ>ª íÛKõË»aóO$¥¤qöBW"±·³ÅËÓÎîîX˜·åÌù =ñié×5ç¹ü+÷‡š©Ü„%‹æ#IÛvüERrJµû"?¿€”´4!7WÕÉrìä)Î^aâØÑØX[³õ÷?ȸ®ÚgE…ªZïÕøk”–•q¹Nû¾.j<*{¼s*k½=šSüµ<:¹©j{íÚaÓ®+Þx NnÄ'$6{yÑnaZš@L\.†jz=ÕÜ\]Y8ïQ ÿY¯í½¡?û*qñ×xqù›€ê‚å¥óçÐÆÌPÒ£«7g.\dΓKødåÛŒ6„ЈËû''Ÿ ¹\NYYOÍŸË„±£j(Çí×OΟÿ—½¥ÕÛ«¤g·®L›8ž¿÷àÿÞûP5ç=2 w7W@IŸžÝ°³mϹ ytÑS,Y4Ÿ1#†òìâ…|üŸuløá'6mÙFyy96íÚ±qÝÍvKJËxã½5e˜0v=ºu”Ü7y"!¡áD\‰ä¹W—`iiÉs‹ab"ÇÄDÎS æ²ö›ïXûÍ·šu ÈÄ1#«|Îî>]˜8f4{fí×XµâM½ËeTó<ÍñÀÓ:{lÆ”‰L›4?þŒm{æ=: Ÿ®^|¾n=_mÜÌ;Ë_fØA:~‚ïæ]{°´´¬ü–MuU>ý÷ ;ºût%øÜÞú`5 çÎfÒØQõ8î®?~Þ¤õNõymÚYñÙïêŒk.†ºŒµ¿ö¦¾ÿŸªûmYVþ±QŸ5W!寮ü|"®D‘™u™$áêìL¯žÝ4¿HQ1±\ ‹À·oo¼<=ª¼8|ìY7³™1e"¦¦¦³sÏ~ìlm3b(;wïãû-¿°ð±G155¡¼¢œÞ={hΑ”””püŸÓT( òëGûÊ ™câ® PâÙÉNn155Ñù )iiüsú }zvÇG¯æ|–¤”T¼<Üñí×G3>öj<Ñ1q˜˜ÈéæãKå¹8Í~)(àtÐYJÊJéÝ£»¦Éš_PHhx™Y7pr´ÇývvdçäpàÈq&OË¥Ðp²³sèìéNw½ © !¡á¤¤¤bccCŸžÝ4̪]ÏÌ$ìr$ÅEÅtöt×ùLêýïׯ=Ü5û À ®Î·?‡z¿Òµ‹’‘ѱôêÞî>Þüµ{Å%%Œ5œö66Ä'&¹…}ûrúÌy¬ÛY1з_“ J¥’ ³ÈÊÊ¢gw<Ü;ÕùXø_åյNj@ª‡#å…@1ºw†®ò—I`  >èŸ]¼ˆQÃîvq„»H ÓÐ -د‚š8šœ8Ø"Ôçû«Âÿ6q,4§†7#ÃEX„Á˧gó6Åß&Aîuâ  ­–8(B«%¾ "B«%P„VKt‚‚Ðj5¢DD  ÷6Ñ¡Õjp 0%1þN–C¡Ù58­ÚÙÜÉr‚ 4»FÝßαCí3 ‚ 4¡¬Œ´Úgª†8(B«%P„VK  ­–@AZ-€‚ ´Z"AhµD ‚Ðj‰¡Õ(B«Õ¨o‚­[BRåbh׳2p°³§oïŒ3ŠN;Þå BÍD õV^^ηßÿÄÞC‡Q(:Ó““ILNf×¾ƒL?–…sgcl,3¡ejqGf`ðY“026ÂÙÉ ß~}icf @EE¿îø‹i“&`aa^ëú"£c(((À·_ßz•ãZb§ƒÏV;½“[GôïË¡£'6Ŀڲ¤¦§sæ|3¦Lª×ö[ªòòrÞþ`5¡á˜ÈåLš4žáCpsuTxüŸSì;x„]û”œÊ;¯¿"BPh‘ZÜ9ÀSAÁ;OAaׯgñãÖ_Yòï—ILN ¬¬œ-Û'¯ ¿Nëû}çn~ض½Þå(//§ °@3lûý’’4ï‹‹‹INMãËo¿#"2 €”´4~úõ7õ¤¦¦ó×ß{ê½ý–êÛï"4<{;;>ûè=Í{ o¯ÎHHx{uæ‰ÇçòÉ+°·µåRx8Ür·‹-µÈ?˽ºû°hÞc€*ˆV|ô1ëÖǪoÕ{]¯<·„òòòz/çåé—§‡æýÞ‡™2q<½ºwÓ™ï‡õë°±¶ ëÆ :ÊœYÔ{{÷‚„¤$ö:Œ‰\ÎÛË_Öœã+--åÉç_DBbýÚÏ011Á£“o.{™—^‹=û2iÜhM-QZŠWÔgllÌŒ©SˆŠŽ¡¬¬Ìà<É)©8|”;wr)LgZDd4¡á€ªùü÷žý—püŸ@þü{7Qѱ .[EEû!?¿€7³9rüŠ‹‹Øº}»÷¬qÙø„DvíÝÏác'(,,lpšÓÃGQ(L?¦Nܘ8n4 …‚ƒ‡5}¡žZ|XZš#ÉdÈŒŒªL‹ŠŽåW~%’+QQ|ðé֭ߨ™r)”SÁçUóyý÷?ðÜ+Ë9ññ‰I,{ç=9Ö ré7Çe’¤úi$C&U¿kÿܵ‡>YCFfÁgyæÅ×ÈÎÉiPšSHh8#†Ñobb†µk4µ?m#t–„–¤E6õŸ¡‡F2úu@ï.ùö¿ŸkÞŸ»p‘«>aáÜ9˜Uvœè{å…¥tñô ½5ìÚ͸Ñ#UFÛö6ŒÀù‹¡<ô¯ÕΗ–‘Áæ-¿°î³U8;9ðÉÚuü¹kóç<Ú¨24µ¬¬¸ºè6e?÷"©éüýëÏ:ÓÜ:ºp=3³J(õÓ"02&–­ÛwPQQÁµÄD®&$²òÍåç•*k]ÅÅ%¤ed “ÉP*•ܸygÃw¬¶0¿ÝcëÛ§;÷ì¿ó¢áW°²²àJd4W"£$I)©ÍV†;훵Ÿ1mÖlÃÕO¬ü„–¤E`Y™ªÖDnB€ÿ ^y~)¦¦†kseee|¹á;"cbñéâ…••e½¶eÖÆ¬Yñ™_P€„ÄõÌ,Í8g'G\]ZþãììlIJN!)9o¯ÎuZ&1);»¦,š 4H‹ @í^àÚ>v’k‰I|ññ‡£P(رsw—°á(*.á¡™3Éî‰S°ýûô")9…ãÿœªs;@¿>½š²h‚Ð ÷Öo ·[RŠ Õ7ndßD’dš m³snÝ­¢a"—“_P@QqÉí‘Th}[¢WîH’Ä®}5÷·DãÇŒB&“±ïàâ5ã?÷’Á×ñ ‰ì?t™LÆøÑ#›±¤‚P7-²XSSS<=Üùaë/L›8??¶ïø‹åï®ÄµCBÃ/c"—ß•²¹wrÇœ•«?¥Kg{xÞ^^äæåñÝ[˜2aŽö<½h>_|½¨˜:º¸{õ*cFgðÀw¥ÜuåæêÊäñcÙµïï}ô o.{Nn|³öÓ*óÆ'$²âÃ)++cúä ttu¹ %„šU½®$­AV91 L+×Å‹æOhkQ¿ómu!I]\èàäXí<þ~¾”–•aogG/Oü!“ÉèàèȼÙãâ쌧»;¦¦& I8;9àêâ‚$IÈd2zu﮹\CB¬=»ùÔR0èÕ­ææmuʪ½>¹±1Æ P(ioÛžŽ.Θ·mË ¾äÐÑUõÞÝ­##†A&“Q^QAßÞ½èß·F.óiiúöêIdT,W8tì·òr±hk޹¹9åå\½zßwîâË ß‘_P@ß^=yaéÓ÷\s_¸wä³~ã¦ý@2PZ9”倢r0x¢ßPלvø©ƒÏ h XVþçOŸøL<¸u*//gã[سÿ`•›!¨ÉdL™8Ž;'‚]¸wee¤á;xø‹@W9Å衽 ¼çšÀÂÝgllÌâùs™4n4#$4œë™×p°w _Ÿ^Œ=R4{…O Ð`n®®,œ7çnCLœ˜¡Õ(B«%P„VK  ­–@AZ-€‚ ´ZMzÌ[Ú4åêà·G‹îváž%j€‚ ´Z"AhµÕÎÊH«eÏÆ¬^¨ƒÚÿA¨N£°¿ÿ°§ŸñoÌÚ…ºß·Z· A'¼¬h ‚Ðj‰¡Õjôe0‡Ž%6.P=×ÅÕo¯.t©ã3#´qððJJJ0„•lˆòòr¾Ýô=>ôP””sëÛ~Ý®yommMŸ^½èæÓµÁ娯 ßmbòÄ ¸8;7Û6¡µjt ðàáÃ=~‚¼¼<²nÜ䯻˜3¯¾þ9·êþ|Žââb÷8GŽ#!1‘ظ«*WYY_­ßÀ­ÜÛe8y*¿wï©v™œœ¾Z¿7o’››KPp0sæ/`õ§Ÿ5ª,õñÝæÍ¤gd4Ûö¡5»#BûõïÇ+/¾ yŸ”œÌK¯.ãÝ•ï³æãÕuZÇ¥°0rnÝbÇÇ«5Ïú½ÓBÃÂHLJbÚ”É5Î÷ü3K°°°àÌÙs<ùÌRF Æ MÿÌcccqeAh&MòMŽ®®¼ûÖ›<2wCCéÛ»·fZЙ3ÄÄÄâââÂÈáÃÉdÄÄÆñçο)++ç›o70îc Iœ &!1 sF Š]åóeÕÍÕÅ‹jóRXÉ))L™8±J™.^ºÄù !ÜÊÍåë ßÒ£[7† ¨õ³ àG¯ž=8w!„AM`p0ׯgâäèÈèQ#1­|¾ˆögŒŽŽÁÕկΉ‹eôÈ‘šé×33 ¦¤¤˜€Áƒqu¹Ý“kllŒÜXܧVšC“u‚tó銷—aá( ^xå5¾üz=™YY|óíF–<÷HB¢êqŒêæªRë¡æ—.…²{Ï>Ã’$$IB’TÛdu¯e¶³²BndDYYÌ}œ#GÇ'k>gö¼Ç)--ÕÌ»ì7ywå$$%±é‡xdî<9¦™~îüfÏ›OÄåË\‰ŒâáÇætæŒfºÜX®yħ M«IÓ\]]ILJ`÷Þ}\¾r…½;ÿD&“©—8óAþ <Ͱ€!L?Ž‹ybÁ|ÍòŸ²ZçibÎ}œþÅ Ï=[ï²ôíÝ›þýú’˜”¤³Úäää΂yóËåìùëM™nåæ2vÒ‚ÏžcXÀŽ;ÎÙóøó×mXZZ¢T*yyÙrͺ ï¾ÿ>O?ùÿšq½zö`íº¯ð8M`AhNM^Õ°¬<—v:ø nnÙµg¯fšµ5ñññ bpYuФ¦¥‘•uWW×fé Ø¸ùLML¸•›Ë‘£Ç˜yÿ ú÷ë«)“B¡àZB"999¸8;“QY¦SL7KKU¯³$I¸¹¹‘‘¡z`PJj*‰Iɳs×nnÞÌ&þZ¼fÛÆÆÆ¢(ͤIÓ’““5b8¹y¹”––‘švû«[Ç ¥_ß¾Õ.|ö,}ü ŽŽŽx¸»“qý:NŽMYdòóó)•ËéàèÈšWÓ]ë™Á?þ¼…_ÿ®ÞÞ899QTtûn,iéøùö¯v½¹yyÜÌÎÖ¼xbÁÍkQ„æÓdMBRü|puv&95•§žXTçu¼þæÛ¼þÚ+Œ5 €u_£iR«;>ŠŠŠ077¿£e×îÖv-!µ_~Åž?ÿÀÞ^Õ¡™ngk«ðúÔ×ö9‚ݺœgù+/c_ÙÑ#BÓj’N´´tÞ~o% æÍÅÉÑ€Ñ#Gr*ð4W"£ê´ŽŠŠ nfgcbbª—uã†æµƒ½=’$¬WPX¨y­ÈŠŠ Í8Ò+›£ ‘™™¥Z©ª×·¬¬ŒÜÜÛ5 ndÞÂIDAT¹üØ»ÿ€f>Õ2™š×ÖíÚÑ¿__6nÚ¬Óy£¦T*Q(”——7¸Œ‚ ÔÝ©ž á³ÿ¬¥¢¢‚k ‰„GDðØìGY0o®fžüxdÖƒ,\üÓ§MÅÒ‚ÓÁÁüçÓO°mß¾Ê:ŒŒ5bo¾»‚Ñ#F’šJtl ýühÓ¦ 3ïŸÁÊVq>$„ôôtB.^¢G÷™áÓµ+_|ùÌš…Ÿo†øâ«õxû½•xwéÂ쇪×çìÙ£;¶íÛ3oá ôó#äÒEnh…òä‰صgÌ›Çè#IJIæRh#‡×Ìóú«¯²ôß/0ÿÉÅøHZz:ímlx~é3ÄÄÆñä’¥,^´%‹Ÿ¬WÙA¨?C'›$­AV91 L+×Å‹æOèàÚ I’°²²B.—caaAÀÁ,}ú)† ©rAsÀÁøHIq ¦ff̘6w÷ÊËS$¬­­éݳ§fþ1£FâäèˆÜDÎØ1£˜?÷1¬¬¬ðôð`øÐÜ;u¢¢¢‚aCxúÉ'1·h‹·—£†£¤´”NN8:8à`oϰ€ŠŠŠpuqÁý“Þ'—hcf†Ÿoƒçáär9S'O¢MÛ6´³²bޜٌ6 gggìíí$‰É'âÖÑ ¥RɘQ#177G’$† €mûö̘6kk ñöòbú”ɘ™™acc“£#ãÇ5Ø¡ª´äDÖoÜ´HJ+‡2 PTU›\¨BÎÐ8uø©ƒÏ h X–€ÿùÓ'ÖÔv;,^}ý ºùtU]Ø-Âw!è$¾ƒ‡¿y@>P£„Jô‚°¶s€J½Ÿúã= …BóúVn.§ƒƒ1lè],‘ ´ ÕeTYU—s€Ú+ª±:)ÀìÇçÓÉÍ ;;;ŽŸ8Éófišì‚ 4CùTkNÕÖ6âö¹¿6€9ªf°ÿùÓ'þÛø2 ‚ 4žïàáKQ5ó (AÕ® š&puUÐ Ušþ•ïÛ&•óW.#Ó[ Bc©ƒK]Ë+Gn¥¨Â®UTÅT @íõuoëoôªN‘6¨‚Фr]FˆáÎÓÀ TYTŠ*èŠPuzÔ©çW›¡Tr;¼ÔUFí–¡JVuÐ)*ÇU"üA¸óÔyTQ9¨³H»¶WNõMÞ*XS P;üÔ¨:uÀ©Çɹ]û(BSЯ©›Àêš úú?u<ï§­>MàrTWª5^]#T×þÔ(‚дP‚ÚAXŽîu5ª-µ«œRå†@7µ;?´¿E"‚p')©Ú2U^™ÖOu8ÖXûƒÚ›Àp»÷¤Bk¼zêZŸ?Ašƒ¡T÷OTh w´ ¬=ý6¸?Aš›¡ÔÃZƒO­¦À’ üÔ;CÁ'P„¦¦ýMí Ô­?oµ–¤÷Z?ìôk}"Ahjú—¶h×öôßëϯ£.¥?Ouµ=~‚ 4—ºÞü Æfp}B«ºyEð ‚p·TpuºaKCÃK„ž -¸K• ‚ ‚ ‚ ‚ :þBtÎ ùÛIEND®B`‚././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gtk4/images/layout_stack.png0000664000000000000000000002053115074674453022653 0ustar00rootroot‰PNG  IHDRh€‘ÞÁsBIT|dˆtEXtSoftwaregnome-screenshotï¿>&tEXtCreation Timejue 08 dic 2022 22:18:23“«Í IDATxœíÝy\ÔuâÇñ×p 7J"Š€Gæ]™ÖjjæZvºÝ÷VVÛOÛ²Z×úUnÙ®¶ÕÖ¯Ú¶ÓÊ#--Ó5MÅ»ñ–Kó¹oæ÷ÇÀÀÀ^ñýÜÇ<„™ïwæ3ä¾øø™ï|DDDDDDDDDDDDDäœb9KîSDäl`;™wv2bZÛ}(Ô"r®¨-Ì'ìÆF´ú~7oiJªØææmnih<]…ØRÇ×}ӹб­Ž¯]íW§†„³zx-U.Õ¾¯-Ô""MIõW½”Uû¾úöõr7ž®¢\fWEZDš:Wq.«åR=ÞU÷¯•—ƒ¨mÆìYåOOà< |Êï[‘¦ªjhK€B 8d¥å—²*VÝ×B=‘®/ÐÕã\1C®ˆ²tøbά{_ÒkB°)È"rޱ`³•Ù2â7lþüÆqãæ»€\ìñ¶PéŠP×éúBZ}I£j˜½óz÷îÝgî¬ÏÞ´XhÖè'&"Ò„ØàøÕc¯hÛ¶mt {¨+fÕ®–¸ûÞØê‰óQnPËd¹¾·iW]ÚðÆ>sö:íÛ³s¶BNxü""M˜­¬,=¶ã|ì3éŠ5éê/:©kíØÕ‘¡±XhÞ˜w™——Giq16ÛI=¯ˆœe òÉÉÉ:ÓÃ3ÈÃÃ_BZ„|¦‡sJX<D<,|||°ú„R˜—OA~.¾~þgzX§‚•Ê~V tÅ¥Q3èÚ–9<º¼‘W>sVœE¤: ¼}|ÈÍÊÂ×·Iº²5O‰Q+WµtuºÐê‘öhèêqII1ÁZw—<=<(È/8¹g¼7GÕÓcÔç3éÚ³«ºƒ«#5|ñØfÓš³ˆÔÎbÁf+«»³SÕ8»:¡œKuíêXèªw.""î©ÞOW}­¡±g³³œäÞ)×$ÛÒ¨så7älvÎ×5ÉŸ¡ˆœqM·-µ}"U­{HE#—8šîO^D¤jfCíxƤVpˆH}šx&ê&wPrii)‰;w²s÷òrs‰ŠjCŸÞ½ñ±ZINIaÕê5Ü2þ¸ëâ7ŸŸÇÔ»í²¸ìÙ»///ÂÃÃé÷‡ËhÞLçž:[dfg³|åb£ÛÒ³[çZ·ûýÈQ6oûƒºu¿q«&¶mÑQm5®Ý_ÌRßavupõ‰u]N½={÷rÇ}bòÿ>Ϻø lÞ¶iÓ_eÊó/””̧³fŸ’Ç^»~=ËâVºµíÒ¸8V®^M^~>GŽeÎósýlýå·/)9™·ÿû¾ÓueeeÌxý 22Ž7hìÒp?¯ßÄ’e+™»à›:·;ôûa¾[ºÂíû[µ–É©׉îo††¶ål¸4N“™A=zŒûÆ?ƒ÷ÞÃM7\ÅRù/‰ÒÒÒ382×.êÙ“Çïø~⤧yïÃxcú?ÝÚÿ÷ÇùjÁB¼÷§ë?Ÿ3—ëÇ^CHHó“:^q¶nã®=‚Oç~É¡ÃGˆ;ÓC’{ót¾à|žžð(ÁÁö5eåäðÊ«oðëö|õùGgx„'2ƒnÔ/S÷êõ·ÞâÊýwãõØÛ\y›§§UrøÈaæ/\Èœ/¾ í`ZûÚµ{7s¾ø‚o/&''»ÆíÛ˜=w.ËW¬ ##£Ú“´ýëöí|üég”––¸5þÞ½.&++Ëñý²¸lÜ´Éi›?™É‘£G8rô‹/!¿ Ÿÿ¼ÿsçÏl|ðÑÇÌ™7Ÿÿ¼ÿùùyŽ}geòÝ?2kî\¶'$8ÝïºøxvíÞMÂŽDfÍËÂE‹ÈÍË=¥ÿ½NdVq¦>zŒ¤”Tú÷íCÛ6­Ù°y›ÛûÚl6wï凸Ÿø~ù*’RÓjlSRRÂúM[X²4Ž»÷Õ¸½¨¨ˆøM[Y²t»÷í?‘§b¦Ó4©jÓš„;ùÛ‹ÓÈÊÌ";+›g_œÆ¯ÛwÐ&2Òˆ¿ê'°Äa–•?­æê1£êÝ.ãøqúów²rÍÏŒ»ý.Çz0Àg³æðÄ3“I=tˆeq+wû]KOwÜþÚ›o1iòöî?À¼ ù÷ÛïÔxŒä”T&<1‰ÈV­Ü~÷äö ôèÖÍñýÒ¸åÄoÚä´ÍŸ|Âï‡àa±ÿ§óôôÄÃÃþµGùcyxx8=nâÎ]ÜrÇÝ,‹#aG"zäϼSeydíúõ<o!É©ilؼ•ç^~•5ñ¶™õå׬۰…¤”4¦¿õŸÏ[à¸-33‹g_~•u›¶ž‘Áëï~È‚Å?œ´çv.yî©¿Ð*"œÉ)ümê4þ6uû$Ê”§?ÓÃNóÇ©:Šã÷ÇÉÍË£m›¨:Ãf??>zï]üí'd¹û™ûå&Mœ@Jj*ÿ~ç]f}ü!Qmì/²Lyþ>ý|6Žˆ-[·ñí’ï™óéL‚ƒŸ—Íþ‹23+‡ O>ÅÍãnbð +\Ç¿ü¶wßÿ€ƒ±æçµ|9gvåö÷Y}„¶eÄð¡¬Y·Ž»ï¸Ý1†;n½…·Þý×½†è¶m׿ôÏéÜtÃõÜyë-Œ9’G&>ÎÐ+¯$6&lеKf¼ü¹¹¹ s +W¯aÈ AîýG8‡¬Û°…Aýûгk¾ùn)GÓÓ =ï¼z÷9t£†v|?kþB¾_¶Š¾½{9®=ôJ®¾j{öõãÅéoð‡Þ½ˆiÛ†/~KLT¸ûVõïËä©ÿdØ—ãççw2Ÿf“×â¼óxqòÓL~ñ%$§Ú‚ç'O"<4ô ήÑ3h[ÿw*—Ÿ_ï¶>>>Ž8ô½ôR<À¦Í[hÖ,˜m¿üÊ¢ÅKX´x X<Ø—”Àqq ¹rSœ«*).æ©¿ý./àîÛos{üÁÁAñÌ”gÉÍÍu{?w¤gdðÛö®»æjÇu—ôº˜ :vdãæÍŽë*ŸS@@Ý»v%­üç"•RÒ’’v‹ºw cûüýÜ^æ¨ø×Nvvû’’  =#Ãi›æÍ+æiÍùícÙž¸ €_vâççËOkãùim<{öÀË˃ß;OÏ mˉüÏÓÓ «·ÕñØÞ^Þx{{ŸôÇi¬&ñ"a›Ö­ñòòbÏÞ½D¶jØ àýýýgØËÊÉÁ‚…´C•aŠjÓš˜hûl45-î]»Öz_É))ìÝ¿Ÿ‰>RïãvïÒ…ûï¾Ëñý½wÝÉ ·ÜÊ‚oÔÃ:„Õj%(Ðù—Jdd$ÇÒ3jÙ üüuæAÖnØŒ¯¯•âV9®óõõ%~Ó6F ¾¢ÞýeçfRT\BltyùyõîÖ‚Ì,û'Ïäæç‘Ÿ_ÀÑc•Ën#"$D‡h6TÆñL¦LFJjš}ÍHIKãÙ©¯ðüäI„4?ó?ÓÓèSóxOO.ìÙƒ™ŸÏ¦¿¾ GåJ~d«ò ò¹÷ÎÛ3ªÛpôèQj{±±±\{õf¼ñoºtéLçNç»=Ž À.êуԴTÀ†Åb!??ßÅcUå¡úsÁéö!!q,ý-ªü<=#ƒ?\Ö§–ý]=Ž¬Û°™®:áëã㸮[çN¬\³ŽŒÌLBê9–}ö—_Ó¶M$·ÝtÛw‘¸»Î}2³rˆjÝ€°-hÕš‘C®8±'"¼ðÊ GœŸŸ< €)/N#%-¦MgÆKÏŸážö£8N‰>ʶ_埯½Nqq±Ómeeî°×ÅaÁœy_º¼½[—.ü¸<ŽìœœZï㺱W3tð•<5y ™ÙÙn¿¬¬Œ¤”d:´ï@ËðpÖÆÇ;n/,,¤´´òyøX­dçä—W¹¬c±Xðööæ÷Ç×…‡‡Õ¦5ŸÍšã¸nßþýìØ™È¥½/q{|{÷àhzwŒ»ž±£†;.wŒ»??_6lvu»…Ò²ÊÃ<ÏÂÛÛ»òû¬šŸÉxèÈQÇׇ%açnºw¶ÿ²¿øÂîü°b•cY¯æÃYœþžœ•NÓQûö 6º­}¶Ü¬!ÍšñüäIÄF·eß$#ŽâhKÚÇò¯Lã…—¦±>©ÓþÁ¯¿ýFLL4;5rƒ `ìÕ£YüýÜyß\9piÈ3OþÅé~žz|÷>ø0Sþ÷^}åe³qغíÞ|ç?ää³eË6Z´eÌU#¸fÌ(¾øê+}ü ¢£Ú°~ƒóÚw ((ˆ¿<óWºtêă÷ß‹———õéÍ+3^cÐÀ\5|(±11Lz|“þ:…½û÷ѲeKV¬ü‰ÇÆ'å—6=:~xC¨ ?Ÿ°–‘'6Úz´ŽŒäÚ«Çеsg¬V+-[¶dôU#wÃõX,`f͚ѭê:²ÅBËðp:´k@ûví>d0JJJéÓ»7—õ郧§'žžžŒ9‚V-),,¢cÇ\wõ5øúú¢ÚDÝ6OO{(33³ ¥Y°ó?{- Žû gôÈÜsGåÒJpp0#† Åf³ƃ÷ÝËù:о};üýýñööfØÁ”–•JLt4^^^ ПÀ€¬V+íÛµ#0 Ö‘‘ ://oš7kÎ}wÝÅ.íSuDޱW^c¡C»v´ ?uây(5 o«µþ qôX:}.¾ç…Ô¸-,´¥%%tlëô&)«ÕÊÅ=»“——GdDKºuîDûØh°@û˜hn¿é:¼¼¼éÐ.ƾƒn»éZ¼<½ðóõeÌð!\Úë"Çýy{yÑÿ²>D„‡QXXDófA ØÀ€:uh‡ŸŸ/>>V"#ξ`-).n’Ÿîýú¿ßúHŠÊ/Ÿî]V~q9Ïvu⎪q®³/öO¥ *¿\¶'ñ· àñôcté©ßèRióºUø•‡E ?7—–‘Mï<"í;u¬²Ë/y@Ρ®± Òè%ŽÆ-«è'©›*Q©É¼“PD¤©iü‹„ú5'"§‚ÚâpGqè§("§‚ÚR¡Iœ‹CD¤):}¶ØØ÷tqL°ˆ6›ýpXq8mGqxzx’—EP3H^Dj*--ÅÛê­Ž*NÛ‹„ž^9”J@`ã¼Å""ØlÜd0íÛŲ4.®Þ}ÒÛg¡-ÃÃOñèDΚAK ßý°”+àŠþýùlÎ\ ñññq¹ý‚o¾á‹ù xöÅ©øX­ÄÆÄðÄ„ÇHHLdÙò$¥¤b±@— :qãu×âçççØÿË )-³Ñµs'¾ýî{R"ªu$7ßx#-+''‡ù ’˜ˆÅb¡KçÎŒ=ŠÙóæ³wß>¦>÷¬Óö[·ýÊ»ï¿Ï´Ÿ'00°Þçž›—ÇË–ñëo =–NxX£F £G÷n5¶Ý»o?~ò)‡&&*Š1£¯"¦mÛÛ-]ÇÚuëÉÉËåÂ=¹áÚkðôô¬w,"šA‹“}’ص{7CÙ=°?òóóY»~}­ûÄFÇн{WúôêÅÀþý¹¨g²²³yèÏسoáá¡X­Þ¼÷áÇŒÿŸÇ)++s쟒šÆÿ÷6Oþu Å%¥D·bYÜJn¿ï~Ž¥§;¶;œÌm÷ÞÏ’–ÕÛ‡y_. 7/Øè–._Áž½ûœÆ¶hÉÊÊÊÜŠ3À{|ÈÌÏga+³Ñ¦u+~KØÎ>ÆOkÖÔØöé)S((( Md+âVýÄ]÷?Ⱥ Î/8þýÓyeÆ¿ &2¢ïü ÿó—IØl6·Æ#ç6Í ÅÉ?.%¢eKºtî Àù;Ò*"‚¥q+Ø¿¿Ë}ztïFaqó¿ZȨ‘#hÓ:ÒqÛâ¯æ9͖׬]ÇÄIO³iËV.¹ø"ÇõAAÌ™ù‘cÛ›o¼o¹¯¿]Ì]·Ý ÀŒ×Þ ºM¦O{ //翺!Í›ÈÒåq´o @II q+WñÈC¸ýü¸÷{x¼ãû²²2îøQfΚÍå}û:m;ãåi\س{ù~÷ñð„‰üóÕW™õñGxzz²nÃF-^ÂÌþKl´}f=zÔUÜz×=¬Z½†—÷s{\rnÒ Zœ|÷ãR®p9eeeŽKÿËû²zõÏ5øþªÆ Ï%½°X,$';µàçëã´mxXÑÑѤ$§ö.×Åoà–›ÿX#ÎV«•¡ƒ¯déò8Çuë7l¤°°ÁW t{¼¾¾¾Nß{xxЧW/’’RjlÛºu+Ç×þþ¾Ü×$§¤±ÿ@ß}ÿ=»wsÄ 6º-çwì@ÂŽD·Ç$ç.Í Åá·í ¤¦¥1kîÚ·‹åÇeËп óæçµ$îÚMfV&»vïqëºó;v %5•öíbIJI!))™»ÿôÓvÉÉ)t-ÿŠH]hqXòãD¶jÅä§ž¬qÛ³/LeYÜŠ:/¯€‰OM"''—‘Çѳ{7üüýY»>¾Ác³•Ù×lsrrjݦKçÎÄ´mËÒ¸´jÊŸVóⳓô8K—¯`ê+Ó>t^؃æ!,[¾Â­#Y 8LÞÞ´jÁ£ã¬±mxXXƒÆ%ç&ZûZëÒeqŒ1œ‹/ìYãöþ—÷å»–R\\Œ···[÷¹.>ž-[áÇE ^¤³X, _tTkã78fª®\5r8ß.þŽÎÎÇ×LJK{÷nÐãü÷£¹zÔ(þ瑇×mOHp¹mõúÖÅÇÛ`‰ŽàüŽX¸híb¢iÞ¼yƒÆ!Zƒ–rñ7‘ž‘QëRôëKnn.ñÜ[´§§ý¯×׋“•MFÆqfΚMiiÃßaÑ’—÷㣙Ÿ±jõÇúxü¦M””T.—Œ6”¤”Þûð#†‚‡GíÅ­V+$¨\÷ôôdã¦-$îÜEQQ¿mO nå*—ûÿý•éHN¦°¨ˆ•?­æí÷þËo¼ÁñËè¶?þ <9y Ê×ÜsrrX·>ÞégàççKJJŠÓ‘-" @K¹ïËÞè|Á.o¿øÂ ñ÷÷eYÜJ·ïóò¾`Ä!¼öÖÿ1|ÌXF޽މ;]+ìŽgžxœ‹zöä‰g&3høU :‚ç§¾ÌÁC¿;¶ ¥÷%½Hܹ‹«†«óþ<==5|ïü ÃÇŒ%;;‡‰~„cééÜyÿ 6’''O¡s§N5ö  ¢¨¨q·ÝÉÃFòô”ç;z4÷ßs—c›ÐÐüû_Ó),´o7xäh†Ž¾†¦½â4æ«Fg˶_:êjÖü¼¶Q?iš\ý[ÓR~ñÀ¾â øþ@Pù岼ܜ§krêmOHÀÏÏØ˜˜Z·Iܹ‹²²R—ÏÉÉaçî=tíÒ«Õé¶#GräÈZ·nM³à`’’Sðóó%,4€Ô´4233‡öUص{7ÞVk geg“’’BPP3ZGFÔ˜%Oíu6mÙʧü×­ç¾gï>ü‰hiSLaQIIIx[­DµnMYY ;oVÉÊÎæðá#thߎC‡~'3+‹˜˜èÏ»ªãÇ“švà`×c>tèwò ò‰nÛ¶ÎY¿œü'kìòKP%@`+¿8(ÐÒ¤”””0úú›¸å¦¸ãÖ[ÎôpD€ÆZ¿ª¥IùiÍÏ?~œ¡ƒ¯<ÓC9a ´4)_/^B÷®]iq¦‡"rÂt˜4)Ó_šz¦‡ rÒh-"b(ZDÄP ´ˆˆ¡hC)Ð""†R ED ¥@‹ˆJ1”-"b(ZDÄP ´ˆˆ¡hC)Ð""†R ED ¥@‹ˆJ1”-"b(ZDÄP ´ˆˆ¡hC)Ð""†R ED ¥@‹ˆJ1”-"b(ZDÄP ´ˆˆ¡hC)Ð""†R ED ¥@‹ˆJ1”-"b(ZDÄP ´ˆˆ¡hC)Ð""†R ED ¥@‹ˆJ1”-"b(ZDÄP ´ˆˆ¡hC)Ð""†R ED ¥@‹ˆJ1”-"b(ZDÄP ´ˆˆ¡hC)Ð""†R ED ¥@‹ˆJ1”-"b(ZDÄP ´ˆˆ¡hC)Ð""†R ED ¥@‹ˆJ1”-"b(ZDÄP ´ˆˆ¡hC)Ð""†R ED ¥@‹ˆJ1”-"b(ZDÄP ´ˆˆ¡hC)Ð""†R ED ¥@‹ˆJ1”-"b(ZDÄP ´ˆˆ¡hC)Ð""†R ED ¥@‹ˆª¡¶U¹ˆˆˆ{ÕÎúm«ögõëED¤~µ5´Î–º3ƒ®zGeåZDÄ}®úYoGÝ]â¨zç¥åqOE74Éõªåz›‹‹S ý'~€ð.¿/*£oi̳9 U·¢“%@1Päã:ÐÕ/5Ôèê\ýA7þØí‹=Ò^€' ´ˆœ{ªº{+‹€ìÎÃÞÎ0‹vh•q­:{®xÐb Ê—•_çY~± 8‹È¹§¢—³åŠV”ÿY芙tõ™s`×5ƒvµ´QâŠW\çMåìY‘sQõ mÅGÅLº¨ü:WK.5d‰£{€‹ª\_1£®˜=WZDä\T5Б®ê*—9µÄQýÁ*¦ì–òçßU_´ ´ˆœ›\TQäâ*VÄ»Þ7®Ô·ÄÒX­IDATAùƒ@å¡uU×X*fÍŠ³ˆHíG¾U¬=×v4‡Kî.qTD¹ú‹â,"âÌU¤«ÆºÞ0W¨+¨V±«0+Ð"r®«úNÁª¡®þuõmk¨/¨–j_WqõY³-"çºê‡ÎU-»zcJ­3iw‚Z}›ÚfËŠ³ˆˆ»'Gªs™£!Q­m[…YDĵÚìÖ¹8WEYD¤atP1Æÿí_Ÿ§ îŸIEND®B`‚././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gtk4/images/popover.png0000664000000000000000000021033415074674453021645 0ustar00rootroot‰PNG  IHDRÚ·©°—uzTXtRaw profile type exifxÚ¥™ir#;„ÿósÜÃ5bn0ÇŸ¬’,Ëêî×3VXU®…D"A›õŸoó/~‚Á„˜Kª)Y~B U'Å^?í|;Î÷ù™ÍÊ}õÛuc×}*=GÝ(é:ºÇõû…ÇÑ5ÎâË@eÜ7ú÷5\G)o]öX¯éù¼ª÷@^®î ]˲©–üº„¾î%Þã7]_¡|7ûÇßïÍÈ<^dyç-ßÞËe€×_1¾qCøyÐñ@ã–~{ïîÁpÈ'?=*m55||è[TžgoÑŠëµ·h¹ñoNNÏãÇëÆÅ·þ9¿¼ÎÊ&ß®”}Yôæ}ýÝ{–}ÖÌ*ZH¸:Ý‹z,ñœñ\g ºLK6ó"ŸOåS@õ ÓÛù W®í‚›®¹íÖ9701È2’9âÏÅâ³T^ãôã¶d_ýô…¸Žöàåi‹;ÓV;Ì™­0ót<*ŽÁý1ûÂÞš Ω/ã•§Ø%¢ÎÆ œ~óqûvj<~|Þ4®žFõ²¦Hűý¢G÷ÅþÚó`äxå Ëó1uÄç‰Qs>ºälÉÎáÈB€¦‹Ò‰€‹Q&FJð>›":5¯dw•(\6\‡ÌˆDôÉgbS}SÆ üäPÀP‹>†cŠ9–XcK>…SJ9))¶ìs09æ”s.¹æV| %–Tr)¥–V¥zH3ÖTs-µÖÖ˜³1rãíÆ­u龇MO=÷ÒkoøŒ0âH#2êhS¦ŸðÇL3Ï2ëlË- ´ÂŠ+­¼Êª«m ¶½ÙaÇvÞe×ÝžQ»ÃúãóQswÔäDJÌϨq5çÇNé$j̘˜àˆxÖhјÙâBœÆÌV!+¢`dÔ˜M§#‚a9‰Û=bg䊨FîÿŠ›Éá[ÜäœÑÐýeä~ÆíSÔ¦–¡q"ve¡:Õz²o³œ£Ÿc·:VΰKèÃE¿‹ÁÒŽÁi;™Í±(IKjêH$|O~û¶YM¤ÍòcJnnÊoHŸ>ïe\؃Ø׃2/í#4`[^‘ؘ'1MÿZÒzÝ«÷àwíÛK®Õ­UD´ÄËRwåñâSݻؑùnÍïuϤɮséºu6Ž:_d{L–æ]Vø‡©–¬\jÓ{ÒŸ;ëÜ1ïNŽëZ4l©loOXŽ›ïwÔ[ㇷÌñBˉ½†‡à”/+]ɈŠ12œê*ê„Õ‡2·ÍC­ªÉÌâçl‘‡Hë5S ³éªô ¿z³ð­©Jfj K' uŽÔÈš6ëSh¦-²3+(5‡¶×´ú[ÖDí,˜%.d…oäƒÈQH¦ÚVªŒê:,E.®Úï®O Ü7T¥]ˆP<2Tf'ÿóöÙ¬ö÷„Wý¯"ô[¬ãNs–¡QÇMI¹ó·ÃÆ«ûaßJ‚…d 7Þ ëŸbÝü;¼°!‡¢\c¬&yÙ=à²Õ d¥ö3äüU*|*°Áwšäù$ùýR¹Ì0/Y¾~—å7à‹· v®…h÷¸¤lËkÀÇL[Ý2V÷k•ÆDÚšQB†Õ²´Ô]ëM5‚‡¢%g©> §R©„Íàè©bÐbs•™»'#biÔ„_Gò^ûãj mŸÕ‡Z×Èi÷V¦™±ÍRaq¹„‡Å7ìï±íÞÚØJ,Ô…:iæ F&™JðkNºøjŽ„YuŠµØ‡ˆ)»«‚ÜG\E ‚ø±Ø¹nV%íf‘@xMϑҶ›ZÒìn‘±Ó§ª+“*ñÅY¹~­ìÇÊg Åëž‹*3ŒœÈœ ¿­ÐZ]#Ë¢†(ÔËô’ÕwJ:yì„t³]¢–rñ™x)w *$õYí[½R|ºyÌ(Ȱ¹Œ=4d‘»ºdÍgQ&êÓÁ¤QÌ XfÝ9$ß%Œj‹kóòF  àè ô£†F.‚A›M·ˆ;²áñºmMŽäcnzǰ|á Êè«XÕT»£—U€Œ{wäí­ïp$3:c_ýÙèbÚìÊ}‘V•¨È -‘±xÛü#4Ó/Éžu!∉¬‹iö*%ÐÖÑ2 ³<|¢¥¯Šñ+¤©h#Íeqh†@rG#l&âîWyi¾áÁ:$ÚH z†ÆFÌJ8WƒºÓ¶¨Ð¿0-gkÛAJ8»Ð¦'t`M2,ä¸RxÆÁt6M§üê?ñCóDÝÈQÖj3ý!!¾ò˜¥À+µœøIng+4ªVø¡Pú& ȃ¶‡úµ„÷†šcé±3o· ÈõËÛÎâ,H<]¥°Û­^ØX§ÍVTz;¢Éô´Z£Ñ *Kˆ4W5(v<å$&¡ÓrЃƒÒ¡^ ê×¢JW<˜|Ùb§¶L©U›Ñ…LÔÂGå àèÐßFúë©ó·œIk¨p;i[P@-ÎA³D¥$×Læf÷8X.M<UG©~*Ø&àÂG5DÝ4Tx‘=Å—p?® (‡›*J Yêôi =CcäVÑI? æ¥ÞŒîWEŠ0Ù1ʲC[JäáFíü!1È>ÝëwÔXñQjÚj^"ØÂ÷go¬6e{£±€Çu¬d&墼Y!¶Ñ®“ûör!*¯û3^=3ã¡©ùM8Ktãçñtëø6sã áAïÐuRÉ`lÊ DNI虂Ÿ²TrÊDâ"ÃY½è4P$DˆÐw³e‚v@ šN¥¦ŒR»ŒºLRƒR‘¨jlbÁÐ]€Š¼§Šé§r‹×¾¢² Œí¼£ËÓ`’~dg9ÓRy‘&¦Yõiê`Jì®$°nh>ÏŠ)A»×Ft;=4±×쫲/?³¦¥”Ïa¯~-:z&2ePÛ%—Ú£ípH‚ápÎ(p¹Ät»¼ >4€‰@>;‚½5š|Z&šxí¾a¬[&£BY½4$‡2"Ýu ŽŽìTÂ9ÐÏSi¾¨a‹T±âlÔ R”9dE/«¢k¨kÒ Æ™·H0Ä(ž›}dŠÀ¼œ6Gè½ç¹ÖŒ¦[)›ð‹ ,[ ê1kzøLh’"³nj1É2¶¨T¨¦»øpïâw+¹#˜û¶T4Øži¨0fÝ:O€ÐiŸŠÂÎñ'qÈÆ5‚‰Øeu´@©ëÈ êg[02® Ö“ɯ’î<·lP7‹Ôœ¢ƒÌ¡.ío–†ýëúŸ‹jA›E§Œ%œŠOA!×Lß/R´Ÿ§RU£Û:æ²jëçÙ“@3TÝ5F³MO¦?!ôh†&Ý,SࢶCâÇÙƒ~Ök_é£Ïé.`ÂmNÆÂj%i0T©:¤+ZèÌÅ5­™öNUHËi‡ÓÈœNóÚ©Jí{­"~Ñ ’:WoGu÷ªxTíá wÿ…pcÙU7j“Yœ´üD^|®ükŠ­ïïé-ë~àôí®5ô–¢›ù€7Õ¤e²Ìedn Hž]Û3%¦¿$ADR©Ð•†RßH™à®“ÑQ儎׆è興zÈ;’§ø‡®qË;áqý_‚¬©§òá§Sª‘qTŸÐbO:0û°Aôô_Ú¤z¤ÍüA×í1ìƒ+†®•&zª×ÍP2µSEGOt‚jÔk-Þ#qáî®Û[È.˜ŸÞâ´Õ;äV‡þÓAûàÛu‡\@p·…5)£Pt%[Ä]b4Îkƒ9:oô ¸ÍÁp1¡'ZÕ½#ë‘5$ðUú'ÈE7 žUÏr¹¨T£ÝOA ¦Ævê¦2¸wÖ 38U¯L%]ÚL¸–å#2iÞ'’œ Ýï·0´uOVªÇ@w ¾BYõrŠòüV”Ÿ5y‘gNMyžy‚ŸÎ£Ï=Â&¡5Õ15ò–J13õáGVaµJc©qçÞ m8ršºb¶Ø ÌTHR/'R¦ "Ј1{ŽTíîÆ(Uw,²Š €xÀA(OHl7Ž"”uÃIïè¾æµ3ä㘠Æ-Ì¢Õfnd+Öâµ£DVx¯iËk‹V͵~2T7l´ÖÍœ³‹û{ÝiKT»F÷tÿy×h³À‘9ÔË5Æ|²æìS‹M®µh7tV£°„Iu#è¶MîX½ùÝ+ú¯«ß %ï6Ó`g¿Æ|¼táøý5ýó¬!Þ›¬ÇÙ×2t+ѯºÐ•øË?Õîoy¹ö÷ÖE»^¾{¸T¾\j.9uñÝñj–*Á%µ™ßT0žJJŽ5Ø®üJmη¶õÈ­iz¥a’Ð"UÙ+#† ®2`/)©FE¦–1Dãv4ª=…»€2z†ÒˆÍQ: €OÏ’èlñÞB_#†œ«MÿÙÉT-/õB^VcXN¹!ÖKž{" ®Bú6šz]/¥^EýFQWH›¿GAGÊÄÆmaVü·ysœ¿?ãùì߆~ŽÆÞH2_!|Í¿Ïúæ# y/¨§©)·k)ûçk¼¥ÅøIæÇW~Æ÷\R¿…_øMÿ4H‰_ÂþF=ž]dz ¹(—ƒYTøÐ­ÖsH‹6 h 5H8ú4Q¤ ¡<0L³œZ•x½¢´5«ù/”j0gä}õ„iCCPICC profilexœ}‘=HÃ@Å_SE)A;¨8d¨NDEµ E¨j…VL.ý‚& IŠ‹£àZpðc±êà⬫ƒ« ~€8:9)ºH‰ÿK -b<8îÇ»{»w€P/3Íê4Ý6S‰¸˜É®Š]¯c}’™eÌIR¾ãë¾ÞÅx–ÿ¹?Gš³‰g™aÚÄÄÓ›¶ÁyŸ8вJ|NF€®] QsœïcÇiœÁgàJoù+u`æ“ôZK‹½ÛÀÅuKSö€Ë`àÉMÙ•‚4…|x?£oÊý·@hÍë­¹Ó M]%o€ƒC`´@Ùë>ïînïíß3Íþ~&r‚à£Ôã xiTXtXML:com.adobe.xmp ôè5bKGDÿÿÿ ½§“ pHYs  šœtIMEæ ]¯Ž IDATxÚì½{´~YU8×:ß-(ª@y¿5ÊËGÀ j ‚#JlG5&¶1bQ£IÛ¶éVƒ6 FTDÅ6vk:1m41jŒ1±µu´âÀà#¢‚P"ÚØˆ¼ †Š/U÷¬Ù¬ç¹e¤dŒßGïUãÂï÷»÷~ßùÎÙ{î½×ZsNyâ}ŸF   0Bj€BüG (ðŸˆBuÃé´áb;ᤠˆâßÏ÷ &(PÀxÁü7ÒQ~Xü¾Øê¿ì¯!⯿HÒ_‚Ò×­ („˜ÿ.PáŸßßÐÿ ŒÏ)ú‹I\ Å`bØ(P* ôÿĈ;Ìß“~­÷–"ñ~¡ »ˆ}O„qeŸ%ÿ÷ÇòcÇ{™€úÌþ<ýúânø+QÇs÷;ãoǾ˜BÆýóÏ–oMˆßc¨õ¸`|—Ÿ0~ÖÏ•ý™cÉ™>¶ 1.Fȼ>¿6` Uæ¿!"0!Lü3j½^l¿¾‰—gÅøf>23ȾCb¾øÐËOcOãÂüa9EÙãÉhÍ=‰˜Ÿš1ó3[ŒÉqAÅFØAn äµøæxæ¬g/1žóÏAÿ3¤Çƒ‰Äï°n?ãù u\#{ÆÄóg™×Œ˜ÏþÌu\‹Õ§ì§ÜŸ6LJø,æg’.¡?#Ï/£Ô<Ú}ìÖœÎ1M˜ f«¿³ «%„Õ¥Æ#¯<'ÿ¬ƽ$„êsQüù%&PÇL› Næ8 ñ!kÖÄü£o}ËïcaöÂì…Ù ³fŸfŸ Ö·(î±A P(ˆrŒ H½) Uˆn8m'œ.N¸PÁI´à"œ9F\c²õ$/ÌK2’0¹2©$~>“°¡ÃD^wO‰ôI1Ç¿ L{p3†XN 1ÁØ ˜€_ ›æR3®!ïÁ«W%)PÎÉB Ô ýóQ ­)‚+dCs~Væ"5'AŒOH‡U¥Åä °ñ•P8žº‰fB«·zŸZÜŒ1Ïü¹~"Rw·‡Ê¼k¹Ø±"‰…(ÁT,ÅŸ¶ü4„€±ãˆ}E½)ãYåG”@ýC‹¼¸4ìl𠶸–¼÷lÜ>Žs#€\” lìÅ»æHÖ½_*Ðѹcw¯o¸jqt¤@õseT$Äêá13®_4€Ž2Æ·_£á„ˆJ,ŽŸ+·‚ÚÈLÀ R.¨Þs|Œõ¤çqÞè\"eƒÔheRb±€ó¹ 'Y‹ŸúŽvظĦ•Ä)n£h€´( 4é£5q³Æ%Ù0 ½ÜsÉoŽÅ±!\˜½0{aöÂì…ÙçƒÙ§š6&€ö',²‚¸¬<—رA¸aÛ6l§ Û.N6õ›E&ªÅ‰+²žJÉ8SÑ<»’Œ÷ÝêÄåÙÂ4Q]!&Ø4Nßñ84ppWB=w™ E©|°ç •8­°² û ææà“7ËÐïí£´F™[ò뺒٠"0Nwô×P6\éÈìä©Ù2û!!AõÉnœï,1¬– Bý>’ óÀWÙ(@Ô:£” K, Œì‚0óQ+JP­N—R‹z€æ‚_‹¨Ô½Í¿“Ä&I¬Ç, AX<˜Ú ð\œéÏ׳ €ÅzFëE@P™'¥æ×ªõ¬zñó,^/ÞžÐò”I‰…Á°É©ÌÌOŽ4…Ä '¥ÊPÃF§ÁȼD&HºØ§øAj”H²¤IŠH,rc:Ê<´’ñà:»#œå¼ÈÅä[Vé´ËRdO`a@52M<­$JÈjîꀳ֯ƙuÊÉfµ0d™9O® ˆEi*{"jœ\c¢ÎS>zß h»è&f5E$€…ý<˜Ç~«q(y -J´j‡²˜gU¢IB$î›  H÷4b;”ç0©cé ³\ÎX쳜`5?K§kÆk@ëô}( Þ‡U²ë×ò¿l=k“Ï"ý™©“ÚÌdIŽDlˆ“é(>çb•ÒÅx¨6v–3³±¾h¿—cMkÌW ¯îl—úó‰µ!±¯RYÕÎÁ *’í#õ’í"›¾¼ $…Z Õá339Ö¤öý‡¸_…’÷ÁqÆ?Nfª; CÝz‘Z˜½0{aöÂì…ÙgƒÙ')0íž0™€mBQ( ®»¸Àéâ„MÄ3îâ@é§ÒpJhö²K{”3§ºSœJ!{€½Å­ÕCμÁ™1A^-®W ˆ(ó„çT€TëÆ(ÏB¼ÌJ€Ûáè«RàÐŒ¨ÕÙåÄš yŠ=£ŸUÆ@èºYMx¯\fù#NÛ¢1xwïãÉ)EâßEª^@FÖ!¥å¢UãºOy->.ÂcRÇÈÏ'‘åÏ.1¡2Xsâól‹¿ægÑŸ0&K¢‡Ã²‰À4NÑ*Àå¥÷¥Zö‡n‘ˆÏÀ*ŠF6J´¥ìeÖªoR2k!Ç‚­?C«¾7?ÕW™œÌ‡Ð2Ç¥ûî8º5uÜÓ,…åÒJv6ŽÎ“‘᪦í™÷ƒA"Ûšü{Ìeñ,ÖL'Õ†‰•[‚ÄX[öÑQaÖ÷Ö°;–PÆNÒ»…E8w—^AÎÄŠæb¤™Ÿ¨6Ë짌œ ¡b‹6ÙªqÈÅ|;d´ÀÊÌ é‰ŸØ`ì›ÝnaX˜½0{aöÂì…ÙçƒÙ§nØfi?éþ8›n8]lÐízá½nÍEáèǑÉ^ä8»?+û{ÆÈbd”?ûóVs½±'‘DIL¢œc*Ø«H£l™‘nÅ›1Ÿe€ú °.šŸàrÂ.n>ÿ(ä²CÙÓ&1™¤¹¥ôãg}hEÅâžH·­) cA•œÐРЍßɬO¼Ÿ Bʱy«û+Áî0srE+%3$µ8Z/9ð”Çbug–Ë3Sþi·Z€I­RW]7ƒû‰~)ö½À8¢Fy™£ìW$t »ÄÅêò'äX ³ÇRº{Q·S!ZôÆJÊqÜAc¼wñXèŸ×Ä:»Å¦‘Ôߥ{ýd\Kö£ÖØ(òX—+ƒÇ9Õ» šçÿÎJ Ðf÷«Ê¤j ‹‰Ü"##«€êÔš+Ú™Ñn‰Å(Pk¯ÇöQuU{-¶Ýâ 7™¬ž_!ŒV=½*[oÐbÓ*‡–iFf*ed'«Ñut¯ÎiDˆì‡vß™†È ¿¾F³.é/Ì^˜½0{aöÂì³ÁìS1.76»Ôzlr...pq¡N°P"ÆS5íóÀÿƸ±If1£eœ’u’<2íõýFˆI`:ú“Èè'ÔêÍÉïãlñúÂ:ýÚ••¥³f|÷b$E2±š<ýlªâñJeŸíx–öÖ¸ÍHÏ{3®¢´ê™eœ"Q.ãžV_MM«2®Ÿ’÷虓"ÉxöÅ™%'/#Q'ä~¯Ì²d©‘Du¼DmÑëè×£cJ|Võ†ÈêU3Û«4—$ÜiÅUb¯–T9  ¤Ì4“€¬Rº& ´=3«Æ+ªù''Xt)ÍÀÝbòke 6éEJ |­I&#ËÖI¼âºÇæŠcAµ+ ½±`m!P€™Õ“"Áhƒ14‡ó³¯0KîÂÙÇ9TÆb™˲ô\h ¢—mŒ{ß ™ßûÈÈ`›£6‚]î«þa!­LžÌ±\@k±Él…ni, Þ«ÙZZôvopÎ;²êÁñ‡ò@ý‡ú™)j •{½”&K~aöÂì…Ù ³f_ó˜}Úá=K›Œl´u»§ë×mÐè #é Äž<„€dЛíãpVÅ¡(¿eßWfIŒGÚú§;ƒu¿L2§£÷Çß!úұéÃ'¥¯C^Q±bÕË #dY‘3™ƒÐ8m ”K/+ I/!LY!rÉàíñ8µË8¡¡ EUŽ®A©’Á°!€ƒ¦OÎ;ö8Á¡N÷„Pç Ô’¡kRÏÍ™êMvi¶û¬:8ά€Ñ³h~ú”Èd–[—gd¶”R—^÷CâÉOÝ Ž%l©¬šp™á!«L]²aqù{š´˜õ¾°A™` î:û§"ƒ`äÆF&®@d2³!l¸ÜwÐ,žóåQ2îfº¹ýÑ"^•t—ùø’e¬^Dï#euÚ›‚ê)ìM„•Á´ZP¸îª«¹+Ñç˜}©MoQA”ÿgEB©ÁºR“X׋ fá”[5|ËþÌ$|Uf½;zA˜D†ŒØ ñ_éSe|®\É4ú‰%R‚–óh¨O0².ˆy‰ _µ “̹l&#~JÅ•U÷Û ”e™\¸aaöÂì…Ù ³fŸfŸ¶`}š9ÃJlÛî²]‡í¤Ð“ÆInÆ©V:E¢ŒÌ1±¤åd7—]ûz˜šRGìWLfhʺäÔ˜på ŠÅBT€•}C<x,&x‹×‚6Mü–½¹ˆEÂìGë’D ޏWŽ—1©‚´BÄ5KA;Vò_š®"¡ò£}(¬ÈV²MÕÃGz¦ û¸;’Cf¨”CýsX0Õë„Û’•`OXÚ¯²Û¸ÔÁ9žÐ Âø3Ëa’}“At y/cŒ9(‘|”Tà(qµ¦'@kÝ[Ï<âè˜Ô¾8·œ’B ’EÒ|/¨\ÀlÍÁÛˆ^hÄ"™¶mËÅ»”¹º`dýmƒM]YËìdr±”æ.ÑšÈ"=«Ÿ=ß«ŒÎSÑ1:H8-i†±ðYµ:4+\ú}­A1¥Ä¼ÚÈ’3:YF #";¨£ÑÙ(0±’¼ëžÒÎL¦D™½º|Ä&±ÀVÛƒÖü×I¶Š2²r‚yl¤·kížå{*wèè ’Žà.u.Ì^˜½0{aöÂìóÁìSža¨T/Búé„ Ý¼Üx ç)CJÈ[óUW\—Ç0$¡²ÌX'j™È•‘Ñà®U¦ËžŸÒ²—Ù#šüc=°n?ŒAbè|CKmô7É^E …Ì=?SöÇÕÕ†LŒ&‹WƒÀ,«Æ@§Å$tÐÝ$„Xlq —Õ³&~}q2Ü3›Ân¦Ìiž<[X?;/5iíË2HÏÔ³Ô6¢` #]ùŠ»S)ƒ ½$@’´Å"[í%ñÅ2i˜L}-R–#mn _ “:¢Y¢¡ø³ø½Óȼ±J”Û¡Hž`éÄ'fX`¢D¯ØŸoæy.p¥¤ èè§”$œÐÉ2n msã°Ëo;Æm¨Ô¶i€ÊP:‹438’7khvVf*Æ'âYevÃઇþÒì³…`7o?(ÅI  e‹ofF&°¡Œ†BA‚W‘U06¡n,»— £ —2‹’¢Ô%4i*2@ƒf…ÐÜ£(TI˜ó­pöo†TXepZMPf×bnî„£¿•¥œ €áJ½<6mIP3vT­ú/3ó›Yª,år4,Ì^˜½0{aöÂìóÀìE zÝN¸8]àâ¤Ø²¿%ÔÇq;Jûw³Tæb¹¼ÝB7>Wj$‹=€ÙdÂOöÎqº4t¶²úx­Õ J¹Ÿ­´Y[-Ab¼Jè÷ k*ÇÑU2cBi=àƒ¡ ºœ(C¥ ihO911¨£2Czb£åp ƒ–Y¢úìùù·9fv·–s`íµ2™ìg*pŒE|6di<úŽeº¾pŽ®& ô cÕrhßrôJY˜½0{aöÂì…ÙçƒÙ'=]`;pq:aSÅIÙºrDf&Ž^B„É£Êy$ÛÜüÒvÙÛu,€Ž‰{`çdFd8=ÙÔ7d{xÕ䕱¨°å]gY3{{Rï0O4MFVÞq"k‡")Ö7À e‰Dx+È8}ÅàÒÉOŽg}’”ñ°³‰ eŒq ýש ³”;°{ÃIy”V†m•ÆZëRÚiÚ¢ÒÉúÌq&ØäĽ‰ù*m£Ë©É+W––‚b-š‘Û†m®è (eL.šY#ÝGUÙ„8¹ i('–¡aPƽjo/â‰÷îEÏ™øÂ]2PB˜&qE±ï·ûî%*Ù†TÊ.ØÆBI¢J…µÁÉ{‹§ª¯°ŠÌ©P‘î~¼8hÀÎM“aš3ìh-2¿¶-åÆX‘²ôuûÖxŽ¾Ø°€–¬ƒtg[Ù·‹îCZã©›ô¨\PóÈ¢Gׯìk+dAxˆ<ÈqG]UélpNòÞÐTä^ÄŸ)G–nƒ²6´qgÖã:‡Þ…Ù ³f/Ì^˜}>˜}ºëuwÅÅ…ÖÅU3ºZi$¶-+ÛZ÷Pâ(ßI„HJZTÜ kC“1„”¼—oõLÊÔvv¨kE’nµ™»³v”Jf²õiÚμ·e ;„ÍE `R³잟<.®*~WCŸqT'‚„!W $zëX% zÜÑYh}Ú=IL®–=Cj«:óEŠ0Á˜–µøºCU²ò1z¾ò”ÜOyÇÒSiû¬‡…oJa‰¦°»²Q™ÅI‡§P‰icŒ -DÈÿ$ykdœ&#xËét3ÒK}Â-ã‹ PìÞ}}Z@Zy@&hj\С{ΰ‡‹\Ö¦´4n!N'åvé½lZVÀ»5Ó¡éꦬòdªLÊFö’Å£ÒK ·Ö›£t¸W:”eOœ‹~I›Ñuš³×WÓ—“ËmÕ¾àÄ—–™»²¼„áDËͱg¡Kž¥ûš´â@³éN]– W^O÷¥YŽ^í×–kÙ2™óþ hÖ› ÁôÏEÂÂ0: ¼Î†7«±(±¹(yåì&¡¢qû9HMÀÂì…Ù ³f/Ì>Ì>]\ç‚ÿ4ï}K+Y«9•¯Hô”X<*¥]Ö˜LÆé`·ÊhXçôå:”¤†è¼E¯œ´¦kÍgvÉŽbR–º¬L m2P¨2§¥ûК­ŒpðN‡sW=ÀvG겇΂ܰ£_e¼Ò¤ ë”Ýפ$Y={þ¼¢ÿªH'a¬•r£<•Jµì1›éÖ¤]–YÆjç*†ÃV5æevÉ^£_‡Ó6OûPx.¢Í±CS«\•R>Õ62zª]–I"ýAË20#›·‰Ê`UÊäpsÓÑóZ¥Ó(kY˜UÄɼЬÃPA™œ Û`»ìóaUó^–ƒÃé®ïypÜrÁÜ QýgÝ7VÊ™u¨¾Î0BFw’YdÔÂêZD°oMv“R#(*Éái²4:cÖf]Bvm©S+’–=³”¶“µ¦q<‹yeÝ(`(Q´7y ¡ºÁHy‚¦õÚY*Ïϸ+C]"$ïRº*MR‚”ª™éÏ-‡þÑÜÔ Ž}× ³f/Ì^˜½0û|0û´e# —0¿Èjw“fj&‰@»¿§ZÓëDz£Õ³$Åtu/‡ÄK”9¤ÅþkHd:¾Êž »ùº:4ý~Iðˆ¢‘È0p…|†î¡DÁ‰*Š=©:6²*уTÄ‘<Á—½¯ W, &º…í6,w‡ ¼(H«“Ï\êL|zoYX£eÉõ]ÓYIeË/¶+®˜Žßº»½@Žòg–c)Ø­³aåºÜ’6~dˆò[HZ)˜Y(a•ùÚá ¥™ýdi{Ø(S7:¡})óóò(‰4JÌqðŽëí>MÆIZx´à…E>®Íwþ|;ÒFW³<ÆÖâõ>ÇS[:gy”)yÖºÆ@7×=æNp÷¹fh)é*|v¸ÅÆ¢;-2`W@^2HÁNÑ!5•'}h34{97ò UáCLƒ5ß+cQ­¤á:3PZ$9”‹S”Kãó ­dCý¾".ØÝŽÐó]y¦f­ÍErNn˜û¦nð…h?äFd´QP§^±_·™zÛ »WבEk“S ¹¥÷Ü*¹@íñùC56t ³f/Ì^˜½0û|0ûT,Ü®<N‘¥uš|UæUãU…ÙüŸ éø¦r¥ë§é2t6«a £Ûð ª,ú Ì~-ŽÁÓ\P¦Çý±±åâ5º…U²“aÕÙŒÕ%$£šH«%obqZýsW~Vƒ\cCÞÉ{ÄÆç6¤†c-,%|²ÿ©ŒBSØ=×Ræ§ÏÝ2¯ÊœyöFI' 2£g.2´döÚ‰uožü)§oÎ2´^9ºÛÈ(9ì£<(Ò“Ë®Lîæ/k ЋX) ÌÓ§Žr¬³\¬ÌD+W–f’6¹3IBfM̪͂m£,Æ"yOó#3‰a=ÉaÍ™3èI@Ý€K`ßý}µÌ!Xý˜‚l•!¡A´Ù­m˜ó3¹æpoi8$òïS ¡S–ô—¥žn:.H»¡•œ’´–¬Á°‰àö˜»ãJǦ®ÀV¬µW«þ›mlù´J6%È*v›XÑÂŒrXd÷lhfÃU°²µ"ƒÄ²ïhv¼—·9$Ó’dçÃh˜¿DV°JÏñ³"cëª„ÙØ°ãFuaöÂì…Ù ³fŸfŸ4œ½,z44,%û¶lœæe¸ ¢\(ßfy%Î&É Z:œ5y->fœ¬N¶]j3ì2EÇ»Œäã$ΣҲA:¬h'«\†œÐ¥p¤ô˜KúXŸ®ÓQ4o‰Šzß nMWŒRcŸˆ½ö¡íL•I*ãaFS™!Lp×ÁÔnzNÚ‰L6«QWlt b ÒB7uzFà —·ü=¿×Z„’¤H·íïèMrq–ËŠ€\û\ÃæT¤‚D³ä%CŸW†}ò¡ «²KY*=–¢„‘2HšÔh¢+bÃÕäÈW˜bQ*‚¤rP VN‹jB#£§Î–³ÿvÈSäH!'6Àö´K·¶¥t'¬lY­<]wž`S Jv†€ý¼Ò IDATüYt‹ÍV¿¨“ºNÜv˜Óz(lóÑälc8VæýuÂúÅ"gŸ ·sã~Dy.@ÞØ%Á^š®m+ìsí-m¿™¹âïgïÏÞÌrD”yK‹©]+ÇÔD©Vº·Â‰@ÖÙãl/H¼úÜ ]×j‚-Ì^˜½0{aöÂìóÁìÓí–ÎXãÑÊù•ªwèû>œL+Ê‘9ÀðšoÓÍTõ’/jmÂ* ²µ?KË1EÐK´\ Ø,NjÍPn@yY ­Áj¬ù!Ž.)³o {@Œ{Yxj«ÅIØIVäCѺ>f14û’âóŠŽÓb”#yE„]%Mf%§tŸŠ2¦V#U J+2Ÿ¡Bi]ÚK X!TµJ¦$D«-zÜ mm{œ:>gj¶¥÷,Ά=OžµpÅ™1ÃQ¯•ü\Dܧä qô¢†q»ß%éó¥`¤—ìe“±Ö “ãžå&ĬͺØvŠË<…¶-xêÓ¼$$ì­Z R_CnVô.Y—³ËtÓ‘¹‘ÒËM€±Q"ÝDJÚéÀ1§J—éú–Û„½úgÿ\ä«÷‘I`ióºäx€`Ë{–µž-°©GÒªál 7·©ƒsŠÄeè«n1Ó}ÐbõÅÞ6R÷ Ôa–’Ò_Z þpÉQ-ó¹Òç8š+bѦ´ãb’g;Ë’Ùªÿ–9ÁÂì…Ù ³f/Ì>Ì>©”9o‘rrsÜ•îA™.Z}*¬£HÈ4¥õ¦ 2M—0‚‘r*ÉX •)ü:õ_Ñ$TP[ýÖ¥ ¦üQ˜hô!Vá)ôÉðbZ¼ŠÃ_eNÅP–Š÷ßëñh;B4CºzÒ0$Œöáê‡ 6ü°d¢¤»êÚÉѽÄ&%pÞ,»R®ËòGšRèÑ=mº&ŒbÈsV¸.ùÌå5Š24]q°|ŒÚdF[8¤~,†¾|dm„Q‹Ä`ÉçP¤ ‚‡$¼pèÃJ[T§ s.€–€/<’Ä’|D³mh6»—Lå Y¥Š:21"žUôÅ'‹Xl9°A„á´©H¥ms¶»í°Ý±28XœˆÑÃ*iðÁ¶L¦ìãóÄÂ6݇2@÷ðÅbȦᬥ)$<zlʶÝa<Åü+¨l¨X•Xy íŒaEé -¡vÐõ-cÛí½}8fb‡ï™U¯¬ús^Íñ"îxí23GCRoºìÅÍ‹ê•}aöÂì…Ù ³fŸ fŸòô@ö…h¶ŒŒÁÔm ³æaLÁP¥Ýƪ#à;ÍÊÌxÑϪ·ÇO;IlÙe °-K½ÊÀ:•f‰§{¹#OÖLâMqÅÛTÀûýÏ“rñ—дñ”äÒYŒ’XÙëÐYVÒ*„I N «ÑqúK&Îèë’4²ÕȼäïÇÂúª6/šReà]úóÕr Z,¦ÔéM4lÇ£èT´(gJñþ£ìÊZHr!0Z¸Èµ\Zý“xÁƒ.§‹ÂµR)Ï6סÀ¦‘ ê.8Œ>·”ÚU±ê‡›}Š*‚³gÍ ¦WNü1Ñ5hHf¸4ïf<¥‰‰aÒ{ØHé]™÷+3KÝ¡TìºÊƃ}ö,oË ¸mEâš½¶Ñ×jéma#ÏÆa“;7fay[É0=´‹ íÓ´'?HÐ])µwïBç«Â5O†Ã±J^d[ðØaètEè±$YŠî…Æddžèê RN–D™Ž$8s#¸0{aöÂì…Ù ³Ï³ONÈÐê£É’J§Ñà&AÕ¤%`êt?Î,óÜ>Ä ¢dÙªñ öÆ– j—6™n=9a•tóùîxÒÏ÷ã`O±( ËfŽçÁê5¤›Œ£4:ltÆmVÀ!AÖJ<uͶ²ÌH=åZ¢gNÈ1Юtj|N÷ª£m[1׋äÞÒFÅè¥Ó!1d¾ð¤­Œ½*/CS—‡Ø)n{$ˆé0.z¶ “Úâtùèt{e i®![žbm—³œâ‰vfl–sÇ-Cé’Nm2;d7e¹Ð ›ãš½:P‰™:9þK/|u÷Yei²ó_2$˜„@ÎŒgçyrÞgfÇF_nNk‘#þ” Æa3{´\™Ä)­Ä?«L^÷ÞÖ;,Ì^˜½0{aöÂì³ÀìS!RÀÛJŸM"Æ·””‡jà‡‘&'$C7N ÛK‹ËR:Û½ìSÁÃI‹FɪŒ&6´4EFé§À3€¿úˆ¤ÊVR0mó«QzH±Srkf?ÛR´¤–#oz.`VÒKÝ Ô/ÃCY¢²Ò`•®g¢røÝ:K¥ÒûÚ<ÕæbYrKŠ6d´Rÿ4uÀXÖ»zŸÛ§wV”D¥³-³“ýYI¼˜=…ʶUу>e–ë2«%ƒ0ÑÎ]s¡Ô#ǧmœÑÚR°kÃ2,¿¦éE‚*U*£8HPaÏòwudGÖኅs-C–Â:1O{Yå=«…>Êå2ņٛ)QðsyWØå`]³š ús‘ÐJoõ"ÈÉû–¼ 4©M˜Ü¡>¸êÑ[ØnbÙ6€¡ ‹‘ÉÙƒldŽdx¬+665$/k"P²às¡« hÉVÕ¢ÍãÖEp(7çœÜ{›¸îé‹§­H|icºÀ±˜ï‰sb%q·0{aöÂì…Ù ³Ï³OÍ^1œ–p¤¾j3½Á%O¯ÒeŸ:EŸYµå*Àf‰V@zŠmé@”\à´%d!®¡šòLK2?£XcU¬_Ù”Ÿáÿ¬lÚ(Sè`¤¦¬Ž0ØÝq_tc¨£ÜÇvÚ³´%S"©™Å2ØúUºd:éèm‹¬B’\dH(U©¡—©C’ÉÊIGÉf…Ce/„Ü3³E;P_òi•iBÙk-ìÊñÒO”;,ú–0ì‡YGI¹ù ªÚZ¼eÚÀbG7›>H 9‡N§Hf{qv²t–Atc壙êíjBþ º”—OÂ×?-`Ìׇ±úDK“ ¤=5ÈE<ꤻÇ&E‡¡ˆI+¢ÃþÙ•#¸ DO}ö»í0º!‚:zÌ^EMâ›N9¹Vækк#SË´ì•¥ÞÃ`eo}Ï"¹*d+¼¶S]gÕhÝWÛªR‘Í“~þ5õÊ~œÝ6@)­à]šÈ#Pïk®,$CÂN`bCžŽa€€á.èÏEcÃ[Îfƒi?Ë•‡ÌY,V¦Œ¾e)Õ€…Ù ³f/Ì^˜}˜}‚$0[ `íæðA²1i&õga˜(S/R«pi[L`“oM]P–ÌJËêgIЪq>'Rè ¹â%hêåŒê—‰ÉÑ«˜Î`{_ÚñÎAVišêC’êC2Ù›IdS¤´þ>u'ËÞ>¡Ð"ûÈ{ `³pç (NÓæƒ"AÕüÒ,!Ze4~ÐjÑi ×ÊY. Öç­ÔZeŸÒ8Ê~dk›’ÇVÂÓ±ŒÓn-Ë,‚äR§?F6ËMӺʤX%µ$¬çÄ3[•§c\iÊ=Yif:i*Æ œY_Ù0X¼†µ†hš{ÃÒ¨C1 rÏ( Z¢ s…\tË9jØËfŸÙ¦mÊ1ûÕP&>­Nùû²CHœ¬±ê¶ÓÙ:Ðk'ÁÍÉ7º lßqI‹S¾Ösˬ`ª6´BDg %63‡’)§Ý÷žT¸Cv2Ü[½*ØÝ’­SjË@³±1ôM™ ­YIMåén¤½TtpÙ-kkîÒhÙY„[ÍA`kOÐ"Û¢>'Ô’Ü'Ž\Z©J´\oÔR··[5&˜§8^öZ¶î¾0{aöÂì…Ù ³Ï³O2¼"8¸Wa*1 ëYŸtÚÒ8‰ "£Efœ²²)|è¹ð jÞ²)%8õ¤\j2þgX(EO“ {rŠ•Àh ÿ&µŒ³4ýðÑ»4®™©%je×;ÏÇé$d¡*åÊ4&¬þú{­»m¾Œ8d¦ÈyG»W Õšq[þ‘ ÉÞ¿A@¨þMi‚Pò€A¢ 2­2:Ætp*óßʈ$ÀǞ6éÉíÏ!2ÔØ½DÊжõûgÇÒvL› EôsI”¯¼ì'¡ÚÒYù¹’Øc9дG†¬QYFC«¦–}¥Ù¯™ÏaÔ¤v/Þ$’äóÉB1å"µ˜›#b/hÒvËŠ¹¶UZ^éåèEœìöîC$›þ"£üot@7gºÛ^e;{ÏÜ 5œk’Û˜›,´ä×”s+ÒXÊ<ô Wö1ó ²c§E–IZ;—Ç`l¢B¥ad«ô²õì-œY¶ØX¹n.z›ÂTA°p’k‚Vi+EH33 šz胖bøsuú–ÙÁô¯»f/Ì^˜½0{aö¹`ö)?•QÚb7&¶åi¥òr`—êŸâ$L`’éØã¡«K3q¯A`Q3t§Õ©iV¾ÀvÑâKkM„ Â¤OQu^Dg‰ñ¦ù96î 儳c¿ý £¬‚2 4·*ŒÞ£v  ÌBëÑÂæUòžñÐ{/£,c¸Äf£ 柡Îvä6È ƒtuù£’vÊ2YVÌyjãP$h °Ÿ²AÔh£1”ã[²Â³œcPnP»î©¢ÚBüìÍEgÜ|Q¤*GÃ.Ì/Œù99£f™–z;,9ZeÁ”L¢´›’¦¼¥‹T‘‘RÈå›RQÀÆØÉL† #S×(ÕÕ6¬cÅ¥Àˆ‘íš<þñ Å‚PÕà)œ‹°KË)‰lØ÷0só SŒ ®xÌoÐj±:fä€ µX 77NBQqºè=a‘Åê“°ÖXrRkhZwœ8ˆAf#»&Ñ/—Ÿ¥Ùù.ú0GŸ²LÐÞè`YZ¥Ô˜ò^ÍÙ?Ø}VK†]ˆ åo¸”îÛrR…°×é\Ë«AÀ½ËÈ©ê°I‚‚Ï93õnWóÒW‘Í„¡i \jf´L2j!ˆ’jåа—þ)5ÈKæl2!tóÿßé ¥VÎCø°GY`Ûji ,uér*C?¶²=Œ‚`¥´³˜ý«]b´!{ÆôC•í·Ò¦ ­[bh1wo2¸k˜8Kï£ÜhåHŒ[éçZhÎ*´0Á’8WïrEˆ‰OUå{éžÃc>]´‡YCæöÒ>-Ì^˜½0{aöÂìóÁì´·Ì^´<‰T2Ú“`QÌt)uK—I€cOYe/¤´Š„ÛÖ1~r|î¥[iŰMëÝL h”ЬNÞ(v?y±ú³RvÉâÔöí,E „à2Ùß24GV}pPPö*ŠYœŠY'A w©¬‘ÁlÔ›ñs‘ȳšÅÃÞr°VÏ`Z£(y˜>8òVã°J•¡ ™½]ܱÅ98Ëʬ¿uO–M›æü¡ý¤ÑWƒ>S¹`¯‰ªeûj nG[ÔHP=둎Q]]ŽìS’PâYú‰ ˜…SšÕ8Ì’µ‰Á=aÖYáe|þÌ™gò†¬Od¶äYåi’Ì‘ ”ÖBXbU¤Ùƒ`æå/[W9ØöúÇ0JÔƒ³”ÞJ»YKDEÏ-(‘¡,¿Ö`Ä46, âÏ%oo…ƒ"劌\”ÎuJ€!²n%_åeh+Y¸Ìž…cZ¦Ð*‚z½Ë´nrPb™ ƒ„®}|¯t—;ó—%ù=›-‹7½ÍªÁŸµ;È &[¡ÛV¬z9jÀ‘m ^&lE tÖ# —no2²§:æmÛ¤ ³f/Ì^˜½0û|0û”&ð“Í`{—ðz¦ô'(•(S"FÚ2öJSJÖøÄ÷›!ÆfqZOd‰þ¥Ëým¸íòíØívìvÌ‹­vNß°ÔieKúW§$^˜mtÝŒ_y íþ¬¯ƒ&)ÙSÁQ5>Dûk@¢D“æ+–Úüô×cÿáô½BŠIƒms¶`ìñ³L[ÌÕ3;C»tŠÙË(h±ÇWlç=8˜'\ñQšý“Ã/ »*ó³òvèF“FDiR‰ÖÂʃ4“XÈ]þ=dV†ä•Œ?5燡…U‹R`å¹ôÆ ó9LòØ¡ ßÍ«]ö-ýV) àcÇa÷$¶†0‚5 Åi{¼×“Mnég2éÝǼVmY°‘¡“ÈTÒö¢Ì!­± È5 PANVíÒ),ìµqÅäašŽdÖ´ÍM®xô¶þéĤ±ñÄAúª{$•Š“\‡M¯ÃuÛ 8éõ±aóLf %ˉ¹ù»Â¢÷¶Zž»SŠ µ`‹¤»ÝÑNYR bȘ-Ì^˜½0{aöÂìk³OÔ+‚îÃbSü…`›Sœ%XÎQ7àHÅûk•iia‚^¥“…®ÛíV¼óòð¹_üd|ü_ý0Üõ†‹;šC­X±bÅá €w¼ívüôÞŒïù¶çãúÓ½qÒëÛ"Cä¥ç ó~²JŒeáRvÇÖ¬a&’—«æ8Ê‘qt!R¹0{ÅŠ+γå“õî¥A˜ÌPF-Š) J»½'L§µ,KdžÔê’H§EŸA¸ƒ0ÜzùV¼íößÃüßÿ3®¿ábš+V\qëÛnÇSžüÜpqÜEï¨wÅŠl¡/ÙXmBŽè%öö ‰~ãÌ›–8ì°ñJ #áQÿV€‹mÇÂì+V¬8Ì–O~äsbû­„›Ù«QÖñR¢÷ÝìÁlß"²'ÕCwp0Cl–YBPÞh!;u‰ÛíxË;߈zá³°é$+V¬¸¶b7à¿yÂ×àÆ»<§ízœpò܆Ä%L6öVlÐî)- ºèëÔìÓ•)«vȪ¢p–x³«óT½ ³W¬X±âZÇlùÔ‡?'eÌËÖ³È,\š—Õ{õvQ([4%í8Újj:2Å[¥Öçžr<Üãp‰—øãÛÞˆïý‰€ëï¶²"+V¬¸F³$o¿Äç|Âó¸qýµNÄ¡l.=U®…ý}¡˜‘®gl¦8¥šÌ{§³§4³Ñp»`ïË݃¯P. Qf¯X±bŵŽÙš-~Õzæj.IdÃJÌOiQiáÞ¤ ÔÚÎ’¡]äBñ©¯©N³T ·ïoÃçñ'.À^±bÅ5×ßí„§~É_Ámû[q;oƒñvÏðJ“Þ<ó±!eÊDÝíÎÊîÇüs”(ËbÕ‚øbªg”&¬`aöŠ+Vœf«A`¢-¥‚–Ê@Òµ%¬MSƇê%HŠ 6í`£¶V舰=$‡vì n»|;>þ¯~Ø+V¬¸æãÉŸòÜvùV—p=+Ëbïk¾¢ÆÀa»=´¥-•4J/úæ,¢bdW²Ÿš¡e¼0{ÅŠ+γOÙŽR%,í̶¥œnQëÌþ”Ð=ÔpJÁ| iã0UH1w(3Ãmv+îzÃ2/+V¬Xq Æ]o¸Àn·¶ƒêrNšvÕe×­eßz¶Z¢\RšÑ2$ëÚ:™Ûo@`¥Gra ³W¬X±â<0û$a;©åú}{% î»r-­A–Eª8…» ”'Û‰ŠsÇÏÌÀ¸”Ð`vÛÜ+V¬¸VƒØíöƒ„Ó.5…h:îe¶Ã5pEYD®hé¦A‹”†l¾×­– —…Ù+V¬XqícöI²eôãÕ›ÂõÈmDÃiÒwøùÆi MäÝóGˆ6ÐÀn>îäìuífÅŠ+®ý°Ð˜6ÊHºœºYSI³iàµx2²Ò2\Ѥ˔éD˜¦ …“Tf¯X±bŹ`ö‰ÜÂ×­ (Z&O +fñ}©¿òUëÑöŒw+W/C†ï—h û¥+V¬¸Öó#Ž\ˆì²F_´¥Tž û`ñÒ!˜™¬é`®á$C‘Àb üÍw”AJ”…Ù+V¬Xq&˜}Â(j¾`©ÿáhÛÙ÷Cé° KËÖ/ÜEÀÓ–ÕàèN¬ñ»ù×î+Vœãè´ð IDAT h3\ÄÚr:…Ò-ŒÑ -i‹`Ì0…‘Ê}„¬ÔŽ*¨–lñà`¿×,Ì^±bÅŠ3ÀìÅÒ”>„ºS’d‚z$ÛE FìÕë"åõž:îûî¿itÇ1ˆ¼„˜¸„ay £¹>ëÂì+VœI˜í í †‹\Bå1s=j.Õ¢¯ïhÕ›ÛâRàËýo¼¡ôžé=²Ï ç¢â&ŽÂ…Ù+V¬Xq&˜}JI'Ícôý ÝÕÝ 4ÞÜÚG4Þño{”/Y)ô¼( Öæž6–ô /9•×\üý¯x&^ýš×T÷¹×½ð˜ý`|ög~îuÏ÷}¯þ¼"‚{ßë^xðˆOø¸Å“žðÑk@¬èìˆ0ö¥¬I–ÙMÐŽÉd‡†=z+…¤Æª›ÍT©¢¦€´¦ä„ˆdædaöŠ…Ù ³WœfŸ$¼Ù][ÐÓÝu#%ߘ#·ëš4K îèoA˜H¥Ð#á,›divÞe%G®åøÈ,à•¯zžÿ~¿ù[¯Â·|óqÝÅ{§YÅÇ|ôMPÜò¦7á×^ñ ¼ìå/ÇÏýâ/á+þ§¿·à ‚`8Š™¼Oƒ³!J®”›Y–cš¸ÑLì¶Q‡Kò™´onv%dúf¯X˜½0{ŵÙ'ßá‡_»‚=p™Ñ:n舌†VùQAßåSýwG3ùe@òF7O0æ##/²`û<¾ä‹¾÷¸ñF¼ýíoÇ?xæ³ñú[nÁ/ýÊ‹ñÄÇßô^ùy¿ø ?w»ÛÝ¿õªWáë¿ùÛð‹¿ü+øé¾OþØ'­aqFñiŸõT|ð=_ù?~ îq{þä­oÅ7þ/ÿ+^þŠßÄ¿ÿþïùs½®áEØýÐ&žùp#˜­6§&ÃH†N^¤0,Ò7ÏköPk|nÕB(ÇFä{aöŠ…Ù ³f_ó˜}SŠ$ Ô\â)“ÞÀœ2(Âüžÿ©¬²}Æb{’Á’?Bsõ¼,À>›¸ÛÝü¤'à{ÿõáõ·¼Ñ‡Šþíü^øóÿ¿÷æ7ã!~0>ëÓÿ:÷ØÇÔïý­Ïû;øÄ¿òñxË[Þ‚_yñKqÃ7àÓ>ù¿Æ'>ùãêgÞÕë|éÓŸ…WýöïàëŸõt|È=ðOÿù¿ÀÿäOã«¿òËñAz¾÷~¿ô+/ÁÛn};>äQÂ|îgãþ÷½o]ÃnúHÜ÷Þ÷ÆO½à…¸ÿýï‹ç<ëéïò3?âaÃSŸò™øÖïø'ø©çÿLö;ÞùÎwù~ÿ¨À]ïrWüâ/¿ªŠOú¯žŒúˆÇÿñ=ß‹W¾êոϽûùŸƒý GÝé{¹âÝ‹‡>äÁøß|%žùuÏųŸþ4ˆžõu߈W¿æµxȃôŸõ½ žID›²ª­•Æ´9÷ì1ü…#÷ÿ›öêss±0{ÅÂì…Ù ³Ï³s_Ú€Nžñ•L“´’Õ¡§ ÙlÎØñ“ê–¿~Šh`G]Žæúºæ¾fÒ ¾./wð~?ÿô»¿ÿêÿ-¶mÃcóhüö«ÏþÆçá¿ñÊÃëüÈý~ëU¯Æ£ÿâ‡àÍoþüãöÝxÑ/¿¤~æ]½ÎÇ>Þûí^zóËëw^òÒ_Ã=îq<æC?ßô­ÿ~ü'ŸG=òáø¨,^ò²›ñõßô­°Ýê~ægÿæßÿ(n¸ánxÿ‡>ôN}^¸éq^†}Ý-·Ô¿Ý™÷{Á ¿zóËñ?øG„ùÿÿiÏÀm·ßŽ{ßó}ñÚ×½ßü¾·Ývû¿—ëëÝúúê¯ø2<ð÷Ãk^ûz<ókŸ‹g~ísñê×¼÷»Ï}ðU_ñ¥ïùÜH÷ÅÂ2ÿï/•ìÞ «_ςԆ¥ƒ]¯%NFd|!z…£Œ¹0{}-Ì^˜½0û,0ûÔ$éÓÎ2˜L¸Ue4­Ä¸¦#è·lJ¶~§u¥çÓ%ÚÅ÷djÆìÈ~À×v˜^ýš×á§^ð38Nxô0~ÿÍ€Ÿüéà¡y0ž÷uÿÛ¶á§^ððíßù]øw?öã•Å€{¾ïûà[ŸóllÛ†ŸûÅ᛿í;ð?õ|Üô~§^牿 ßý}ÿ¿zóËñ”Ïø¸åMo›~÷wñIŸðd¼æõ¯Ç‹_z3÷Ø×þ_xçm·á^ô˸åMoªS°ªâë¿êéxäÃ?ðÝúì×_=®¿þzÜzë;°ï;^û†7Ü©÷»á†»á;ž÷ PU|ßý0~ð‡OþØ'á¿ÿÂÏóòî—%^÷†[ð†[Þˆ»ßxã¾—+î|Üû^÷Â×>ã+ñŒ¯}^óº×î{Ÿ{ãkžñ4Üï>÷ùó¬£"³ÀÂâ¼ó"– £:ˆËç%8Kõ ÌÃ.}—½,}5_6°taöŠ…Ù ³fŸfŸ b£ñÛ$¥M\þID Ö”ÚÕÇõf®Ä?ˆw ;y)ò P‘(]Zyñtj~ŵŸów¾¸+˪øüÏy ð€ûáÅ/½f†Ç>æÑÐÍm-žøø›ðíßù]xÝÞpx¦§‹ú™zÜc!"xÃß‚ø×½î]¾Î½îuO|È£‰ßxåoáOÞöV¼ø¥7žô17áõo¸ðâ_}>í)O=\û[ÞúÖºŽë¯¿xø¼Ë±FÇãm·Ý†w¼ãxÀýï ÝôN¿ŸêQÿ|˜/²I}ÿ{^÷†[ð'o} Þü‡x§ïåŠw/¶í„ë.®;ŒÅ‹‹‹÷üž;”é~½}ÀîŸ•Ö j´m0M…tœ!ÂJ I?TL^˜½baöÂì…Ù×>fŸ|Ÿ¢ÝÝœ"åæ?Û^ðè%Â<…âo5úáFÖÅ(Yo¿Æ®ý¸é#‡îv7<à÷ÃGäGà¡~ àïx'`·½~öï¼ "‚»Þå.ÿÉ×{Ç;ý÷r"ÝÙ×yÒ>¿þ›ÿ~íå¿—¼ìfÜ÷>÷Æ£ñ¼ã¯<ÏûoÿÖá½Þ“pÆÍ¿þ Äû?ôý7Þxã»ý~ªú§€IÿÛŸ÷^®ø³ãÿèñU_÷\¼þ ·TÖêõ·Ü‚g}Ý7âkžñ4Üó}ßçÏŸ1‰¢#¡ ¼ÌžèÀJ±c(Ù¤I‚"%6Êe÷2b- ü+ä\˜½baöÂì…ÙçÙ*Wûñ(Ñß.9R¿•òOgÈL•£zûàVgCKJåñ¼Â]_½I×l¿ßáçáKþî߯güµOÁCôÀú~‚÷¯¼äeÕ³ö’—¾ $ñÞ׹õÖ[ñö·½ ð²›=@ðÁïÖë<ᦄªâ—~ùÅøõWü&žøÑ7A x¿?ªŠW¾òÿÅ=n¼;ü€Ö×ÅéâÏìå{Wý~o|ãïâ»þÅ÷CUñ7ÿÆ_ˆ?ßûáÏø·wç^®¯wëëÙßø-Ø_óŒ§ákžñ4<äAÂëo¹Ï~îóރ׎ìñÔ—%DÁÔdÕèÑ“‰™’H9äúÒŒù6Ñ3-¡›ƒFfƒÈÂìõµ0{aöÂìk³O>p¬Rå’»råȸKi¦þªSÙãM%3'ž^wcËàÀçÒŽs‚‹»~Îñ~yû˜GãWoþ5|ÙÓ¿ øþ/zñKpqqÏøëŸz,ϽímøÒg|5õ°‡á—~õ¥|Ú'Ò»õ:w¿ñFü¥GÿEüì/¾fV†÷ºç=ñ‰ÿqø‰çÿ4¾âY_‹¿üÄ'à÷ßüxÛ­·â˾ä‹ÞíÏõO¾û_bÛ6üîïý>~ëU¿ËËK<õ)Ÿ‰x¿‡þy¿w÷^®¸óñêßy >àýßÏ|Ú—âžï㙯yÆÓðìç>¯~Ík߃ ¤4™FÏ)­jn„X€¶l°Póðý톶É 3ʳ•0ºż_0k²0{ÅÂì…Ù ³Ï³OÈO» £É[+%î~ñ™éHÎ7m½U¡§Ë æo+~"èï‡'ò± ŸþiŸ€Ý¿ûž½ßŸž.¹³÷`Å÷¯þùîû=ßçø–¯ÿ‡ï!î¤Pž•a3£± ߻ↂÿ8Ãxƽ֮¢Øk3¬7A¯åbaöŠ…Ù ³fŸf˧<⇻{ Áns ¶æa&C]°GµÇOyGhŸ2øå»Ä.a¸—¼—¼ —v‰?~ÇkñþÜ7¬ö^OùÛÿîqãÝñ¿ÿ£oZ7cÅ{E|ê㟆÷¹ëC±m×a“»@qÂ&'/°éÉ „ÊË“ìPˆ27G=ˆ L Õ™Qm ÙWÝ–3—êdÅ“úb±0{ÅÂì+γ§¥¯=}Þ­ûôÂE 4h:ë(aô¢£«¢ÝÇ@¨é  ÜTFeüV¬Xq^‘ÚÓWæØd‹?g;‡op­²ÂÖõÅT ‘(3R +‰ÈnB#L•¨`¼>/Ì^±bÅŠóÀìS›êòèúÅãÛ¨ ³!)/%Õ¼WZ«ùoð“Ç—¶–JI„/ÜþÿA¬g¼â½ ¶ P!cp“öQŽª !Çhx îFs„ÖÔÕb† V‚Q ³W,Ì^±â|0ûDtïÞ–n7%Õ.9…ã:t·ã% ­Žéñ–ñÁ†eeåÚ)5£j¯XqΠ]Xérx"R„™¹ÏuÜÓ"¦–”ÿ·²æjQfp㦔+KEdaöŠ…Ù+VœfŸœa®Ñ[ûoS„t³¾] *ê v@ †=œvÂÕ]$ô ­¬v%.³-ǜ̊÷Îø¾ö×MXñÞµý(ÐudÓ$ÖÊ®70¶ÜÆ4œLqˆ¸H¨|H˜ÇÀZÛ5Ò²?Pƒˆ³0{ÅÂì+γOþ³„b MÀîÕÃìÈ‹bØMJ4˼à>„'¼êïŽeª—dÔŠ+Î, ôýjj¯ e$ì{ÑVþðˆ÷K›0@Û^á‘)û_S_ ŒEc\˜½bÅŠg‚Ù§Üŧú“AâB˜/cƒ¯‘í´ØïK8‘Qý"£Ï%0„›,C [É|_¨½bÅŠóÉ8*«ZCE-poë~À@;u€ôÍ+Ûöyë m§2¤ªt©A²Y˜½bÅŠ×>fŸ¢Ú¡ ¨ …Õ¶¨d¤Û£w…âFþž[¼õî’S€ v‡q¯÷¬t&ÆòZgÅŠ+β{£«áf Ê@oR¡Ùà>E>”ØÝ¦ýoÂ!‹P“Ùçt$CüÞÂì+V¬8ÌV&¹&Ú¼5„¹ýýX™ŒìZÑðz/K_qf¦†Dw6–“yñÝ€쩱0½¤¢V¬Xqny ˆÉÁ aª}ˆXgO'ì«FsC, ¸)R¦:® ³W¬X±â|0ûdÒ=yf޼ݩsÆ^ÝŽê“BP¼)tVÁ@äé½-åùžWdˆþU©ª+V¬8Ènþ'1v¨l±á¬³2¤ô¬~K³ÇOf"ĵY-² eç+€’¡ÂçRQJ²Ád_˜½bÅŠg‚Ù'°œD;SáÕD ºyê§æÿ†Bþ'âV¦¹»—=‰w7Æ(IJÐyb§?„UV¬X±âÚ,1V–£á\"KÌЦ>ôì1©òQhÊÞÀ2¡|li£ YD›…Ù+V¬Xq6˜}Š<º$è}&Št!CÙK’mV°Ù(N†ç;ýÁ€wùê+$Ì™›´þˆD»ï¬X±bÅ™àvõ.œ:C=7d÷¤,ÎS*ûýÂìÀŠÑðrG¯ÅÁK’æ ÓÑó·0{ÅŠ+γOiNls) ÞÈ`H |ûÏ8Ànl«0²›¿…(g1IÇÿÛ‘’bd®~¿+VœdwBDaTQT¶#ÑÍ'ñÓ0&»¡ÇÀ«z2r) ³W¬X±â|0û”e@BBWQ›ÈdT¹²²%yJ¨ì†+3¾Ñä™ ßˆ‚z…™žâ ¯}õ+V¬8 ÜCV¯ …‰©NE´øW¥Tk†b´l KŒ Egij”EÈ\ ³W¬X±â|0ûD¨gBðD¢9<¯D`‰H£‡A‚¹p”30]Œ04Zc÷_J!f‰=ÁS–*~â¦'=y „+VœInä;ƒÓù Õ`¨32¿a€¬v -V–éAf’­^µeùbC= ˆÑïçö ³W¬X±âl0[ÜôÝ!Ø’1é={Œ¯ôl‰¦|‰¤¡Œž=ÿyEá¾7›‹ r†\Ôb°¯X±â|Â@ìô/¼§,2 P›ôÖÕû­I‡…‰·”¹(0ÈŠ¹i±½†Î…Ù+V¬Xq&˜}"¨BhØ¢3Ï#ÓÂä@AlaI9õT Š) I\œ2'L»š÷ š€tç¶ÚýV¬XqN±mÀ¶½¹O‰ 3±AË¡ÑÛ1Q`qBM §Æؘ¤6«„aB‡Tß Å{-Ì^±bÅŠsÁì0É¢bºß”¡¤Ÿ‚<#%qÂäF²ÑÛê Øìµ„ø Ѻ…X´š+VœWˆt;¹.«h½°[,Hl™Í:˽œA:D8ŒuF…Õ¶FçQED™faöŠ+VœfŸŠNìt•l÷4;@P5˜í)ÜMì€4@=˜ÉËIùUKÂzÚZÊ1ý¾bÅŠ×zTîBªD6Ø.Poé`Ž©*0 ÷ÄTc<<)‹ßlÑcФH; f¯X±bÅ™`öI!€14-”¡bG¯©ŸêûuO³k¥5$¾ãâ¬Ê“%˜â¤ø9S`O»ß5V¬XqFQmA’QÝ Û 4 “b2¤ºHè¬Rb“–çÉ|·î èTñ?‹° ›,Ì^±bÅŠsÁìS«`…Ñ¢œˆ"È4Xí„¥Meôº$3³*™!C_{gKêC$ì)WrdÅŠgbÞ¬'l÷0Ù [lU xçNœÂÆ=VµÉ¶øTC'8*aië‹”ÄŽÌ ¬2* ³W¬X±â<0û”ÂNY'Ü$à˜žc}zÙwIxJ„ÏÎðw9“È’DjéxïËRaÅŠ+Î&LëRÂI…îFl Ýî†K»JÅ…Ø%YÇïGfy$¦]ÛZƒÅ^ýÔ[lŠ·…Ù+V¬Xq&˜}ªŒ…D_{Ïî‘à£G ³Á; ,X’rˆ°±Dé¹r0i’Ýi‘{Y±bÅŠ³IŽ@@S`ó¦ p"AÙ!r Tf^v s„$ØŒ€µëXè4ŠdÁ§ë£aaöŠ+Vœfk´‹— é’Ö`—HŽ{üÐßùâÞ¿’N½<°ÕA 2N³4W¬X±â¬@Û:CO«¹bÅŠsÊŽ Ý ‚£Ø‚<#" ›ºÑ¥#ÂÚW= ”'€öýv`¿Ä&[à"1dš¤³.(3B¼ÌYßY±bÅŠó §DOWg_mA»-k– ˆhÿ]* \Âv‹ÖÆN-Ët×Ì.êÍÂì+V¬8Ì>1dJ(l†e]û<À£‚`ÙW¦< L 1éã蜅ÀApÅŠ+Î(=2ÿbÞ-.‘—8§a,ø<~W]—:Ë“§ P fÛ­6À"±c;GÚ§/Ì^±bÅŠóÀìÌ›¶÷ÕÍM|™®`ÉÇN¿ÁÛ´`¦;k3{^}*ÈÌJxÆëp$³å3¶bÅŠsÃl!,,{! H80ŠÁ Þç'CVO|ƒkæb­J£Kð 'ˆºíà~‰Ýv6lþ]{ °`aöŠ+Vœfk&5¶Ò`=šðÆh½néR)–ÒP^¼¤H ʲS*91ŒTý‚ì+Vœa¤§y˜Ä\ýÊ’äÐÉ+»tÉls€>iäÙ6œNØN'ì.A\ÂÚ6ˆ^˜½bÅŠ×>fŸ’0S¹3ß}ëñ 2Ó!ÔàÐ$§¦+`)ÖßQJáôÝ„R ¾ŒV¬Xq~!™áÐhÌ(Ü“ ¢$£,ˆ…\‚ØEJ·ÚàÀ½K³úÿcïË㬨®­×>U=Ó# “¢Ì*QóŒC&ãlœÄшúéËËh0‘ÄLÆç3ú¢‰‡(*1‰C4j≳qÈ‹‚‚Ìc3v7tß:ûûãìsª.4Ð@÷6{ùkµo×­ª[÷öê]ëì½–‰PRX¶HˆšìhY9[¡P(Ї³cߺíRÅ2xÙàÙÊœ¶ÿy„ØgYy.!kwâHÚ†>Af#1 I¾h¢P(Å&· éÍï(éBäü:˜3-~8™©t‚<û"vñéD°–A–ÁÖB9[¡P(Ї³c×»Â0l§šeÆÏÝô%Iÿ^Jº’ˆN–Ãì&g,½ƒ]J‡g¤]„ …BQ,\mÝD¹›ž娑sf]Ôø’ZW³LàH Yü;¡T!!ã67 ›k“Þjål…B¡(ÎŽ QH ËRhZÙûÑL×'îÔ–åH7ËîÎ2‚Yg7Åp±ÀòrÜ]„%‚e“É‹W(Šâ1Üdºq6P.ú€AœOjC°ÆYñQê↠á[Ÿ˜.ƒ†ð|ëüúB<0³LÕ”‚ÚÖ(g+ E‘pvˆ`'Øàûçµ/°ÛÐÒÍ® QP9¼‡ ë`±`CnºÓÅ!‘çmÄñY ®¿\Õ…BQdÄ y Þ”¤¡pÎ iá~ä]V¥5ƒácoÏGVbÖÙ•„}‚£ñÏUÎV(Šbàìògé$ábƒ"v‚°”9(G²ÌhexFdyOÀÖ –iK˧Áç¹xJ?P(ōޏÞhb†‘åGFÀ¸vóXåtÐ;Yù¬E)f kae9Ódi_ï’_ú$L£œ­P(EÃÙ&$ÛøÞ;ršY—'Ã)¹ú ÞøŽ>JýW-9É=!FB~`Ç»ªPÕ]De8m…B¡(¤±/néH@dƒ’A~Ü\z©Ý¿-ë aß/â{MÚHbÙ'IŒ$Ñê>EšQÎV(Šâà옼–&hR%„}ÿ·œƒŸf÷'ÆXb±;q'ÉÿK q¶& ßÖ—º½†ï´ßO¡PŸF’–œ,­œµÔóžÔœ®#§®ÀGœ‹P"Ų… SpO´²-¹V0À£œ­P(ÅÀÙqX d#AÄ–\<¥Ÿªôá™…D˜Œ¹IÐM$–aÈŠj"}€H_Xú‚4eL¡P¡BB KÆq¹¥Æ„œžñk-Œ¡àêá d¶^öðM| "¯ª€`É"!7€“øMYTeNK_ål…B¡(|ÎŽƒZARƧZ°Ü}¡/ÞOÖë"¥“qº Ù: b+„mÃͧRJž£P(E#Œ„–@6QìɈ¯ªUre+˜óÊßT9qpˆ> {J§Ý¥?[9[¡P(Ї³cßyç¤m—þåƬoúKÆ8ÄT:Õ„B‚ŽËÒ$‡P¤ùñL²oƒ[0»Ä2G E1Á—¢Æ-Š×*KÿRj"9^ „,¡nÐЈr"ó윺TG2´ã†ÃE“VÎV(ŠbáìØ÷™x’¦Ðgb2}(ÙåF!bJd9ѽ ÎTø”<83´Ã™€Ã¬Ñ …¢Øz—·¹?+“ê²äHž­pœYk`‘`3b‹+pÄ6oØÑH¤#³MÔ•³ …¢(8ÛŒ•hB:Yn),K/‘{ùœ,€D:ÿ´DéNXíYž—Ù9nW(Š"§SGØéW òL\/`3K’,Sî®ÑÚ™¡™4ôW¤•0ðè¶Ë¸ˆ(g+ EÑpvÌd$)‡ƒ×`8-C)‡²aÑR|Å_ÐÙIqª€XÀG'OÑ‘¾¿ÎãÕH¼£ŠB¡P i“óm"i¯pí4`À‚Œ§à4`&u²öL™†ÉD^|‚YaÇ¥Ö©'îXÊÙ …BQ,œííR¥ßÄ„–oohüt»/ÚA.A,4Œ§);)©éEqR )ÉÁ”× ®P(Åö­”6Xd-,¬Mûû ƒ‰ð!°Áb®º IDAT¥•Ä•ƒŠbƒNâ#}ß q³W¨•³ …¢8;v:…Û±%Î8³²DR’ìPBB¯ Ë“°¢-ƒ+“ Ù¸Yã^,§ñ¿ÜY …¢HÔ–èKžé[¶’ÙëlÜ ¢+XSK=6±”F #á1,“ëLˆYÞ µ­ïTÎV(Šbàlãë}Ÿ&æ+sdT‘Ú±Cñ íúá§1ƒ”_Æ‚fig‚‘awÒ¬Ù …¢’,YSÆ™Z"|ÉÍ·‹óŒ$‡ÑZ¡ ÈtL‡F°ð£ãPÃ;Ùþhål…B¡(ÎŽÃ ¦O½aΘt{íðY•.®€`ˆ×í"Íår"’-Zƒ·›ø$¶¡ËE¡P(ŠD ý{žiIø‘D-ÉÆº8â%‹l¹z…¤ ¤Ÿà\A8ãòA¾ÇP9[¡P(Š…³cOÊ Y9¿Iâärakâ´—Ïç8ÉÜŠdÎÄ.úWvÎ,LÒßb‡kh|‘­í~ …¢¨”qì IYaAÁ7Yéi-{H¤_Ú+(²ŽÉ2ˆÃ. 8xaûqõƒ!Xc¡œ­P(ÅÃÙ±ïÑc_Ú³7ó6aŸ~·©ûÙ„àÈÝ¿"±—2îg–ÓÕI—f&Õ>Qžý‰B¡PL(n½ÖáÚ5¬¸T¶b •uý ¤|®Ã:e…}j‚(#n¤D,žÙ¢°døX9[¡P( Ÿ³cÙÌõ£@zóä@¡}% ž“àÛj`DNÞÏ•RÂû) –7Ýý‚…͇3â` ®P(ÅÊKH”åE6båda$Ä€ˆ` °œ‡ƒÈŠ–"$Oi_t¤Ë&7ˆcYÔg›z¿*g+ Eás¶ÉŠäN­ˆÀd‚´nÜY(7 cÂðLúBR»ÎÄþ’”Nûú|SºÖQÒV(EÅÚf@ k¤0õ_F"x‘g¯çÿm߉ê‘zN “ :%ÙÇÊ0„ü)MsTÎV(ŠÂçì8µ {'¤‰cFlKŒ(%žl!Á!æÁâ[ÌÀÅx0%ki'¶nÈFk E·3òˆÜ·™]'™²‘ÁB¿âhSWÏx&S´¦´.>­{>°ôÊ_ål…B¡(ÎŽCL/û IO¼^,7L°“nâtÙ2t|S4ð•|, :ÞÅ•£Ih‚·B¡P Ø/`JœŠ!¼èÈܦj‡ŸK-ÖiÎR° 6ðùd¾¹:ÏTŠœ§kìš? œ­P(ÅÃÙ1à– );¿.R$ Þ¹°ŠH!MÇ“/X댺}™od:ÝOµ‡€`?L#?û+ P(Å"Œ¢ó\ ?¿.!未zc¿L ¿ôhL[Ù'5Ú*Ã,‘èÕÙ³©r¶B¡PgÇ$3¥NFüU}Ï^zl‹Èûv‹*â/Óž=Ù _"ŒÄz&$Ë»NÒ~?…BQDêYXceŽÝˆ:"|˜iÊ ¬ÆaœS«W¢Y–*å2"_ó’4‚p†ä¥u#!W0+g+ Eñpvœž‰käÎô} aûÀIN“uÂä¦?i×hEq=*&ü€Hõé0Næ‹•´ E1©#<¢ˆ8¨‘ôO{Õ˜ó2Åä»àÂAYñF\¤d‰FˆHç0 ©œ­Ø@Q¡+Û‡ôT9{=œ‡ì^öà´ïDž‘åòt¢Æ“®Œïwñ½*A>‘ýÉ2§?Ff"^?œ…ŠË–¢qÉB´45éÅØ†¨¨ªBC÷PSW¯£0å¤þ ñĔË@‘žæ°¤ÇòÌèÅ7/ãÕ*(m á”Ja…ÔFålE{öŠ¥K±´qZ𕳷)gWV¡¾¡'jêëµàVÎ^‡³cï½jdƵžx£mëd",­”ñngÜmC닟³1ØXi$·`NÒ4c›¯²( çÍÁ²ÆÅ(-+Gum^mˆ\[æÏ™‰Õ-ÍØ©O?½ …ÇÙ¡ev©aF¦Ø3ªGFOñűAÚŽA X²nòK„FxÔõöùb˜Ø€H|±•³íÙ‹ÎCÓÊ•èÕwÔ(go[Qjù2,˜; ­m«Ñc§>Zl+gçqvÌ~úÜ/+†IK±Šòžé·œFv²<3_VïCh‰ÀÖ ò¶)*Ž i,[Še‹QÙ­Z/Æv@\R‚¸¤Ë£¼¢R•íIØsâpË…D©!žDºØÔ6Ê rÆPÏ=f ­Mm¢àz° LèLdõ’aePQ9[‘_d/_Úˆ¦•+1d½ô‚lÔÔÖ¡¦¶S'ýJJÊP[ߠŶrvàl:ÉYþ$±"çèà $š×Ã’³xrU<…'{õ„‰Ã>ØF€5`+ý+Ö„¨`Jo$„Æ% QZV®b;£´¬Kê…(¸Ê&ÛÓ—†Ç09ž¶ °$‘&&Dˆ¬¬´c`ÙÂrâ8Õ8å8f Kb8ãma8oWålEÖZ,m\Œ^}wÑ‹±Ñ«ï.XÚ¸ÖZ½ÊÙ³cb B&™èIâT¾Xw¥JXsd¤yïžúi­¡ ?%/›²³pE¡¡¥©IÛE qI V._¦¢`¹ÛóûÙô4m,¨%Ö¥2’÷Àö4^eaXJ‡oœ¨’z\ÃÇøú-Œ+–•³€S³™«››P]S«ƒÛÕ5µ˜1mrx_TÕVÎfÃÎuÄ0Iâ—ó C왡O°Ö7Ã{ 2òC]$0‘€]¼¯ öĬ­Ä( E±6¥ýd²ã†b‘‡ =s(‚YZ3|¡d¤ÇÚµs0¬!˜DþP:ÈÈ Pø*g+²Å¶BßEárv°÷ËÎ¥‡ÆqI ŽO’Æl3ë‡zÁ 6Î;Єáx µD2å‰a)å$UL …¢àGÕ”!ˆî†(¾XÆMµgøà8WdBf8í·6 C2ï¸×Šï«S®ål…B¡(Î6ˆ^ NwÈ^J—ÆqòU:¥U>§KîÁ–HB 2²ºD_’?Q2éR¥¶B¡(JÒ¦ì7€u¡1†ƒ‚ˆŒø\§zž°³ê³M¹Uöáé3ƒMjµ§œ­P(EÃÙqx yyî$‚9§ ~«áÀ®^wÆÜF–3áNàJ}fI3Û(wáÈ\? …¢˜À):†µ02CØ ¦l/zÞ Ý‚D ë,ùÒ®§L[á[CîBÄ™%iål…B¡( ÎŽÝ2¡Mcu9?hŒÒCà ‡‡¡˜L@àuLÈO_¥Wî Qš2¦P(гý¢#Ã0ƒÈJŸ†süpœf¤:à†i,ÚEQ JWïÓ*ìèaÙy½E9[±ÞjB¡PgÇ~yØe´Ûll¯ëÒK#%á{õRv;²Ë)Ià! TLnšÝˆ8¦ÉþQP(Šb«i(ÔNe–áA±ÒsŠ2U÷D×÷ìíöÂŽü®¥GÐxOJùׯÊÙŠu>’Zg+ÉÙâ¯jÂSL¨ÚudKÖy Z¯€X÷[Í 7(³¶¬"æ`Ú-v(dá¬S– Yï»^}óŸøÅu7àÂo~ç\øŸøÞ~Šg^ø;`ì•?ÇsŸ¶ýÖ÷„G²Cû]û¹ëÃÿÞ|+¾}Å•ëúžþÉL|eÔxò}³›…l´y"E(“ë—&6Nå0Z2˜%øÅ$2‹O«¬d†þëÔéƒ=OÀÆ÷R(g+:Ͻð"¾yÙ÷pìˆSpÈQG㜯]€‡û3àÜ .ÄcOü%lûÕsÎÅÝ÷NèÐ~×~îúpÅ‚3ν^Ξòá‡Øÿ‹_Â?ß}Wß,EQrvÌ :°%“(é>à ëÍÊ?)ƒ6âI̡ƭ3ºo,’°Òh-‡;ˆ´ÚWtÜtû]ø÷¤É8ýÔ“1ꌑÈ%9|<ýTUV´»ýþû~wÛµÓÏcæ¬9xû½á3ŸÞgŸu´°W(6¦Œ8 Ëô>Ks†sëH$ =}43ZƒÌ˜¢L¦;uÅÊ£Vœg+2K—䕳€Ÿ^u5Þzç\<æ|ãÒKÑ–kÃä)¢º[U»Û|бû°a~Ó>ú/¿ú*¾øùϯó³ñîÓ7JQÔœ3"Yô¶$ÖUãâè–(SÂŽät­<‡Â Ža¯“8Y$"B‚LÀ%XJi‰It­«Ë௾OšŒë¯ú1**ÒÂz·]ÖŸVvæi§l•s©«©Á#?µN¡=oÁB|0ùCTUVê¦ØryÄO Â9sØÀ~,®Î:* ¦ –]Š£ È~8Þq®[†ÌFÚB”³[Ž¿>ó,Þ|çmñŽ>ò0üõÙò¶Ïår¸ÿàÕ7Þš¶V°ï`ô™_EyyÙF_ÃCü=òç½Þ‘#NÄÈ'ꇥØ9;ÛqÁ™oDå é¿`¤~Ö6Õ¢%ÄH£×ÛTYòfJyÒ)ÏÊÙŠ ÊvÄmwÞ…‹¾v>ªª*7ðÜl¬‘k9åä“pÒñÇ…-xèxäÏFcc#>õ©Oaì·¿‰>½{ç=wÕªU8ÿâKqÔá‡á‚óÎ]çÇóe<þ—§ðÎ{ïá?öÙ;üäî ÷aä©§à?’wmmm¸ù¶Ûñìó/bÍš58ä ƒðͯ_ŠÊÊŠ½îÛïß¡ktáùçaÌù£õ£¥œ½EœíºH(uR%â¼fqÊd‡y²µ¡„OÅtK@"2º÷yeš@þ.!;oôÝï"XÓÚŠù bèà[´ŸGÿò4^|ée|ý¢ pý/~‚/}©î–·µ×Ýô[ì¶ëÎíÙPVV†ã¿|$δ‰4.]†×ßzGqØ:ÛÿîÞ0wþ|ü÷OÆáÚŸþ .„ßÿ±S‹g-²»p]#Å/2QæÙ™ó”tÓÉwÀŸëü}€MPOÖËq3îÊÙŠ-ÁêÕ«1kölì5|Ï-ÚÏ=÷=€'ž| ?7Ü3Çy$êjkó¶I’—ÿèÇ:dP;E¶CEyÎyÆß›¶‰,Z¼/¾ôN;eÝ•Ï_þêF|2s6î¹ã6L¸ëÌž;¿¹åÖN-žµÈVÎî,Î6΃5Á"%0(4|3KS7`|_ gb+¥ÜXX±K MåÁOʺpòdm•¶»,XfFMÍæ/ïYkñðãÁ…çƒAvEC}¾ø¹PVV–÷Kò»{ïGKK .¹à¼ îïè#Å”iÓ0cÖ,ÀãOý‡üEt«ÊoiiiÁsŸˆÓN>µ5ÕèÞPÓ¿r2^ûŸûÆŠh-²»W‹®,ƒ…–eá­$4úW3{W7ÈèqØ´BÖ¡°%’¡áaXXk…‡•³í|.¹ã_³fÏ3£¶®~ƒÛ!|žÖý>—Kp×½pùw¿ƒÝ‡ Eî=pÔ‡£¼¼"lË–qí¯nDSSÆ]~ùzÁ¾2âdüëßÿÆ”©ÓÀ L¸ÿA챨öb‹l¿jU}ü \pÞhÔÕÕ¡gž¸xÌ×ðÂĉ~ýcÎ;cÎ[=æüópÁy£7隆ףPÎ^‹³ãÔWÕ‰­““;ˆÜ¥•ú<ã…¬Õ³I[˜÷`XæÌd[ÂÀr.£’°.BvÔ×9cÁÂ…è6`Àæë‹cõê5mf¡íIÒZ cÚ×Í>µçî˜3o>ž|æYœ5òÔîóø/‰K¿{9"ãÀý÷E}}í:ÛTÊ`äÕ?¾u55[tF „b[‹ì.,{;£±Ú“aDŠÒeDfç¬j2²5ØÆf&fÍðM[8üÿg‹dålÅ–¢¶¶ õõxõõ7°çfÚ+W­ œEQ»Ûìÿ™}ñÉÌ™øýÿˆK/¾h£û½{µûó(ŠpÒqGcÂþ„½ÿ¬e,nlÄG(ø7-²wÂN³ä …?Ig×Ëç9°¾øõÃêÆ1$Y °†¤À·žAÉ{f O+g+:gŽ< Æ Ũ¯]ˆ?<ü(>úx:fΚ…§Ÿy_~ʼnuµ˜;o~»œ][SƒC:×^>™9MÍ͘øò+hnÎo»ûìûcÌù£ñÓ_\Y³çlô¼.}.n¾ázô_5lÇ8ûÌÓñ›[oÃo½k-,\ˆ¦l~Ù˜óGëà£röVãì˜Â¼ºM£{áš¼™Ò_®ÐóGn щ">ôÀJ¥‹&ŸF–Ù#‰ï‰Ÿƒ÷¾…zØ5E®û<õì xùõ7pÿ†!ƒûõÁQ‡ 8þè#qëø{1kÎ\|ï—®³K.»&<€qW]ƒ\.‡ýûc×]v^ÇfïÔô§ãÚoÂÕW^±ÁÞ¿ênÝ0|÷ ,œzâq(+)Á÷>€EKQW[ƒ“;ƒì¦o¬b]çµaøE@<«C¶¹S9\YkE1q.ñ#„ ȵ]FT͚ȑ~(–•³[†8Žqó¯®ÇCzÏ<ÿÆÀ-Sú­˜Bt°% ålE»ŸK½ÿQ( ’³cOº>ß&‘èIG¼Ń„`]sxÄ©b}On~B“™ƒ´îÑC™ï½Éà( EѰ¶—.$€‘ùT1#1bi äÿ8³P¢¢÷oÎvËœHû ™³SíÊÙŠu>˜z Šäl³V,*f$u1wò‘•†È7~ûD2“Fó29›“ÜMÐ?Rék)*ŠÂBEUrmmz!¶3rmm¨¨ªÒ Q` Œ[jÊ`”a6±}ò•nˆjä ¦P†¸)³_Ãþ€<‘üT|úÇA9[±6Ê+«°jÅr½Û«V,Gy¥r¶rv>g&†5NÝp¬@dID +}{”ª$Ö5…³Lcf“vR3WÞEs'ÿ\ãÝÜ Ea¡¡ûNh]³Z/ÄvFëšÕh输^ˆ‚cmNAöê0\"£÷fåYîú7˜\ß³%F›Úˆ‘ñneg,•Hj™eY±¡bYª´ålEÞÇ‘µµõX´`ž^ŒíŒE æ¡¶¶^ƒj”³ó8;Èr¯ ã– ÉÇp0ßö1–ÖçR2»©w&¹Þ– ƒHJð_%ÿGÂ/oÚ é+ 5uõXÝÒŒe‹QZVޏ¤D/Ê6D®­ ­kV£®¡jêêõ‚dqã ÎxY{EÃ)#†ó•/’0ÒåIƒ´ru„.Š ³»î™d ò¸Àål…/²‰U5µh˵búÔÉèÙ«ºÕÔêÅÙ†Xµb9-˜‡ÊnÝPUSÞ…r6Á 挩vøXøIu¤Ó–~‘eªÒ-5&ˆ|/[2ai‘ƒç`äT$`c]û9±L|êXM¡b§>ýP^Q‰Æ% ±rù2½ ÛUUèݯ¿Ù Oº J{˜Å"*-\=]K‹‡Ÿ[dsW³ß§ËþùÞ胈`™¡œ­Èƒ(ŠPS×qTŠE çaÖŒôÂlC”WV¢¦¶•ÕÕˆ¢Æ½(ÊÙ³coÂÍìM¸½ˆnB ïäŒ4ÁÀyS8˜a#Ë•¾¾·AAq­rᜲ.ŠBDM]}Ñ{ .r7 ;õÔ7RÑɬÍECœ<ȸpW²Â0`Ä^Ï-G:Î3Ò~a…iM¶ö|¾}#tR;µ€r¶"_©#DQèV[‹ŠnÝ`-‡!.ÅV¾þ ãÞÿ¥j¶rv–³c° yíÖKèBäÁwUªÿ •„ä0ã̤ȿJ ™^@¿É X–géìºbë`É’F,ilDq„î zQ÷‡Õ Âì}Y³–Qò8ù"ØÇŸ[Ä0¡':û³´g¡¥CLú൷Dé[G6ÄÙ²0J fëË@î9Xrá6Lf¢œ°”ÀrX ¶If”ÈG.—ÓÂǾëŒ6_lûÿ²zým—÷Ó£E¶rö:œ‹9‰4€‹z4° ¤Žef-CŸ ÌL`aK‡‹?°¨"ƺ&r‰Ô ¹ñ¤| èD,_±ó,ÀðáÃADø÷¿ÿ(ŠPW«=‹ŠNû«š™&ÄóŽ…f]LBÔÆÈѹn6Ý»°¦>ž‡å{áFÇÐÞ[°>Îvó Ú’f´r rI+˜“¼âš„§Ý¹ºèu?-ïÕç kÁœ G°9X¶`›CÂmXݺo¾ù–~¶¥¥%¨¬ªB}]ºwïÞ)íZdoÿb[¡œÝgÇ,‚ ÌÒ`p(ñ~—øÃû>&×—B‰+°ÓfsÕÄ©Ú&*ð:/@¡G26š IDATØR¬Zµ ³fÍÆž{î‰ŠŠ Àž{î‰÷ß‘‰P]ÝM/’¢sÀVâÐeQ“ýckL!NÃd ,L°ç3AK&oÅùÆS^Ý òqèks6À–‘KZ°&·†ï„#N>Ÿ=t8vÚ[ß«DKK3—4bþ‚ùX¸p!úõë‡ÚÚÚNi;ЂO¡(,ÎŽ½ßj"!i›H*™§=)k0&uW%'S˜p—šSYÞúƒ‹<ɉg–¥O…b ÑÜÜ‚ŸÌİaÃP•ñž®¬¬Äî»ïŽÉ“'cÀ€ÝPUY©K±¥âˆLž;‘ÁPê.Í̸yí #ÜgœÞaÆš[Ÿ*&n|Ä„Hx3´ä1˱³œí:×$«Ðܶ—^1_½ø0}“ •è·s%úí¼3æÌž)S¦`×]û£gÏžˆãX‹e…¢ qvì…jÊXzSªq%rOð©…”³OBo| &Õ)q@ä,]}ÝOªgüM`,C¶¶¶âãéÓ1pà@ÔÔÔ¬óóêêj <S§NÅÁƒPVVVÄ ¿û;!}ÑîÿT`‚D¨`¤Ü I=®ü¨Yúþ¤xÎôBv\Wt&fŒ³ûuµq3šÛ–áªÛ.ÄAÇì­oP‘¡ßÎ;£¢¢ï¾û.JJJP__8Ž»4gwÍbN9[9»}ÎŽÝ÷¤oöfƒbqÂä¤röb9ùKOŸŸF'¶IÞd»•“q/òý¥O[Q¸öŠ¥K±´qZš› ˜Ý ZÙ`àÀAèÞ½ûz7«¯¯Ç€ðá‡SQBÉ:Ãa¥vUV¡¾¡'jê5ø €?x´ä:Ø·aZå¼_ˆC^º¤)dî[ìdéœ&>‚Yyd0´äVà’+NÑ"»ˆÑн;† †™3?AUUŒ1›Ü³]4œÝ¡œ­œ½!ÎŽïôk'o÷ä$t“ÆVŠ”N°¥Œ ”¤¾sêy’žƒ˜3wØi 0 }û ±È^¼pšV®D¯¾» ¦¶® ϳ­­ “&OFÿÞ½±ÓNOPìÙ³'’$ÁÜ9s°Çž{¢d T£­‰Ë—aÁÜYhm[;õQâ.8ºvJ†›sñöw⮄ ©QÚçç šc°‚GÌn œüÏl™„·ÒÊÇ@Â9¬±«0p>8]ÛEŠývÞóÌÇ’%KлwïM*´‹…³»*”³•³7ÈÙa°Ñ·€x5š„Ÿ Ø;ɇ'"7aÉDapÝÎÕµk[÷d¤›2^¬ñ««\Wd/_Úˆ¦•+1d½ –°“$Á‡S§¢GèÛ·o‡Ÿ×»woôèÙS¦L)X‹²šÚ: Ùc/4­\‰åKu)¸GR72cüÂdO $º<3hîÝ™˜‰‰`ý`ŽXG%Xo Å ÃÖ‘;»x`ô–m¹Õ8òäýõMé"èÝ«7–-[†¶¶¶ÿÞ gwe(g+goˆ³ d€Ñ„"Ù+Í,K” C.¼=! K¹0miÉ5…»ä0·±“à¿E@æ„áNʧŒi~RaÁZ‹¥‹Ñ«ï.ýK3í£P]]þýûoòóû÷ïÚÚZLûè#X[¸-$½úî‚¥‹ úwHuÄÊ€Àle@Æ-#1¬±HHÜ– ƒ83 šÐMç»ÙJ…òRf|š ‘9<ç2Ãr>{èžú¦t4toÀêÕ«‘Ëå:\¬gï(PÎVÎn³cßúZxËF2•é&,ŸB7‹ C¾ç™”&_A_¼»þî |€&ZËÌXÝÜ„êšÚ‚¼+gf|üñLj¢ Øìý¸~íñÑGaРA¹ÔW]S‹Ó&‡÷E—# nUÏx2fÃY&ÑÓÑ’˜¬ÓRÆ)0kf²Ý‡$p–%9|Y¶° µðëB¨¨¨D.—tXÑ.ÎÞ‘ œ­œÝgïâ d„JßOµ»B›¥Z7lÂI‘ÉÉÊËa Á ·aºÓ»—„—£(´Bv{ÛZ k-’$A.—[çkÆ'Ÿ ±C‡Ýb2d@„§Oo÷XI’„óÙÞ×EQP¿%^NÈüceu‘ $IÌÉ6v’!òl¦€yqÃèNb Ìé¦Û5f»+¢²ªj“8GùAÿŽ* ›³cç—í}E¼!·´u°×»É—bÙÚPt³ÿ5~{éq!‰ÿe©Þ²KౡåÄê „âzñ’%X¶t)šššÐÚÚš·MiYªªª0|øð-NQs¿„aÆáƒ>À{g5kÖ䯴UUU¨«¯GNJoS?ˆ2.sÀGŸ»V8Ÿvk›€Ëö{À&“ĘV™ ËÒšçZòœÂÁáÉqvÚù] UUUX¾b%êê´×Z¡è œ‡»/ \‹ˆ•ªÜ²•¾‰üåΰϤ²8¥á3Î22ÿpöOzÊÓéμÿ*vØ;ÿ$I°lÙ2Ì™3qc§^½0dèÐî¸5aŒÁ§>õ©vÖÒÒ‚¥K—bá‚X¸`úõ뇺ººNIoS7i§vLF’qÓ€.f GHÕ…[~$ö9NQ1ð\>§­y)¡3@†L¨«ýÒ´QÛ¦.‡áÇcòäɘ5k6vÛmW½¹W(Šœ³cÿÏ( Õ;§þ×¾(! &,†ÞÞ­$µðƒ”ãìÓ%}¢™(ÞÖFê߈¾ÈÎårX´hf̘!C‡n’ƒÈÖFEE***зo_Ì;~ø!vÛm7MoÛá?·”†nYt|gÀ ²!ÜÀ'áJ¿ ïõíwäT‘àyê7óª 9¦@ ŽÀL JR2'ÀU´»Œ1Øc=0uêT|<}ØM‹m…¢ˆ9;všL¿ŸL—‚›œÇ¶ŠŒ‚© …®—p×ܱ‘ZŠÊmà|}aæ<…ùÑÜêGH’–.[Š3f`ï½÷F}CCÁ^¾}û¢¢¼ÿú׿—ÄhØÂô6E1ÿfpª’„4]OÛ~2<„ñúÄ€”ˆ³ƒ2”Û¤v§¢Œð¾äÓÈ~aT£­w]D„¡C‡búôé˜6í# 8 |£Ÿ…¢9;æL‘콪´ÈÎ+¥x/×Ì€£;†!rá7Y;œ ‡¸ËÔK[Q˜w€[wÿÖZ¬YÓŠÙ³fcÈ!]d{Ô74`È!˜5kª*«@dTiÚQ !OnÆ‘µ„„h_'2Pp`ƧæR&Ä‹²DÉÔãFàI–5ýA9 #h‹vWÇ€0gÎLö ˆÒÒ’íÆÙ …röæq¶qS’IK#î!R•ûIJvÐaV“}v¼ŸÝ„Ä´»#F^L7ÖÙ§ U¡˜O-QôÐÕñÜ /â›—}ÇŽ8‡u4ÎùÚøÓ£aÉ’%ï}èÛ¯_Ѽ–¾ýú¡´¬ K–, ®$<ôœ;æ"|Ô—qÊégàÁ?üQßô.ÎØD6%k‘ ,œÊaYXQ–#­8,ƒÇ–6„x‘uDoI›`ŠdhHà†Ç²H9[È}ðÚo`ŸýÄ÷~0®Ó/ËšÖV¬^½:ï±3GÆ#ýy«¾c¯‡}ö?ûì >ó¹/`ÄÈÓq߃¿/(/ãÿüæ·pËm·oÖsûõë‡>}úàéS×¹¾Û’³–÷ñÜ .ÄcOü%lûÕsÎÅÝ÷NèÐ~×~îúpÅ‚3ν^÷Ž)~ˆý¿ø%üóÝw7KäQÎVÎÞ–œƒS{?0ÁŠ‚í¿, 1ËN‚{ ¯îIº\Ä´Ûú;BB>™†dÊSœH¤HÏ“ã]?½êj¼õÎ;¸xÌøÆ¥—¢-׆I“§ ¬´K—.Åa‡Rt¯©×N;aîܹèÞ½;ž{áE¼ùÏ·ñ_ÿïbôíÛ¯¾þ®¹îzôèÞ€#ÓX쮈lËù8OV&×vçe8\†É)³‚çËË⻊4oÀý°aŠ]&ÕƒØ èxÎÞ<õ׿ás€‰/ÿkZ[QVZÚi×åŽ;ïÂÌY³pÍU?ßæïÉȯœŠo\z ZZVã•×_Ã5×^‡ææfŒ9ÿ¼‚øÌÄqŒ(Š6ûù}úôAǘ6í# 8U••Û”³'OùÕݪÚÝþàƒ¾ˆÝ‡ ëôó˜öÑÇxùÕWñÅÏ~ŸŸpßfï÷™çžWÎVÎÞ¦œûÚÞˆŒn]í솥ºO§*³w—&ï¤-‘DèX{ €k3!æ$ ·ñn%ZiwYüõ™gñæ;oãÁ»Ç£ª*%éÁbåÊ•˜òá‡8`ÿâ‹®ohÀÇÓ§£­­ Gv(Ž>êÈð³SN:o¿û.^úÇ+JÚ]Wqþ¨ ™\wB„eC>´+ë®äØØúÈ_Ÿ æ3»BB.#ñj ¹Ä²ˆÝð Á…_X¤†Äؤ%Á¶¶6<÷‹¸ýæ›pÁÿ»¯¼ú=øK]â=)-)A·nÝЭ[7œtüñX±b%î¸k|AÚ[:Óᇰ§M›†]û÷Guu·mÆÙC^ïs.¹pÌV¹f õõÏ„u íY³gãíwÞEuuõfí÷ÈÃ×W@ cÇ @ õÁ&–t’/æçY‘Ë$ÈJ„MúŒ¼üêkèÖ­ {ì> Ÿ;ð<ûüóy??sÔhünüÝ8kôùøì—ÁÈ3ÏÆ;ï¾~n­ÅïÆßO= _<ìüç·¾¹óæîºç^Ü~ç]øë3ÏbßÏ~¿¸æÚð¼7ßúçz÷ÙÖÖ†ëo¸GŸp9êhüôª«ÑÜÜ’wNO<ù.¼ä?ñùƒÅ«¯¿Ñ¡×ºï|Ë–- ûÚйûãÜÿàïqîׯàóгFŸ÷?ø üüð£Åëo¾¾ÿ`Òdð…ƒ:üü8Žo¢nòëë1lØ0|2s&–-_¾Í8{C_ç^0=ñDÞc<ôŒ<ûqìqøæ÷ÆbÞüyëè _À‹/MD[[[Þ6¯¼úÆ]>O>úöÚëSøîåßÛÜrûxæ¹çpÝ5ÿï½¥%¥¸àâKÐÖÖ†óFƒ1矇/yÞ~íü`ìeaŸ³çÌÁÆ^Öî>ÿû—×aÆ'3qÿÝãñû ÷`öœ9øÕ¯“wN×\wŽ;öhŒ¿ãvüÇ>{wèµ.^¼=zô@eeÅFÏÝãÑÇŸÀ·¾ñu<úLJ°Ï^ŸÂ…—~+W®ìðõÝÐó;CÑö¨©©ÁðáÃ1wî<466nÎÞÜsßxâɧð“qãðÀ=ãqÌ‘G¢®¶6o›$Ipù~Œ¡Cá‚óÎm_Ð(¯À#OÃø{Ó6‘E‹ãÅ—^Âi§œ²Îö¿üÕødælÜsÇm˜pט=w.~sË­:gålåì­ÉÙ&‚7í¶ÁKЋèáD²÷”ªÖ‰ßof ‚£t㑆C7 `B½ŽtŒRQ¨w€[ò5kö\03jëêÛý¹µ\Ü7ÿòÖ~]/¾ô|2k6N<þ¸-¾†ê"P œ-£',C‰Ö7BÂn0Æq$K‚®§Ðh²+‚l‚ÌAÞ˜IV%Ì r2YÎîhëHKK þ>ñ8äKN…ýÂç?‡¦¦¦<•Ž?öì±û044Ôãk£ÏÅâ%K0sÖ,´¶¶âž ÷á‡ß¿CÂÎýú᪟\‰¦¦&¼øÒÄ {ÄI'bø{¬³Ï¦¦&<üèc¸xÌhh¨G¯vÂ¥ÿï"<ÿ÷¿ç=ÿ’‹.ÂIÇ¡C£¼¼|ƒÇJ’“§LÁ7Ý‚ÑgŸ>÷3Fž†Oï½7vêÙßýÖ7ÑP_‡§ÿöL‡?z~gÚPYY‰áÇcá¢ÅX¼dÉ6áìÀIòÕÞ÷¹\‚»î€Ë¿ûì>l(zt8ååa[¶Œku#ššš0îòË×{ ð•'ã_ÿþ7¦Lf`ÂýâøcMÛfdûU«šðèãOà‚óF£®®={ôÄÅc¾†&NÜèëVÎVÎÞÚœ[ ¦!ŠÀlåI.TÆí&èׯ#z]H2àÉ¤ÞØd"n}v(Á XHXÌ´I‹í.‰ž=ºæÌ™ƒÚD)X¼x þû—×á;ÿõutëÖM?]ö.~ÎÕº8tö2…Äñ²/‹ÓV´ ©ÿªáðÿ¾`ÂZ-" ˼‹›y!i¿ëØ)¿øÒD{î¾ZZZPUY‰!ƒáÙç_hwØ úöéƒŠŠ 47·`öœ¹ÈårØ#ó»\QQ½öú¦Ï˜ÑáK—Ý猙3a­Å·ÇŽ ×%—äÐÔ´*ï9åeeÝï„Ä„¡_ß¾8ûÌ3ðÕ¯œ*Šú¦Ÿ»1ûì½7>™9s³>"k??ŽcDqTÐëÎàì¹ó桹¹{ì¾þáÈÇŸ| “¦LÁcý~£Ã¸ÕÕÕøÊÉ'áž ÷á²o yêiu01pÆ)nO†]‘ #Oñ€Ú9Ò%Q[[‹†úz¼úúØs(´×´¶â²+®Àþûí‡ã=F?]Yñ¤mÝзaˆb¥[ÄQɈ(!:1ˆ8ß[âz)¾¤“…°°48²±Dþ¦©³÷{úoCss :üˆ¼Ç.\„~ÿòõ:bøðÓÖÖ5°Ö"I’<ïøÒ’R”u noŸÕÝÜ0Û}ãïB÷-ôÑ÷®#¥¥¥(]«xÛÜsŒÉSÐyåÊìóûö郆úÎË hnnƤI“Ðk§ž¨©©Á²…s ‚³W®r7IÖÚõ~¦öÿ̾ødæLüþÄ¥_´Ñ}ž1r$Fœ~:Ì 19ä`ô‚¼‚¼ÊÉão» õõÊÙŠ‚âlã«h±íQ¤up˜Ö Õ{P¢wPXüv¾<'€¤÷…DvOãnHŠàpó¿Î<}$&ÜÿæÌƒ-{Å8\{ýÿæä¶ò“íÈõI’~ð£+QQQqc¿‹Î¨ÑÁšBÿÕpK‘Æ Ö€\0A(„XãˆØ†Ì”ý™l…{îdJ§Ü] ž³L2Ò ‡çm¤øY¹/¿ún½é×xïÍ×Ãד=‚eË—ã­·ßÞè>vÙeÀÛßbk->˜4 C år¹_ƾ}z£ª²ßHëIGà]GJÛQH;zòÕÏ0 ƒàðéÓglð6ôüóÏÕi/+V¬Àû￾}û !ïe[rvûß÷ëÛÖZLš2y½ÏíÓ»~ö£âÞÄ‹'nôõõµ8á¸cñ·gŸÅ9g|µÝmúôÞ U••˜ø—;ô:•³•³·%g_±“ÏÄ<CÖ¤«$ïãê”lgÏgÂë@H‹4ðA“.ºÝG»»?®V·ÇEWÄ™#OðaC1êkâ?Š>žŽ™³fá¯Ï>‡×Þxs³÷{ÇwáÊŸý¼ ^£µWþì*Ì7?ûáH’---hiiÙdLQ$œmÒÙT pä’Å2«ƒVlR€9~÷|éb MÊM7ô(Dj×¾îž}þÔÖÖâ€ýöË{¼_ß¾¾çžxöù6ºªÊJŒ8ñDüüêkðþ`Ic#þçºëÑP_Ï}ö@@¯^½ðÏwÞżyóÑÒÒ²Ñ}ÆqŒÑ£ÎÁ 7ÝŒ×ÞxÖZÌ_°ïOšÔ©ïWGÎ~{ûxñ¥‰Xºt)~{ûhjn‡ øô>{ã‘ÇþŒyóæcÞüùøÓ#¬sœ =ÿòq?ÜìÀš,–.]Š)S¦`×þý×0Üšœýô3Ïbâ˯8å»®sçÍo—ßjkjpÈAáÚëoÀ'3g¢©¹_~%ÏI>{àþsþhüôWcÖì9=¯ FŸ‹›o¸ý妩½ÏÒÙgžŽßÜzÞxë-Xk±`áB|0eŠr¶b»svLÙ wN¤';}¡oETm#'Ä6ÛÑäÀˆ‡ ¹Ærz´Ä¡Üß^XÖþ쮌8Žqó¯®ÇCzÏ<ÿÇœÊËÊpÍ/¯Ã¼ù н¡ç:Ã÷Ø£Sß±;|ö€ýñ¿7þ‹/Æ>{ï…;oý-JJ\äù·þëë¸ò§?ȯžŽž=z`ĉ' d-õ|CÏŸ3wî&·Ø¬E‹aÆôé[5°f}œ½Û€ÝpêI'„büê_^§OÇÿüb]ÁcÜ÷ÇâºnĘKÿ ¹\†‚!ƒóGƒ&MÆØqãpçooÙà kmM öýô§7xîç:åee¸î†_cþ‚…h¨¯Ç¨3ÏÀžk…éL|ùUålåìmËÙ#†]Ç +ÄíªtoÅ fùǼçµEr>ÛávÁËéB ³(‘†ð,Ú`ÙÂ&90'Èq+Úì,[= oL@?…p×ÇŒ\.‡i“þ{î³ßV;N.—Ccc#>úè#Ú€€±WŒCîÝqÙ·¿…»î¹7üæ&nàè+#Fàc/C[[~}ó-øÛ³Ïaõš58ìàƒñÝo}3û™£Fヿ„ÿþ¦2ƒÄcÇâŸï¼ƒ?=ò(,X€ößW^ñÔw Çï…çŸÇ AƒÐÐÐЩnkãƒ÷ÞÂà=öBÇyEbûaßÁg¡®²?bS†ˆJQ) ň(†¡ÈÅðBz‘&8ÚÐŽGÒzgƒ&ÂáF@ "À¥`3• mŒ¨ °œCkÒ„¦ÖEøûÌ›õMÙR%wÔhœvê)qÒ‰Ûåùüyó0{öl 4p¾ñmÁÙ ålåìÍçlc%tÝËß!7RúYlfšÒ[I¹–ãzP¼w7 @ÆMÃû¨uö-'®wÅ$Þy„ÄÈÛd${…bãXŸ_oGüx_óM\9îx⑇±s¿~8cÔ¹˜?>~ó«ëñÀ½wcÖì9¸ñæ[ô"+:¤X8;(›±,õj Æ-M§ H^o:ÕâD,„M°Ž°ƒx‘øÅL:\Ôo>g+º2æÌ™ƒyóæaè!µ7T(…ÇÙ&›ïsÛSoVÈ„ž•ЉMþ°’âY¦1ƒ!J˜Ì4îE‡q4Ñ:»@ÁÛèkËÑQ?Þã9ÆE÷†œ{öÙ`fœ{öÙè×·/víß'Ÿp|^j]W¹>ŠÎ…ñ³+œý,¼Y)ËŠ_6ÖË Æ„yròÃân¹ÒȽRBɧ馇å<[)EWÅôéÓ±xÑ" <¥¥%ÂIú¥œ­œ½)œ»áG_Tsøû_ÛŒ½IjÉÇaèI ÃUî’$iÅsÛÙJÁŽb¶í”oý`*¶õãÍbàÀ€ÕkVç=æ"{Ši#é° 1ƒ‰…7ÚèÂ<¹‹ƒ·J¥l/Y ,³N›&BâGk2«}$ˆ%a 6OQt)™ƒS§NÅš5k0xð vûë EqpvLbø—¿C6óɆM(éYîÂü$sHÎqʶ ðñNÄÆr0PåÌEG쩊 asüx©ÝÇô³¨Ø8‚îá—“ YQN ŒEêwælŒØšú™rëúMÃn™‘Ù7ƒ°kÿcá_08Êd.!ñ-‚Š-Æý÷Œß®ÏÏû|Y‹É“'ƒ­ÅÀ»i‘­P9g÷œ€Ü¤e6¡YšùeÊÝR±îODŠgcÙ›÷A§æ¼ÒÅÿpEïWEF±éÈúõv¦¯BÑÑ›4¯t˜0aŽ=`d\ÆÛš‚]H‚ó5BÜ ›d— ¬³@ŽdX7`.Û8Îö34Š®„÷ßI’`—]vÖ"[¡èœûí¢ÖÈi¡L€åÄ€Ýá‚Íé€$e½3}Û®ÇÅ"Æ‚Î{Ñ M†,TlÍûæôksЫW/üááG0oÞ|ÔÕÕ¢¢¢"øñöíÛì·.Z„%nÖÞkÐ{Å´‰!ƒß>kÀÀúþ=ö#ߩ˪%#É"pÊI”qL%ß¹3Œ ”ì=Ÿ’]àvùœE—ÂÊ•+ѯoŸMv¬PR( “³c9¸xþ+ò9EÚ·‡„+í— IDATÞ/;5vwýÖí¹‡lÆ*›a¥ýÄ¥Jj{vA—Ú[yß›¿ÿöüz·•oû¯C?È;Úo–¡pøxÝ@ØÈ€ˆÓü7@ãrÝD¸Ô…Ь¥Wøcd{g¾jIÖµÎîrXݰŸmÏÙ …röærvlà¹ý®|•oÁˆ‚g •ÜfŠïtŒ‘Èd|Ý4%‡m9f°„ÝXIdh_l!¢¼² «V,G·šÚ‚8Ÿk®ÊE(++ï~yí:7u£Î> £Î>«Ý}¬ÝCYZZŠ÷Þ|=ï±Ïî³øÛ_/˜÷aÕŠå(¯¬Òd’¶……¡|×$·)ƒLÙ¸¹pB¾ÜàžGLaÎEd“ KZ3Rû>Gôn¬\¤Øžñá|ì6´·¾1]--͈"³Éjv¡qöŽ ålåìv9;—‘ȺƒZ–twã{®SÏA#'I7‹/º9a¹+“dçT‚Ì`%H¬TdšÓ÷zërWaˆP[[E æéÅØÎX´`jkë5ô Ð~G@~vÝ 2Niã 1|OŸ÷nr ¹¥ê‰K÷¥àÎD°Ìa½Ó­n"bÀ‰ì3²„¯½ð¾¾)]KÇ1Œéx±­œ­œ­(lÎ6NYö¦{. ’¼Á¶˜¡'Ë~¬M¤È& ®‰2ö'’÷_ðË “0n‚‡©«¶¢PŠl"BUM-*»uÃô©“±jÅr½0ÛA™>u2*»uCUMmx_…BÚ™/F&z×-FpýÓQØÞe rK’œF¤óäÄ¡uBÚ˜8f3K&° ÖSn…1Q žyôm}Sºæ/˜òòr”””tèw^9[9[QøœÃ;²Ã=#–|ì=¶mèÔC,9D€%ú¯!MãÎç$‘¹IrźMœjδ¿µÐ`ŒAE¨©ëŽ8*Å¢…ó0kÆGzŒ$I°|ù Ìš=8üð¢¼NŸ|4vMjkkEQ§î»¼²5µ ¨¬®FEê=¦4º—9mÖ#·‚È’YÀle(ǵ ÔXëí·’‰›rLû`6¼õyœ~ÑaúÞ1æÌžU+W¢wïޛ߽-8[¡œ­œ½ùœûIKf©Î‰Rã?ßsâ§5avá¿DÞ%Í)ËönSf~3±L½³}4»¢ÀîüˆBáØ­¶ݺÁÚü¼¤-E.—CåÒ¥Xm‹÷ýïÙwôÙuêëëÇq'ÞyŒqïÿRe¤à~I‚@`˜d¹Ñ§ÝJ«SÛ;œJÔüd~º€Û[äZí(åL7 )ìlPB%H¨7ÿüôÛµ:zo}ŠK–`Ê”)¨©©FUUU‡ímÅÙ ålåìÍçì˜à’Æ|Ê£eãmr¹î!˜¡Ä¶rÂþÞDJûx°8 Öƒ!NÒdÔÞ¯€‹mÿ_îäFú\¡¼¬ åhnnFeeeQ]ŸææfT”W ¼¬ åeeZhûëOD›Ô§©ØvpÇnÉQlŒL3 Íu0yžÌkö‚±u¾0A€)ß.Õ%8ÎdJa¹–s¸â¢ÛpÉFàô‹×7©ˆ0gölL™2ååe¨­uv¥›ºJ¶µ9[¡œ­œ½ùœûÖòr¹ÔÑÄÆ5s7év)¡¼¶™Óy !4>%GúVÄÀ†ÄIíF\M…[lo Â&"”––¢¬¬EWh766¢¬¬¥¥¥())éôÖ…KÛnÚDVõ,\/Ÿ |bÄ…}ª®ÿ}b'^°±Â¿FúʼnI¬¨)ÆIÌH9›@6FIT†EkÒ‚›ñžyô-uò~8ðÐáêFR hiiFã’FÌ_0+W¬@yyPS[‹ÒÒÒÍj=Ð"{ûÿÍT(g·ÇÙ1Kh qjôüDEHMúØõf?o’ì[F|âŽ[§Ô/›¤èNSz|¹bG"c JKKQQQ æcçw.ªk²`Á|TTT„?ˆJ°;ÚïDGɬÈÑZ7^å`@†É5«Éx°’ãWNdÝÂR%غ0"01ȺáDŽ[g›"Ä(*AI ¦}0½ÿ(n¹êÑ4­—©Í“Ÿ¼—sNÜ:%“ïOdi%L`9¥6Ø$E‚Ķaåš…¸íWê¡x5Ž#TWW£¦¦5µµ¨(/ßâwå#…¢°8;öDv RúTœQ·nvŠ4Ù8Ü”3¶ä¦5-œ¡‹ò ø¾–ÔÔÛ”¬uwÚG¶Cþ‘‰ãݺuÃüùó1gölô+’b{s–]èó „¨^àÄG† zIê¨ä "Gˆ6ðªôÐ2\[»g%ÂÅn²]h_ –TÊãlw̘Ë`¢‘)AήFζ‚‘ƒåØš´…/gwƒ#*9ù[€, GRÐ3È0(± Ä%%±~¶@hˆã¥ee¨¬¨@UUU¸q×þ^…¢ëqvl²*3‰-IƸ‘ÀœÀ‡Â[Ø \§Mæ”yEò§ ÔÐY”`F Én¤Ø í’’TUU¡ªª S¦LAEEºw/èóÞ’%E£má±4è‹Ó –(_òI&· ɶÐ*§Dn$ö×w", ŠçH;œM00(A â(FÎ0˜[ásÐ8p6DP‘p² †H_"K¡ÌlsHl+Ó†\ÒŠÒ¨ýû÷×ÁðŸ1%%%ˆã8´Ÿ©S…BÑ59;6ŒÐGÍÌ¢nˆG¶õ¸õÉ퀱°la(‚eß’õqG0€„Óø—`þš¾t£“Ñ;*¢(BEEjkkÑÚÚŠwß}Æ +Xe»3–]ŽgÄøf¦Ö}ÍaOÿ#!j tì–AÙ´1öšŠÁþÿ‚Ñ6ÄÙÆJŒØq¯aXN`…UH–%ÆÀÙ²Œê8;s¦ 3,å`LÃŒ!˜\ ôƒ°…Ŷÿ̨ç²Bѵ9;NˆÝúª?ï ØLðŒeéLaélñ€†C϶óC1r0ß0[×Èé]©íÈ ß§]S[‹$IÐØØˆ©S?ÄüóÑ»Wo4to@EÅö’ÜKŠ®AÛ¨Ôõá9µ’~K)φ„]aPJÙaqÖ^Vz9Œ(.99à ít”³™ ,,"ˆ£ìUðÐÈpm($'N’…À‰k±^Æ ›NwÚQ(Š®ÊÙ1û¬vr¿W¡}•oa@Ö:„ÄE¾ÉÏ&­Ó”w‘Ò½5 Ü”&ÛL¼N¦ãD±ã!Š"T”— ˆ¢+V¬@sS>üðC÷ÚÎÓó[s`IQ¼ !Ö d–}Ÿ!×k› tg¬qÄîC¿dœ&Ìßkݰ’Sà×A~‰°ì!•³ …¢88;vá3¾«ƒÂ #|Žyô ãò³”{ Æf–½­ £àH’²5òTmÅŽúáwC‘•ˆ¥•¤©© Í--h]³¹\ÖÚírn:°¤Ø€8Ï›Æk¾?€È`+³-ŠWÆÛ dÙy´Ê `°k%BÂ&ØJ)”=ÃZJ­œ­P(…ÏÙ±‘¿ ¢Õ3S”¾Ë Ki4¥¯Üáý¶­vû–’àøêÎ6µMX¢°’¶Ûq†ƒ***ËåÐÖÖkívSµu`I±aÞvìf ˆÙ9s¸– ³–"œ–¦V²Ž3­I·'oûáK—8ýÌ 3`È%›)g+ EqpvLÈÖÀ62À‰x3ØúAH‚µ#FÝð'BŒHì]RŽØþ…“—þíÌÒ#³³@ÑaH€àGí[2Ø÷Pmç›XR´+È¿­Ÿ@gRÄDña]ð>®üóˆ—©½–l2©`Ü^-”³ŠÿßÞ·$K’ëÊÁyeöFÚ€&Z†£ýïAª€k8fµæfd›ÝÛ]uN~"NðÏwüfÂÜ,ÊïÏEgîòW¤,K3¾f@Їâö±ç #ÂèìªëïÓ/ûɤ掆T°ßÍËÿ°±½ãŽí<­ÜT >UYN`õjÎ>ö0Ì<[“ÝÊ´ÑàpA~&@úQa5ðböwÜqÇï`öG†$ÙŒz1ýäc/åCÔ‹ƒ­¼|8»~3¯¤ÈlW£ù~õ§Yméô±È÷¼ãŽ;îø)ä®àƒJXLn´ 7ŒöšÁ³}hcÿdQõ` uÀäP6h0ø³RwÙ\BkŸë‹ÙwÜqÇ¿€ÙÓ/)¬ ê 2€¼‰¢öeL/W>‘\ZÔGе( Zo•ßËW[©ÀwÜqÇ¿38‚šbþ±,óGW1”ÄèÅ» æw•žKCá¤õÆ79Ó®´aWÏŸ\̾ãŽ;îø Ìâ^m¶mýpy®–« ½8,¢´Ô¥_Ô|§|^?X_¯“'/^ßqǿٓ½%·Õô[MOj¦Jl‹÷¬`f“åimˆ…“k)à û²d‰x—¯/fßqÇwüfô©bG*ÔkÏ)e´'ktÍŽ³¸§«L5ç»"=_¥¬™åŽ;î¸ãW€Å+˜t‡O/7©¾ª%…y>IºIÏxV¥ø‹škÀ÷†ô‹ÙwÜqÇ¿€ÙŸ(«(5=¦Â‘af„·ÚŠýe¹¶¾ÒdÞÉ[™Ü>í‰LŒÌÈËÝ ½ãŽ;îøÉxYÓèi®G¹u<æ{ÈÅN,Œæ&À3X ÷jOš,úÒQDïá%Rÿ\̾ãŽ;îøÌö¬NT 1Ø;xTø*$Š0i^ÿXuÆ­·ÕjͳâÍŒ)Þ žòbnæwÜqÇï LÇÐ?ƒ´×¦=¹j(6îÔ^ÝÈ·í+©@¦…‰N‚ËFÅñ“ÁëÅì;î¸ãŽ_ÁìˆâŸ¨4FU™weÂØEtÒàj[ç^±”ói<Â^ÓIÁÍÂoqäŽ;îøÁâHñG¢C¸™=éIM$÷¯ª"½™¥¼6)Ý®|ýŽ;îøÕI¡ÕN4_ój**] a2‚ÒÏ’"~ iPíÊyDÒ¦VR"ž‹ÙwÜqÇ?Ù…Dñ½K?cû%ûCéd€|ƒNïÜw´§+Û›0æ÷8¯F‹ïyÇwÜñ ˜mâû¡l¢Âõó)áÍp¡³æù |ÃÌóô´vá-ÍðH«>9täÅì;î¸ãŽŸÁl—‹‰ƒˆVª›Ñ‚¯}BuUF‚´—,_A·“H®˜à4/ F¥ñ0³âÝ|ÇwÜñ[#³ °ÒÁÆ ¤-¡Ìa1µ 2•ïoã©•ÂÝ«8:u¯ ÅŒìö¼~/fßqÇwüfê•Ìhö$Ù¤wâiÒîJ´n¨3ž„FZÈÅ›N§*É $ðí ×ï¸ãŽncÛ¹z ö¢¬\•æ(^`UMÊnïU˜BqifNo·iTú¤2^̾ãŽ;îø Ìþ¸^ÐaÑYî;5,ËáYj‡9¼8.ìR¼3J™É³‡< ݆ËÓ§ V”ÙIJ¿ãŽ;îø™ÊHaæþ÷&–_‡*Äðƒç—åèì#L$ÂÔ{lzˆ¬ü¼ÒÅÊ˵ÞéböwÜqÇ`ö'u˜(‹’"‚Ór4ëâhÏ@Z”ÚRg¯üø‰¸TåÄ1-K*žŒ·LrÇwüÞÀ ¶y”[˜]‹ ÞÍî$RÄ(T¶òk]WÕR^äfÙ"ãÖűN¾˜}ÇwÜñ+˜ýG%íH¼¹*iÒo²Ý‹µ‚áô©N2žQJÌ*žƒ†2-MçÜâÈwÜñ‹ m¬ ‰¡\X½©-%¤ÚŒÑø‡sýä$:vÂü© /fßqÇwüf ^=N«Dä/­7 •͉zãÚëóIe&a^o•‚LT²˜'ˆë ÷Û§;î¸ãŽß²‚zjSk,<ƒÒÁ“©c,OêÖÆF“þ­!j`ULj\\?UEÚYïböwÜqÇÏ`öeÞM²~¹hà°,˜¯ªZ‰ž•”æó•/á[ u•[¾Þý¡’ô÷îßqÇ?YÑH®´!Åê«iÛkU›Üí­-r&1&í㬔”iÆ×HñMD!ñÅì;î¸ãŽŸÀìf1ðøÉØI¾ âæùÅãS]dˆå,oÂi=ÂvRez7,)gôzNˆBú¿ÂÀ?³ï¸ãŽ;~³?X sé;•é0ði€Ö_íʕݛÆÞ¬O!&ŒxƒìߨÖ#{÷/«•;î¸ãŽ_!QŒÚŒ½ U„ FVä¹Ôí\T‹’SLi>u¾®Û’çô?³ï¸ãŽ;~³?bxGW6º9»öâµ›¯ì”,&<Íéõ9£wÿGR¢lTvrðí;î¸ã‹$¨t”pfÚŽ’Rl 3¦&­ƒµ'Y¶}ŠTïWJ¢áÅì;î¸ãŽŸÁlÇÔ?êÿQÖ%^oþš“µaÏ41S´$Òw5X¹ðX1ÀζšJ5|Šu´Ë'Ü^à&ÝqÇ¿†Ö†@Çž§G ‰Œ)ð&Ú=æñ1·§ñÎËaíÛª* Y®!¾*ÊA{H»˜}ÇwÜñ;˜í-¤±ôgþÕvôÚÞwZN6+¥ «"‹ÏE;ýLÔ±jƒHó(‘ÜqÇwüÄðŠ?G&("¦|0ÁÔn,˜ r6®ú?OðÄjc3¾ᆰn]š°øböwÜqÇÏ`ö'l“»9©¤`¨z8=Áõ¿ª¯ËÅÌf'_¼¿ B°²RAWPò‹s•çï¸ãŽ;~§<šÁa0Oè,¡¢A¬íž3ztµx¸Ò–Xɬ”Pø[êÞ—¨Èu\̾ãŽ;îøÌþˆå·¡3Ëé{ ¯ªˆYÀW‚h+X…íòuz@0Tš뤰O wÜqÇ?ÛU1¶ö›ËZñcï¹1¹ª+ë…m7•õ‡’.fNcÞ&th¿|1ûŽ;î¸ã'0ûýAqÿX5tZšD9Ì‚a^"UH‰zq7Fý;ÌÙ£*_’αmX 诂ýŽ;îø¥•6‰ò\Mk½¶nÑ3,ÔE¤Âm“¹„5Tµ [WÕ:¬”³ï¸ãŽ;~³?J°ñ°å,(;¨0Œˆâÿ¡Òsœ´×Tü€§ñàó˜šIÑÍêËÝäwÜñkcÙB…ž |!’–Qöyn°—•.沉ê—(7šó©* òg) )´ã‡UÛSâ‹ÙwÜqÇ¿ÙΪT4ïÄÐ.RYÁ`ïÏó-ßtnm®V®{•â¥\¯˜Ë]zßňŒ~ÇwÜñ3˜M³åe­ŠÆ ûP‰…‹a î»%éÌj Šºam3eÕ’tIwB!³ï¸ãŽ;~³?¬œ°ŒÂ™x¡k%†•=ÌK SÊwíÞÑer%|ö*mÇËÛ•~ûŽ;îøÁQÕ‹RÔ˜Œi E·h‡R¸SDqýÒÛÚ1›_mx»± š›gWèÔÆ‹ÙwÜqÇ¿ƒÙŸl+²Ûƒkßoff/ôâULÒXmñY惪~°¿ .u;,ý…IÎßqÇwüÈpÙ?©â¹±uª¢±œ@ÌM!è;-,š_me™—-LŠ+ˆ©N‹’Ì a€Oü¤™YxGY>föØÕ]¹e‹Ûú|R»_¾ßwÜñK˜íK™ÎòZìµâLÃÍÌSéÞÕa/;ŒŽ1ºÔïfäcÁ§DˆYQÞ2‹â2m½˜}ÇwÜñ˜ýÑqN#ò¡´šèÆcè¿Á΋WY„œ$L_–) ƒÃ9cNô; î¸ã޳átº¹=æö1]ñm'¥3ãM«€™´úéefp¯:ZÁ¾<@.fßqÇwüË1ûã(ysU`áf/õâ®Ð°çRŸ›…K­nY’¯9:IMqƒ…¹Y¼öDÖR¤Î¼ãŽ;îø…áðÜ€fxLâÃnÑ¡¹Æ-VlÕVLn_x…ÅD¹‡˜Ð=Ñ68#Žÿ{1ûŽ;î¸ãG0û“-È4Ú†|RiÍ3QO Ø¥²´JÁ©¨÷²8Q;³Jç™Eª8É:9xÕO öØÿúŸÿÛÂþXðµà›œ@FyÁZ[QA‹ÀQÑÑ+[‘/Û«©ýpkº€3DG,Ö!ñWÀð¸ÑžÒ#òÁ²¯ù²Å²¿þ¸«ec”¼ê+ûm¾qö1ꊕ“Í‘jûúØú®/¢{<2«ä{~ý9øõþá[r­ÜýÙ÷²Ïõ~fCÅ_'Åï‹ùÿ¹´Ç¯ãøÖû÷úŽ?µãOþé5×veýÆú>âo­?'æýŒvxCïÞsvDnýKœy+”ëÄömIÇm¬oT£ü÷ç}×ctÜ>³¿þn~ç¼<ßb~¶^¬§íŸçus‡ÏçèÛ¶z®s·þÉÛç3‰ïu¿­>´*e×ÿÀÍñ˜ãSÿþs>EÉnÞŽ'W΋º‘l¬iþ…3õÚà—Gv}Ƌٳ/f_̾˜ý;˜ýQV˜J Ì«ô[øÂån Àì¸ñ­Ò„[à=TÐB áÊþûý þ ûcäk4ã›ÿnoq˜-y€ €ä$Öwsz.H+ˆ–ùôè$ ôŒåâܽLʹ°9ÔZ|T×ó ¬\¢[ºšHñ¸€¨vEs´#=ûž¾x‘ì˪†ißXš„ÝÎЄ\˜ÊSÑp<‹yŸV „²›&‹ÏÕŸï‚ JüZ61“YWj ±Ò§ »¥•µÔpÕv¨¸@X×q¬Î¸–z¯“õ0kÁWµ÷9ßÿ°ˆ8ŸA׉<øµðxtæ›zñd£íØÀâÙŸ"ÃGð×2àǵßï;›²xÃZ‡¿>a º=æ_«AÏLü÷€{½Àòo>œ®¾–ÑÏ” 9Î7"ÖåGµùÖÆÿ^íkƒ³ÿ\Œ ÔïÃÜ0·'«ø˜ûcþ[VH ÙèM0zÞW7ýî 0ÿ¸Èç'5{×Ü_éböÅì‹Ù³/fÿf$„‰¨ Q&XÞ*wÔ .ÈU§€E”ˆÝh¯EÜi•B¯Ø_ÀžíG2¦ŒÑàVÒ!=Xùþõf}2››O7{ŒÇII 6§ñ»Ñ ö¬Är°2, '6$íÓ¨M6§ã¿®Ô>ó Zaæì‡ìÙg\LÍA§^Ç×:Z` ËkÙ3»A›s½jö“ôUÛ@^àGïimÇx‹ ,ò~)^ºæDp›¼U0ýyáƒÀ*´¿©9·––^Èê÷]@Û '¶À ˨+[4{‚ˆsîyϺ?ç‘ÿÉ0é}™y]}®{æÄ_¥½´¨k©? üg=O}-æ`Rl9dôµjdLœñNGÐÖón›þ@y–Î<â PÕäïÍ5/¿+k£²ßå‚Ç^Œgׯ{š2ñÜ Ð=ÅéVóÍÝÂ^3 ¡dm@ªÒëØ•À¸E´^«CiêÏdCFû\̾˜}1ûböÅìÂlꜚg²pödK°‘Š áQhn“ìQt#& ÞW;ðÏœ©Q¥ý*D«>ÿXT pè Ñ'[¬$¶™€Š¨1eûþßèÓ»Z1Tê§9&’ÓA ²Ö‘±}ÉpMFÀo|ê¶¢õih7Âæ÷9ÿ½ZpÇ¡Î倞q4ÙlNY è¼nrìÉ­( ¹ [ÐS-ÐeÍ6±Q-[¯±[ŸS]Ø\A×ÊÂUbÀw;õ:·ðU­ÙÍ¿žGåo©ÓçZè©ïWÛŠÉg5CÇ­¡5bvV,xTrQáãºë †˜M@c…Ïñ_MpØß-¼U<ÍØØªému}ß·þÃWÁuZ7–¹Drïqvk0„O5«Uê@µÒ±šºôic»µG©ZoV!'úªîõì¿5'@{äkª¹Ñ¡v£ •àÞt-=·oérÕ@͘×sañò¬SŒ¹ždµÿhì땟û1ÂíÁS–yùÿ¹©,¥:’¹œ—ÂÛNo·óu¿ŸY¯ïŒ³­…Žë÷j’rU:/f_̾˜}1ûbö¿³?(nKp˜FoÝLµ£gEž4U>÷Í«3 ”ÐÞÈ‹ëºÉõ{(ó“°×s{Í-ðX˜›ûkް`4¨42×ÍR …G`´Q\Ãu*Ú“i@‡ÓFrë6lÚ½D=ª©¼wV…F Ä}Š/á»ÃW­/=öÞÕ¦ášý­TJd¨ø2Â¥šðêœ9¿8g`/V”Ue<¨/ݨÍç[‰ÐÂ]Œé&×÷r|¦ÎpVË¢*6j·¤Í—oø^ôÕê}Öº+^Ú¤,墚íÆõóô—ÑNŸ.£[Å… ´ÝÞÌçÿÉ­ IDAT¨¦ØjßY{U]1ËVÓóÂHá¨6@ª*WMiÕVoŸË)Â̬{»Úx<—>÷¹¶8 ^—(p,‡¹¹YÕ(&׬±çCúâ¾h™¾£K’w;«OúÌ­ö®.Ìz ­G~jîswÝk“·7Y5S Qâ”Í÷­¢©×³ãUÕ¢­Ífã÷’º™ç¦| þä»/à ó™¶*0‹d¤‡õ–T^z†Ã4}#ŽJ§Öxù[4„ÛÅì‹Ù³/f_ÌþÌþ «]°ŽˆýHx·ˆX ×§{…`Uö|D}iÅ…¹=íãJŽÂ=§Õcí9bØ-",eg7C‰E¤‡áY•„E…Z>1`àÙ–Ìââ¨ÖGÕBiqKó¶Ö#©ÏFž„.ÔS‚åU»Nâ RQ=(œÄzU|ó9“#¸ù7«‹^”TE ,Õ€>qv†Nb\5±ê$¨“&aéY|·{ø¹TÙâTþ¥Í)XϾ9oÝ'ŸÏ¹„Iïz€giÁÊÂã!Šù.MxÍé‡Ù4¬¦P¾šwkÎ-’geD•…U%‹©#v‹ø=à×TÃéJ×nnª­Jè™Y·ÙOõ¦f!U\`_õ›ž£i©öéÖ|Í|èv·Ïs=/µ9ž¤Þ÷Ùg¡ò3‚=ÜvŒó/Ð$X\V›g´·ž!ß‚'ç?+r`])ÉMg‚1ŽÅt/ˆyÏÝÜÜUÓfT íMugQâÁ™=¶hFh.¬Ê µÀG?tYÙ,­gU~ã÷böÅì‹Ù³/fÿf¢90Õ>ê4M½YvQRvGO¿èJB Fg)Œ 4×G­¹ ú ë ÀøDÙFå âe>¤^ß2¤„ïSPNy+.a¶¤Ä)¤Y<ýù½ 6æø Ú{A)€)ŒˆFÜÝhÚ»ˆ;:E¿6ÊŠ5o„-íµ¸hOÜúé™0ÍaÂQÀŒïÙo›cº·Q¨cq ‰¬Z~û„›§e]ӃݢÍt¸jiêN D~¯¶Ë^_–úÕ¶ÑÔêì]}ÁŠ‹6VËgÞt9*p]G/»ùU G·Üœ+µï`³ðj9GU¢8|ò‘ tØØ2Lé@×O-;²õ)zÙUS¸[¥ÚT¨ç#D£Õ<®,FšDÛ \ÇS•JšÙSÇþ§Ú O]S&Øz‰¼>‘¯í{£%)ðŒUECKXH|¢¶æŠ_7lXÎfÊž™UmÄëµÔ<éŠO‘Ì&ÔâÖ`Y+A¬*CV¹¼ªfvˆîpHõÖ¼¬káxz{/.©©:¢0ƒ]¡â8dhã´Y»A½Dü5Áwнì^̾˜}1ûböÅìßÁìK`GóŒúQe^_d÷h¥6»%&¹4yR÷áÁE¶ŸDµ¨œVÞ†nư? ¹#ËùõyòDìÛÞ©ÚX§øÁû,O=uÓ’_ô´½•Ú¢ù/Ñ(îuoÐV$1}zŒPï‡nä§TµS…`ML¸Ôß…àô檺°T)õ¯¿×IÙ}Ô¯\xuÙfµhE:¶Ê^‚†üïð˜vÓâ?=æ"U‹1T¨'%ªòó¬qEŽ2Û}X×§'oÛ›)\ ÐækO5‹9ü£Ç¹Úë£G7¤I¼ÐœúÔZËbܤšO¥pă¶ÆBɱPJswK%‰{ø,ðîs,Î=Ÿ‡}òÿT>V€[‹”ZËνnwæLÍôT…rá¢çæÊ1­KHx†È¿óU¡,1Ô>Ç;|]ìf,gcôû=UOSmB§Ý[”³ÃccnöØcf«9²Ep%¬#Åós|úûaªÌ–ólzl½o-ÄËgBB¹¤ D‹‡TÊZؽڋO9_dUD …7^4‹ü  Í\Á1KH‹ŒP§·p©…IûûV%íböÅì‹Ù³/fÿf|Y¯Ð17Z--ÔÝ-±zß(®`7±ìN$S˜¥1YÊw¾ùhøSØö0OKæ^Êe¶|*1hq•EZÕŒåI)¥4pú„ÎÉ)úhâæøc¾¤ÙÄß““·Å£”O«¨štU5éß·b˜ÑØŒ:õGª ¯Z2U¡‚QʆÈb«,üT|sq™¸,—tb ؈uŠÅVF+ðB´Xþ“ÕšÕ£|¨RÞ6ƒo†YÍú¸$÷j·‰¼+Z†·Ÿ8/jà–2é ÿôýY^¹¾dî03.Ï`µ}ÛIDζA+°rz'JE‰±ˆñïT… ”9ïØZˆTed?äÐÆ…l@ˆZ@ú›¯Å[$SmÛ°.‚²0jðŒ(Êsc¶¡‚!°Lji†OÞ×]ájŸiUê'šj©•ß²cµÙíâÜìëŒL2t½j£Ç P[šŽ¡Âç"ù '.øÛÀ5;3¢_¡ªø›ìøˆ–Ð=ÑâÐ.K7ȃ•˺j6m2‹ 59¬Ó=ÁˆZ8ÊbaÿÑfôböÅì‹Ù³/fÿë1ûã‡@!º5jèX-¡¼À:/¢58O¶Ô:}öfÞÜè5IlNêPy_þ„.Eýâ,ÁЏž3$[D>|@z´—"¿˜_С^ŠZ«æ?ùgG_jË;•aže%•GVr´ÞaM¥ZV-›R£2«6¿YGV þt%‡“!€lëÄ|£ÃbG\³O=Q €<#UÐï?ô>¥<Å«’Ò m÷²¼ÉIërõg±ÞW¼9Ôýxºý;Šz4¡©5ïe~ôäIµyƒÜ,Ò:½æÃj5÷ø°UËS©ÓS}þ>ÝW´´¼CŸj#éìì˜jZ|QhŸÇ(Á•õ }B%Š¥õ¸ ƒN›o 5XV ­ZèyüÆ ÁaÙf_~¡Ál/Š/‹®” ÌUÅ£ç|€Ø»lUF¿Ô¬ÅŬËè]‡T»¼ñH¹œ¡ìâÜÛ¸Œ«5kÝG÷ÅE)õú™á(’Ây‰Ûª"ÖÏoØ'I„ÍÓ{Íð…Ä=ôÙxb|¤Yé`¬ÊF},¤PÜV_6mâ­úT­X $ù}³à¦ˆ/Ÿÿ-ÈèÍO;¸™ÅÛï‡z?_›À‹Ù³/f_̾˜ýïÇìO«k·y}X :·Un1B95­Î´‚±iÝÀNOØŠ fÞtÖ)I<¨ç›ö.ŸÒÅ)’ F÷桸i¨öºˆ€ÃKÊàu³çßV6‰…!œ´ùáHÕÿЇmï‡=ŠwÄ•äîe¾Ž•|¤±®Óî3zñèÿódoXmNUÁ†±Yž¯T3œÄÀNwJ­½Ý/} ‹X–_;…-—x„/G4yn·-YœJoŽÜ$U­jCY éÁVÅÇe€"l2•¸[†0¯VݳAˆ8c±PÁ*thÁ6È/qš* ÖËW"Á®`=ÅÝQ^ V¬56>¹,²qù{õºž“º±X2 •ËjV0¶ýR‘ ñtb¸~õp©èôn‡–&0Ib,¤¦dö°ótÔÃÛ*EOŠÎ†Ñ<ÇÀĈ¦® 4ÿråäŠO¶^ë–ÍM7JºYæò8Å9yr²~ ÄÆÒ'o·!ŒB_ÖAj}Ž fZŸ.Õ8|£& w»Ù»÷ÔB6÷±ÔÄjXëºd•!_/ýqß®f ÚÎÍó[éU:íêLŒÓQ\ÇØùÓÖK%›w‘Èl7vQ‡õ“·oî“Í$<Æ‚9ýØbt]Ž"ïÊã«Ê’Uë°xgQ-Z‰Jä?m74JøP%hY]=bëÊ‹v¨ùQ‹Ûõ¸Ä>†Ð3‰W«…²€ª.b‰_lªKiïÅÿ{±'J좸‹9³žn3æìjÝW3[—¶|J¶C¶¸ßrÈpËÖ±©UßY ǰk¹->s{WAæw^¡/‘…¾[<8ÏT{÷“…SxQÏ*V(HóK°…Ú¨ œU°1]̾˜}1ûböÅìßÁìùYmŽBȉ"€àRübN¿4®ØØu¢õT¬§q¨—Ø´\”¸‡€Ÿf©…ž ßÉY‚àýåÒŠÍÃr©åa3Á˺& m¬É‹•B†i—´è¤8 a•¤Kº½*ÕºÁ2™Ǿ¾šý¸æ?^ŠlU—”è6ÖV8ÒÈÔBc·{Ñv¦ö%›jW/nØÛ­FÖ‚ œWjõ‰aîS%j¡Êá㹌{ªŠ¤vuÀìó EB”Ô½ÛžåíêcjŸà€þ­ö7ƒü¼ONl` ,Ár [«e!õxŠwˆU-ô==Öâ¨ËˆraÏóóÛ±®^o¯c¯ö{«²(i3¤ð\ Ÿ‹Yñ‹±jk+3Y&æ1 ¨UûL‹ò¶ ³áÔ5,¾!±—,T‡›,žòâ-‡‹Õʯ’Wqðäú€["î5ÿ™I ˜ J/öŵs©ÓQU5L¦ÞÉ1(;x¢“tøQyVDkÁVÜKU,Õæíe9T}Ï÷Ò¿½èg¨ycÌþôænhâ ¶÷´,¼0–f³/f_̾˜}1ûw0;©#Á&Ûï3|8Íø|zHÊò†KIº9rmü®Àƒ²šñÀLN«a÷½ÀQˆ>ûg4º“€ëä‰:©9llnB™ßÉOO½¾u›)ô»mJjóÖVÜûzÄ#2q¼š¿ç+öõµ§¬‹¤jU˳ãm÷d[‚áXçvÔ5G2X'¥å£þ¶Å—*$K}Üñ ì(Q=<Ô‚FÎ÷%ð>) tt?ÉÓ…6 v' ®‡~µ~­øOâÆ-®žm«¬=WòÌí£³oU¯25œ”0pì´$ÈɃ>Y›qÕ×ɵ8\Tõž~0'ˆ¡–1—¾/f±•²š‹ñhk1UbZèM]–A´ðLc¸ª)(Aº6W.N]ýN0&"y%ÈM[{&HÅm×<‰ß$mÑ-ˆ¯J_OëÊŠ€[‹Õƒf#­{ͯl«ÇÄI7pç<}:ûÍfÎa?]^‚š©Fqí¸²Õþ¶7´b´WæXœ hIˆdRU/æÆµyŸÙžvLÍ_¶Äzžf-ò™!£?çÅì‹Ù³/f_Ìþ Ìþ<ÌнÚw:‰Yµ ž²vzõöå_ªò}vWL¥sûæÙsnØl¬ñ~íQÞ¯˜X^´²´º‹föV’)â};ø ­¹‰+Êöû¤Èa9=ž{$Y ªZRV3œ˜%rÅå¶R½^«ŽTŸY¾´Ám' ÄPG–O¦YÀÛ~è_«¶á«_Šg Ë+÷‡´·î©?É]{eª^\²?Èü·§šAýBXΕHiâf5Ò<ÿ1øR†/áPZ„ñhuæ> „'X²âá,ëÞÕt”ìzjT÷åÞZ¥/c7/‚w«ü-m~ ÈÞ^Lѯë»VCvTôÛ‡äl?Rí$µw9¢ç²ß_-ÛO—cØU¬·’Ìp$¬Ml°·È¦Þ¨Xë £pFÍ 7e©)9Ð[Æ”L®°“µq[› sëWÃv®Ø¿ rh“ t3ʵ@s7v8bmz&¦wRíV5JB2gW£îyonš§Œ ÓÀÚ$É2¡^\Øï°‹mY°ã,ˬ°“î›×UœÌ ”ìláŽø×“”8 FníÅì‹Ù³/f_Ìþ÷cöGàâô‘Ë–‘6L;JâJ=m&#LKÊiŽAe»À‡±#S7ø°œk(±Mäõy‡W3'DB¸”²;ùë¯x)½Òþ´ÁÿJìâªvLºÚn_XÿÖB¤“‡ ùìä¢ÓXùHÖQ¼«‘³ª"ØrÕ·i Ù²ôâ²rç°:ðÃÇäˆ!ÝþZRªù€Ûj}*ò䊢SÚl§·¥,Jp`Gž¾=Ý&å\}[ùa/ÙßAa;ú–ØÖ[ÿœ7Ư:ÚTZ¬ìï4ây²«?ZJ0ÓÜQ¦ý4¯ª^´ø"êBW*wpóù–m›ÍËæR­fÚ°I\Qì×·î·PΖ(¹ª%6:6ÅW]™ 6¸°KÌB ^ú`UôöžÚ“-~¯­?q|»Â…GË·ãqw f˜k„!%èŒ8.1žØ¢Ó(Îë:±\®X~ȶ®­6«,á–8Ô²½“/ü]̾˜}1ûböÅìßÁìOk—ø©š„¡“¨—xE'é´ym56ï«ø~uç6H5ËJÜ$–ò×’ÖÖ*³ °[;:u O^Æø1qºjñ5WqÌ{lµk¸*)PÒÖ^8¾TäFY+a‚€ÕZ+µpÝrYIn J ë3ÉV»•‰™ðŒQį3r¬vYú9F‹H<ê¤ìÑíçLÙcrlWr˜/7U6Øêãë‰[&Ì5iß]¬Ö[%,J”9½"¢»y·ì¥: Îcî³ÁX–GØ ë,ÚèA°¥Rn¸oD V€”jÎùâ…±[Úã?<–X™Fö%ŸZâ«S+²Ëù>X‹wó 1I}nhA ‰i7ú<Ý$•šx{mÝ´„m´Ãíaݯx¶^݆f`g8ÃÞÜÙZ0ÚW®+ ¹2FXY–M+Ô(7²H  tùXönµ±òq=eŒIœÖUÕ$¢kÌA!àl^³^š‚¡†[óL£ F˜´8‹eÆ}ÏouZ¬\.Çâr¢ñ¾){Ý¿˜}1ûböÅì‹Ù¿€ÙŸð!ª;%þ°ö—tœ§ÈV™êB TW%"¨X$–%S èìÓ‚D\ï„¶ÿÏ6”·PB‰;:•ÇN–æ§_Kˆ{·¦š¾6Ç1c­& ȦM8B\)`«`àRSOk–؃Œ1M.ÝÓ~“úýG‘­ÝlÞ[?<1é_[U¿ZÉûÆÇB—²Lk)¯ãµwNs! ”ƒkq{ncMÅm25¯Õ lʪî/bÁØq¶¯@+j~¬+ Q–I¾NàÁÉ‘Úó£MjKAnË+tûLH6mͱmÚ‹Àâ«•-VB™c‚BÄ…³Nëª &+þfÎêÕ"¾ÚƒÝzTzžªžâÖ-ˆ(•:&ñwüCk1WU«ŠÁí`aKœ! J-{zƒ“¼zŽºŸ;Kt†ñ†Í=”/áõœwøÃ;‘Ò²ïÂrCî¨\)õY 0&:<–š\k`d;ñcÖWµ¹Uºòzöˆwb¹Ã×2–<‡Ú+u"£3uöÎä7²ÒAöu ©è/f_̾˜}1ûbö¿³?Ífápîš[_m¿>µWRÏ[\(õ [-ì\ W‰HÛG•}z_ Ä©«øÏ5 u*¦'…'ƒ¼ÿl´ý¹N¹J¼¢:Õè†oÊi¹°?ãˆG\‹ÈA |qã½µ?Õ«øT_B _|Aöµ·eócX§â²|Š>t¢*(+è+WKòõ$;ñ¬=xW»§}rmBèè¶Ïôc†ßÔ';cµ×jÒ“]t Íï†äêLí èë$[ʤi)šÐxx~²žzUÂQ;Ôì°Ú£"_æu6ððÓÝznçt²OÜ™¾5ÐaslWU.z1žSðÎÓÂ[­ø¿èdµ€.õ÷ïjã+?Qâ™¶<ç¬TбõÖÅUeûŽbyðZ{Œj¾—™Ñ¤bUœê{Eý2ö†H\â'c­”kC]©x´"«=·¯¦T¬p0vJ®!há˲-–—sWrØ­ÓbûÖwy[UŽöŸV¬t4ýÂù˜ñ]<Þ Cl—¡ Še·õ¸÷ýèJ-ÏX•ѧ4÷½Y»˜}1ûböÅì‹ÙÿzÌþôÉœÊ}_IsX 3-'*Q‰Ë žo·kÔct®–Y—ÿcðƒwU¦JÁ> ?CÊ“ÞâŒqµ4óÌ/7y÷‹Ëœ$ùV}O 5X)ašÄ-Ä¡½€°¢9YG%·I¦â0qú_ ‡aeµZËò'8ü ubNžß, ý:5õÂû¶("Žû¸ÁTú›[WÀ-bÂ8Ís¼^­°â»¯6an‹“æ è0-¦2Òe‰´úžÅ2ôç®D,±ÌF‹žU4p­n ªôýŸrˆ¿Z˜â ¥+(vc]ı‡êx¿ÊöHÖw[SM”¥¼L¹ûóèÊ—gh&ÕE‡hÊd˜_µú%ó":~ eË$ÏNJîMÊŽ<®Í@œ×úhé9âT1|Q–/ÿø ~]Óñ†µÅ»;õÛL•IB°gebW¬ÛˆS5oR-sØá¹œÏDVŸŽ+ûú‹OêmåôxÚré»G;I”…Wm§m½pr-dX­c³è:9vR±‰´rÆ@cÜÐ Ëg{.f_̾˜}1ûböÏ`öçã˜öÀŠ¿ð™BF ÐË|Ô­ù›™E|åÛ³«›Ó>-gf”àR[}I‘ÖÉÅ5³iËé¡§Å/`ÚCŒCØ¢£‘/a ®Ö’à ú”¦CgŸÌ1qe²€ò¶`»Çn'Ñ9Ûu[îµËWÒF4ÁnB-ýòR©Ôo½Ëþl§ ˨>ÛìxØÀ(ŒG°Ã3{ª*Š7ž[¹c_7ç+¿ó»D¹ØƒÌžU²§C6ß«…Ó-œ÷“fW΢S®†‡5±Ò [ë’÷)Ú&°jÔÙ‡Ê|k¿TÕ¹ÀF‰Ò4¥- ¦àr|°Q–cE#â°m!ÆQT/dÈwêTànyÍ>ß¼2IG {Z){´^¼{“Ó‚ÌU9k½¨o%;×üIš÷óJ¨lE8˜g<¢ gSÁXîçKZº æ‡ö¨ŠÚB>¬gKØ6+”¯ªÕ™|u%êi¾.oyÑ)VÉqïöë¡3¾Üšã@4t ]̾˜}1ûböÅìÂìç©ÊFÐÞxÓX?Æïq”<Ä7¡Ç¸y|ÌŽ2–ûÁ<寪X¼2[¤\¢83h%é<Áv¤›m¾›c3qØç0$ÖÉ*Áœ¤ £ûìÔ(Ê[g¥€QÑ´cá²'’¬'L¥,åpE<`r§œCú·±Ñ-°}6É];X€‚ -1òJÙš3®Ùâ-µýTÖâÁoßœå(ÀQSGMÚWµyâ÷¥ŽyùŒÌXÊÔGDµ« ™uÊTVž/cdë”Ú5',«ðµ8Ø_B"¬¨áá—Yù¬rt.áÔkýë>¦ØÈüwÅ8út+½oÑ ƒFW}póU§tÐ`Ó»°nƺ-höø§$ÒÕM_Êk+å{Vì©Ís¯j*zó×-ÛIÙ=g,O»¨í61µ±JÉ—à«„91 ]'â© ¬6ö¡ Ÿï¥¢ :Õ/+p/³jÓ9qÅ=°†ÙëJ<·½V»ÚöX;…hã9€]|Ñ…KcfaÏã³/f_̾˜}1ûG0û/ÃðŽuT>ø>ü, †Ú…ÕºlïÊR’JMõª‚ñxqØ8§Y_d~ÖéÈímÕ|? \“['º ™?é­™W¶'Þƒ³=z°êä-"»¬‰b-Lu-¢¢Zu &ì³*KšÜ±¼Ll›)E„ª•ª6Äáëk°Ú7[ÎÜí7éb½Â ¢ Ý—ŽM‚÷a¾…9oûîÒíðTuš…§o«/‘OÚoaø ÑwG1ePÝ¢ÿ 3©½æN Ò»tµ§Q eS*•/¿PzWºµ{¨ÅwµçJµüYó_¾ªJÔc{›òàî‰oÕNgd"kÞçç«d¦ù¹ ³Zd`u©›ó1Wlv,ÛÓèR”>µÀ¯Ý±!Þæ²­´ÆnÍpíÊ…â¢Û‰c>›¢SÍcÂ¥Å_sÝ|Eÿ²ÅYŠ€˜xknTQB%Ï»ûìj£ëû©R¸,Ù|*-ï"».¯ÅCÑÊÄl¶$šÚmsx1ŽÊ:5`Ãã,€G°žÂ@›îuÎw¸•eu§–n‹­dËWŸãböÅì‹Ù³/fÿfô!OÆ6Íì ãkõe¦MÑâ„NÈAë"йö(E&¢"<}Û†65ÝXYQgL¦Õ­Y>‡U»÷>ÆJ— •@[èåͪɷb6›;µj,VÛ´ÅošÏ(sürúÔdQp³+D«¨–+Æ.Ê öªJ²8s£·ÃK²»ž!v0µ úê§q*<¸d°ªüÄÄ'gëi€i‘! «í•@˼jª' z?I° JPЋgøšq|Fç:Éø·¿'u.ˆ)^é\5_9"•ÝFËJW˜—ò½ÝÚMa^A rqX@¹À¸OϰT<¥1eݵ¢} :6¿qùk°¼[Ê4¶­u/—‡ü~ÏxûB~Z.ÉL×büØþ 8Úö:¿/ï0Òèo7¢ðUÁÒl!Íì™ Í#ÿWDý™üËÇ¢.0Ö3õÄÖ¤·‡²Oë«&'ñu9މÎm†j‘ZÙTµËÂNšc|MaGhN_(¾wåæy]£Ñ ÕuwyïŠcºc®/f_̾˜}1ûbö¯`ö놥`}2EŠoŠ ‚Ãòò4Dd€IDATj ¸MKñ¥U›kì”Þò%E²ßÍñZ•–×£ò¥sÈ À³Òˆ˜>Þy´eO«´m'rmÿâ³:´8`‹½4m´j×ô-E´Çf·ô*| À¨S›¯ÛÉãÏÚí\ÿ:óJc‰|LÕWî|M¸NJjŸÙ<GyÝ¿Ô8„ÖvU]Õé6¸÷IQœ7_XIŒãwj6U9ñ1G¹ýåOœñ{{Çæè$eaÅ ½è»ÙªÖœM¯ª—=*fj4Dj£W0QÓ$Z¼Á®@ØÙ6Õ`•FÏVYU0Ý¢[}^UO"êÏsB íšÚª«SþÇÏØ¼á䮉ë‡Ã9 ª•g Î-޳©Ò8£>ú–11×@x„<õ¹Þ£ø!Þg^@´0¶µ“îZT•B ÞÅÖ·™ýaWÅÅ—m–Þ?²Ú«mh=½Œ ÈØˆ‰W8)‹±læ.f_̾˜}1ûböï`öçxÐ{®gíóäd{965ü N°åÔìÛÕÂóV£º­ GþuÓÇ×òß]>‘XÒ†7jÓšÃ(è[BÃ!¬c é‰ÉóT– ° ýi§½6¬1Ù[v[R´û×:q sÓ&uÊÓ,cñóýLÚ}»*m!}G7·ÅyXïXÝ—EU(F„@Œñ<¶"«ÅLQ€Å'ÛgïèJÄö}gêïôN|GgõÆÂ¶ûgÏCrÕÞV¬jÎJãÊzóšvðæ°cù±®÷y¬ŠÏNãÒÂ釰U¤¯z¡ýšµIåt|ñä8FrEd¨*±SÙVXA®¹ƒe·µù¡<ž ØØOlñýàó£ß¤ÇâlN€—×m7ÝÚ½¢ zÛ‚k[/ñ†›ù³øv™¬$²ý,qÍ" PžÆã)=çRÅÏ&ç°*a…©ØQQÁV÷ËO™[Pv1ûböÅì‹Ù³ÿí˜ý1ÊÜp¹ÉÀ³7þ¨áƒâ¾ûG\j·ÄÔDTË$lÙ¼W¼§-#v§ÖíÚ%{›¤¤¥t¥Æ‡Ã‡‰ýeæûħ ±m•4Ú”1¥—-d³„¥/÷R…ïØ6Öõ\"ö\l»";Ò¦8‹‚==y¥òÝ>ž#ıVùOœ.§½ÅTÀ²Z8£:_m&Dß{ùJª£¶µ+=­yZ~ÈúDª +=ë;|b=*Ó„Uhvç¡> M«êN¬ï±»Xgßoþ<΢ïò Æ‘pþC2ôZ’§#Y~¾ª(©å5AÃéì˜èv‰(>î±s89¡´äiŠ4ÚFV…ì'û«â¶#gÇ%€‡Oêö0°Å£KMœ ]ZCb³Õêe·Ë+w%| ÄÀ8äí´åza\ fÔ¢Ç3.Ü,¹¬O½q˜ªžqF™Ër¬žWÇꤻåòµUÉ,÷÷^",‰™$6ÓN[aÔ,Ö.ÿ\̾˜}1ûböÅì_Áìˆé`€òLþ¼* ŸäÍ9iñ¾¥JEÞÇ"Ç:!Ûšlå°÷Iv; kȹÈIg T¸Î« “aÏPòT]X7‹x3ŠØÆÑìÍÖŽ™™?ù`2ŠÓSp[\½(¾ úâ/5p+ Íb Ì[pèðÅÍ“xƒF0gè^Óòd}Hu˜ԋ”ošhL¶ýœùªjHˆ„1ª .å¼þÛ¶æéu\9§JÅhId3q©vÌ™<¦G]jµ‘ìðôt { ðÿ,Ü~hcì´Ê˜Ç"o«Uµ¬m¤l§íÙ!ni.eÅO{5k·ßhs W›Ýj¦}Š£¹OÐøv*õjï/ßáô¼-[%øùÜ+”MÖaA´8ž4T•n¢l'¬âà4Ech£e¹Äêïy‚Rt‹»`6¢"Xäsè Ë 6¡t/P®¨ÜÚ$:RäÖVQÉMU¢Ú6_ê ÉJ0vT‹:\ÿPMÇgVÁH{3®zK Ú!CÏ‹6>å,¡Šœ0ÎËFO1y(±Ë'×hîQüÆD÷‹Ù³/f_̾˜ý;˜ý±æIò {ä;*f‹"yÇðF‰Qæ» ƒ^œ¶}Œ/…iT:—s9~Ö©HÂFŒKa°­ŽXG¾®ˆT_L‹ó§’Ä8êpÝWÎýÑÁã- óö<]ÖYzÐJ«ëâ%8ꊛ÷NÃL0Gö9¾k‚ ÏN^ž{ÊúVí¶¿+毡½tÙ bXt‚Tã²Ã,ž#D­.ö^\-ÐU }êÕZ-¸ØUº爥õ‘fã4µ ìH„§ç«NÎOGýr-ŽXv¶R(s>‹„@HîPÛ¦ˆÛ¼«|^1ÞÃÆ‰¥Åj7m¯_T²ž:`RåGè”Ìeîo;†a¥Ce‡vhË€þ|ѪûÃKU´ƒVíûÚE›Ú|RͧõV¬ä¼yŽÆ»ÊSÕö Ó–16r¬v[òi½TߺVá«9Î%TREŽÛ[%Þñ™«ªZqxÈ­šä¡Ê‚m<~·FjUlq¥O‹ÞúùÏØ¥…B\Š JróXËÓvx°nª„ÞHaÇÅì‹Ù³/f_ÌþÌþä):“Kq¬ˆL•ú£O‡§zš4ó×ÚV%êƒÄ2ÄWË*¾(aHùÁv©¾XLƒR-°ÿxƒíF§è…"óÇkF³8e6• y}FË_¸’À&ýª½'1Œ¥¦~Ú&É÷a;=(Eª'§íS'²ÝòSŠ’xnò£äæk9š;Õ`Ë:€ÉDYv©-ç8ÁTjíƒ'Ö‰Vó~Ðv¯…þÔgðõZ1]3µn148`Ÿ+7£I°Ëã‹H!8ž¡­ˆ÷´Ÿr,L #ˆÆ:Ý}øbËç’«ÅÖ•µ¢c÷sÑŠõ\ _ŽE–mÑ gc¶™ò´,Q‘!gOÐW[t%Óa”öÉyle{taöú\æâm.dL«‹ËÙZü3â…Ðs ñ(ÑÌŸn©ÛòY%½EKÚ,Œ"$p¨Ê¡ëÞ•ˆUQa¬…žôܵ#rY}ë@ªó½måìLÐÛª-N+-ĉÕàß¾Èó¹­a -ŒÍ Ž“OÉUµ*§xjÓ:–xcõv,QUq­…âböÅì‹Ù³/fÿ f:-ǾÉóXÐFåf­îÕCħN—R©L¯É¦ 9 ‹¿µ}H}•ZþS,•pûrÚ'ûruXD lÀã…ÂVµÀƨ?Ô6•Z7lU3¼“»ü¸™8T´ÝöRrÑšÀÜFK t”1–Lü ¦Õê}¼'ÍšÆò‰ìÚFÑÎ\äœÛÞº[²#ÂÂz¸Ó°àGa… °ÓØ^iuX à:õGgxo&8U³¸p¢oÏe€cÛŸƒG¢ÜJ40ûŠ•5ìN¦5ÉáÂEîÓwʦEnLàZ­¬-¨Éj›—×+»%§yöå {Pãà£ö„^´Lö5ßb²*9²L"—°f‹Þ¸Oê(5Ó1ÙFp¶Ï§q7ü:6HY+×½\ ÁG˜åXi_æ½™ãR¥—êÚˆaWɰÚЫR1Á#j¦mG¶ø˜ÓâçwÚTi};Tê]™b þκÛ–J;:®ÊàÅì‹Ù³/f_ÌþÌþöûíàX¶ÝOÈ·µNïí)0ó–?0¾j§°=ßõI£~Ç,½¢|ç ‡MC{>V{ƒOD4øÛR‰ÅTáXy¶‚% ‘è£ðÞUƒò*® ,sž"î/â;W¾ÀÒã4ÔÈ fO¿i=øTÊpv%¡L†â°€²%ÌÐûNxCWf–žW¾“ª_©QG‹Çgÿ"%î0·­CvW#†"7¯hÛ¿ú6a·ºxsTÕ£-Æ´VròŽiµ^õÝÁU Qº !£ýu×=èÖ|‡9œ"ÙþAB[he?3ºîÂiæ‚§òyÍùæEÿ³¯6&„ͶµP‰S^zEÓ<,½~w°Á>©ûj‹*Ä„#ÈÙìC½ŠïÅù¨¨U%ÃÎÖ#jáB‰ð°Ljìð Ñ=—UÓ´Â_ßáÅTð´,[Ù8c¹U=‹Õ²Ÿ„ÄÕþÿ LšN9U²ÕÆïÐ]ÊvnhrzˆúâO ­¸V w&ÂyxÊ«&ÁØv“¸˜}1ûböÅì‹ÙÿzÌþtôjŸlž¥(Ž:N\m®|{ˆÒíóLEÌt§€fÛæôÏ(¡xi;QÞ‹7ør}rìÈW|Oâ0èð0D%ÿ m[Ô> ¬’Ã(™Yd8€npHU¯Ô3[-›‡Ø1j{.³ô¨ÎË’§Y{jµmU‘ú9'µ(Û¤jÕ5ò¢ õiÙÀ¯XcSÝæä¸gj/¦ïˆ1z’.+¨Ó§À<ª…ó”ýÓRã¾ûð)!JôëÙjl«™Ô“y‹2êôëm V Lò™o‰£Å9WÞ%f(ŽÐ'UF´3“a{~‹SÊÂ)6gs/²Û¤›oÎVd¸…ìÁ<¤¾“Ä´!pv{°yh´£:¥V)»Q³k!WâYÕÓ01Æù÷QIj^#‹'ìÅb@3ºò“T·(ÿàªÂ4gÍ×Ò5³Ó‹ßÖq\ Ü »8’âVëS›§ÐÍÈ´­µÁ[œÚPi»VðômνDaXÔÂbÓ† ’‘Uµ{Y­Ù§6!vZϦº¾‘7@ác÷®$9=´KØõ˜’ôÒ?—ý.f_̾˜}1ûbö¿³?m×Z”1;º-ùXÆpY)%çû$˜à¡“ iÆ7&éŠå)ñA?à‡ÍÔ€^Të£' wL«u[ªsëÉIâ2ͤÂËÿ2Dó3ª\?„4Zç)—£)Zú{Ýüxʧ2úS‡¥˜Ë;‰,TOŠ©v°}2wsÆ»êð¦ÛüªÎŒ·äAîZÕ³i×}î,9‘¶D'ÓP¬èVŸÇR·O«ubV¥…»L³xq­w°±hÚí2pl¢öB•¬µÜ–xŒÛL˜z“˜~üÁƒÜÖGdû2Ç +þš+“*¦êB™ à0îô½!¡*“uòæ’Ш۸ô807ªÎÀû™cúïwULëî™™IÒÚB¬¹ÇÖÕƒèÏÔ¾ÉUARõF÷6ù|ÑU:¡^ifnbD}X\UÆX:1žËfVÉ)g ±¦ËΘžóÕ–fØpdcÝ{ Ôè”V^•R¯èß|°*,¦ŽªÞKD}’Ê—났³òÏÃ.f_̾˜}1ûböï`ög äÒ#:应§ú{¬Øn!ÊF¥€ÍáöÆ€Oð¬&%®1; òÛú(+()iÌàÄðn>[·¾OžHQÉAĈRÜ“/Ôâ†nAz‰ƒêµ"õsŸòˆT‹àm‹¢¬@„™¹‡j>i%™…_¬Œéþ… nˆV ?ÓF¡/ïÛX9뻃5I½'†±”Ìu“úšÔ.á"“®u´ƒ¼¯ÖÜ)è/Žè€`N•8Z„õé+±é] `³\,+CvfãÉ-ËÑä/ã…G­¹®4yW›¶[w0–A½sGlL]‚%rx–»½UcanM؇KpF[-ç§Öø eðîË-Ûªj‹µ f¾*Fh¡œ“Æð ûqðó£±aeqç­pŸ…QÖ—Ìéúù®†òß ¯Ê“\Ê!Ûp¯Á£•ÜØ×]$ ­Öœ¡¿%°òéÿëÓˆáyftõid›T¢ö†‰v$¹Ì½WêXï÷µ³nó³( ¹yû ¿8º›ÿ E–X¶l;ÙïböÅì‹Ù³/fÿfÿ?Pü«˜¿eÌIEND®B`‚././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gtk4/images/popover_menu.png0000664000000000000000000001156215074674453022673 0ustar00rootroot‰PNG  IHDRHå1án·sBIT|dˆtEXtSoftwaregnome-screenshotï¿>&tEXtCreation Timedom 25 dic 2022 13:28:20¯1›.ÒIDATxœíÝ{xTåÇñß9'. w!$€ÐÂ}m­uÕ¶îÓÝ>¸­»KñA¡ên­îjÕ…¬o…»ÏÓú¬m­«ÛumuQ¨—ºÞo­­%@ !᪂( `“™³ÌLræ0oîÌŒé÷ãsžI&'çrùúžËœHH:ë,.¯¯— &®áí^éMÄ,ߣÿc@²¸JF×÷Ø-=‰˜?~Þ÷½oÛ=Ù èpôÑJ4M5êN ý#FÛó˜(ŒNw6z!}ô‡2œàyïc‡2º¸òD£DÛ÷¶í{ž$€dqÔÄØcX‘™¢Øi$»2‚ôýtÔHo(]X6ô… âÛBЦwTÙé.wg#H½“£ö8fH.i”¤!’²»°lè+­’š%—tDÒGÑçE"R¤eÞ]îXÛŒ‘ìjÄüq̈®8CR®¤‰/¿ôÂÕ…“'_*K9r9ƒ É,¹rÕT[W÷Â%_¼ô!I ’Õ>Ðkõ}FXè(d–â1zG‹±i´¤i{÷Ô>¤H( 4N˜Txµ¤*I‡‰clòïzwµ; ¤÷,ulw:ÆLIC%•ìÝSû˜8Þ ý'L*\"i‡¤c’N«=’±ÝnÿYî8¦@úÏNÛŠD0#ú8@RIC]Íã’rúâ_gAÓÄÉS+ÉSŠœÌi>zOæ$EvåRï.vlô8êÅß>•ˆ#€ô–mÕ(EÚ;»Ú¦C¦@ú¯uô]Xø™/÷vËÄs]7%SmÕhµ÷+6àó_Ï}†ŽÎbûw³c HjÛÒÏ¿®@Ò¸®«Ó--jnùD¡`0©ëveg TfV–,«ÿ]€bÛ¢È9“€Ú=†é𫸋Éãtå:Hÿµ’ºa×R?übÉæº®B¡V…B­*˜0Y9¹C“ºþ¦ÆcúàÐ~…B­rœŒ~I7ìZ’*~÷:6ux©O¢@ú_sí?™,©ï*üYr]W§š›‡UXT’’mÈɪœÜ¡ª­Ü!Û¶5 ;»E2òOñ^žè?é}Œ‹Zg»Øþ Äc»Ú6mz/ «¥¥E'§zStN^ö7Ô)9@ŽÓïî5ÓÞ®3'ã(ÒÈD·3‹{‰!}zÇuÝÈË­A ÉÉMùÉ’!9¹ µ#¯ÁsÝþ5ŠŒit¢3 C&:‹èÕ3è”é™ôV:žéLÇmê=o»b=ó6.á™lnI½¸ãN¿ü¿ DݾÁu’¤ëv%_ÏÉ×ètíPºnW pÏF -P¤tÔã@òíìß>=-¾REÓ¦è»7Ý œœÈ›NœÐºýX»ª´ññGS¼…œÅîW2=ñÔ&ÍœÑȧ6=§œœ555Ežp¥¦¦&=¾a£¶íØ¡£Snî}vÁ-ù»¯)3¹9ü?,¿V@¦~ùÓŸ´½ÿÙ󕕥߿»Ya7¬K/þK-þúßž±ES¦(33Suõ ž*¨|G…,ËÒ_]r‘žyáE•—Wè¢/|^ï½X;¦ÏýÅBÙ–-¹=[wss³úåÿ¨lë6…]i|~^Û¿7ö³‡µá7ÏêÍß½£#G*?oœý2Í-)Iºõ¶5ª­«Ó½·¯RÑÔ) ƒúæ·oÔéÖ ~¼ö^5B'O~¢+®½N%Ó‹´fÕŠÞ}Ãâ7]ÿ…úÙÃÿ©Ÿ?üH—æ½vù2]³üª^l×ÙS?N•U5ºí®µºsÕ Y–¥ÛïY§ú½û”Ÿ——ád?rÑ…¨¢²J»ªj$IU5µÚYU­¿þÒ%qóefлe[tÎèÑ:oÁ|…Camzî·úßÏt¸üWß|[›·–«`\žŽ?¡_?µIeÛ¶Ÿ1_f  ES UWß I*¯Ø¥IçNÐ…Ÿ?_’´uûIReud÷º´dF¯Ö½þõÊëojØÐ¡š>uŠªkëÎXÆÏýo=öÄ9Ž£Ù3K´§¡Aw®[ßöõZ8ovd›<_¿¦'ÔÒrJ[+¢Û[S#×u5oÎì·÷lêjôzÇ$ºcå-;f´öî? Ûî^«Ûî^«ú½û4zäH}åÍ©ÞÿãéÅW^SAþ8­¿ûZqã úÖ7¯’$=ýìó’¤…sçH’vÕÖJŠD}ØÐ¡rGÛ¶WHRÛöΟ=«Ãíí.×íÞtͲeºfÙUÆå]³|™®^vU·—›L#†×]«¿ÛɆ}û5jä­Y½B£GŽLîÆôâ2Ÿ4ÿ"Ψ‘#tÁçÎÓko¾­_{]›·nÓÒoü½È·Ùþ'EFGÏýß˪ݽGǛ亮Ž78ãûê}ß¶9Ž\¹*œ¹ûLcÓñ„? ¥3‹ÛÖ3rÄp¹®«’âé’%Í™U¢WÞx[u{TQU­±cÎÑÈQÃ{¼î}J’fO—íØråjÈàAž¥¸jØ¿_ápX³g–´Ísþy õÀÏÖþƒåÊU~~žÆŽ­êêZ…ݰÊ+vjþÜR>|Då; ‡´³ªJycÆh̘ѽþð~?zâšåË”9`€xð§g<ßQ<Ïövu‡ãd(3Ð~k‡@F@@ mú²Ÿ¹ìo¾"˲ôà/Uvv¶¾|ÑΘçÐûïëö»×©aß~]írýÇþM@÷þ0e†ÓñNAþ8 6L•5»U^±S@@ES %Isg—J’^yý-}pø°JK:=v¶îP(r·ªì¬,ãç´´œŠÌµ=wêÔiY–¥¬Úž›?gŽŽŸ<©šÝuª«oМY35Þ<ù‰vìªÔî= š?7u»×~W.ù†¾ýOÿØö~oã˜LkÔê»îÕÞý”Ÿ—§ü¼¼¶ŸÍ5¦zó$È~§`ÜX-˜;GápX—~ñ"eggŸ1OuÍn5·t–Šg)gÈà³r«­Ò’b555éwK¢)…ÊÌÌŒ>?C¶më¥Wß$ÍêäøcgòÆž#I*Û¶]ÁèŸ+hnn‰›§`ÜXIÒæ-å:gKy¹\×ÕÄ mó-ˆ‡|rã3²,K3‹§kAôxã¯7lT8îóÝ눞_Ârå’źfÙUÑéÊ^-+™î\w¿<¤ü¼<­Y½BkV¯P~^ž:¤;×®O궘p»?‰þŒ_½t‰.ºà|M›ÿs}{ÌèHP^z-¨Ý{êÕÚÚÚ>™‰Þw;˜'ª´d†^}ó-5·´hVñô¶ù²³²U4uŠvVVɶm•MK¼Œ.®{bAЦª²ºV·¬ú&N(л›·ÄÍ3>?_³g–hëöºå{ßפ õDz- º|ÑWÛ–YTX¨!C†¨lk¹fMSö€,eÈÒ¹'¨²ºVÔ´)…}óó߇MêÓ“1Ije}Ã^;a¼n[q³†åæJ’Ö¬^¡;×®WýÞ}iÑFýÐÈõ`îl 4(áÇ‹¦êò˾*ÇqôêoiÔˆáZ8oNŸoǬâém7]Y?JœW…Nž¤öz]ÿú/7há¼9úð£TßРë¯]®áÑë,cnýçëô¥‹/TsË)••—kjág´öŽÕÊ3¦mÛ¶5?z`άö?°0º[=»¤¸?Þm;%ž~ìÝÏš¶8JÒ°Ü\ÝÏ=ýØ#©Ú¬8‰nìýÓ ±KfG§’KZXW½óþdm$ÐEþXWH'š5}Ö¼ToŽ$iWùf ÎÉ•ã8ýêŽâ“§ÎøŽ¤?J:!éIÍÑ)ZùÓ q~$p7 Eâõ¥ÏoTòOפ/F`ÀYl UÒu¨–®Û•üM eÒµDéº]ÉÇí΀4NwG; ¤ ™Ž8‹ ¤HlGÖvhjÔàœÜÎ>å¬:ÑÔ(ÛqØÁöà$ *®dÉR†БÞKy |ðž2œ€,Yü~Gq’H‘Ø Uì G@†êk«4ꜱI剦Fùà=2 [=ÛÆï8Ç ²mK’£S§‚rÃ!Üß p(Ôéçõé68Ž'CáSR Ý&HH)˲dÛ¶ …B–dÛ²ðY¹ýœiý–m˱m9Ž#Û¶ûÕk°{‹@)‹¤dÉqܤÅÑ»~É’m[Äч@iÀ²,9Ž•ô8z×3õü2®lú ~Ÿãf`@ À Ç»Ø÷Õ÷åv@Úéq ~þâ¾ÜH;ìb€  $H0 `@ À€@€  $H0 `@ À€@€  $H0 `@ À€@€  $H0 `@ À€@€  $H0 `@ À€@€  $H0 `@ À€@€  $H0 `@ À€@€  $H0 `@ À€@€  $H0 `@ À€@€  $H0 `@ À€@€  $H0 `@ À€@€  $H0 `@ À€@€  $H0 `@ À€@€  $H0 `@ À€@€  $H0 `@ À€@€  $H0 `@ À€@€  $H0 `@ À€@€  $H0 `@ À€@€ ] ¤ë{?Ü×g‘¿Yþ¦%ÔY ]ßÛn‚À§AXí‹é0”2Q½|ZtÔ0cϺ²‹«nØ3…z¼™|!Å7¬K{Ã2ìyŒ-0$v³|ºxÛåc‡-ËHðœê=ö’Ô*©uà Á7HÊŒNè²E¢kK²zþo€nñîåÆ:”t::µF'o$ý;cW;Q ý+õÆ1¶â2IYÑ)É µGÒ—HžXôÚqjcKtŠ2Q$2Ò[ÔDUŽåù¸#FRÃߪÚ›‚ŠEz#™0” MôÆÏû¼7–$€äI´·TünvGLÈt Òò¼[¡¥øðÅ>æU: 怳Í;Œ0¶«ôMþc‘ÞeÄéh;»c)>’±ÅžK´kM$[¢½^ï1ÉDqŒÍ›PGÇ ½»Ñ–ïcÞƒ¡ÞÝêØqINÐH6Óe‰ÞPzOÒxÃØíc±Ù  ¤wÔè=2Š,‰.KLô—n],ÞÑRjß½ö>[¸—š]kéÀÿ’Bý»ÖÆ5Í=ïîs¢(úI,$K¢{Gxßößl§Ó8J]‹˜?|v‚ç #€t謴7‚‰u5f¦ãŠo®\ßcgÏŸ¡§acÄàÓ Ë÷~€dûA[÷É &vIEND®B`‚././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gtk4/images/textview.png0000664000000000000000000004543115074674453022036 0ustar00rootroot‰PNG  IHDR­G¼M¿sBIT|dˆtEXtSoftwaregnome-screenshotï¿>&tEXtCreation Timesáb 24 dic 2022 22:00:08§¼Õ( IDATxœìÝwxSåßð;éžé„RfÙ{–‚"‚€lDpŠ 2‹ ¸Pe(2E øŠ ŠŠ?öž E)£”RÊ,¥{'ÏûGÛ¶YOšNî×¹J“sžó=ûî @DDDDDDDDDDDDDDDDDDDôRc{Ön›ˆˆˆä ÿ/’¢ä~|‚ˆˆ¨ô è¢ÀO)–ä †Ýßuÿ¯´¤ """²*MîOÝ Q0T Ɉ‚g”:?õ™Bˆˆˆ¨X¨s =¯ëþ4ÊÖÌ‘ë;Ë ,ðe×y‚ˆˆ¨ôÙàQ`Èû©AαÚPh0"Ì9QðìBÁ`ƒGB7HØ™Ñ6¯,äyùC…îY “—4L(t;< ¶¼øpàdFÛDDDTü²¤Hp@\îk6È jäëu/iäû †sòÃmîˆm¨ÔÚ½ëŸÑõêÔé Ü!øQ™¡€€@╈ˆº=Ûs €ëðèDAv!40ÁØ^ü÷8èžmÈë*huíÊä """*ÛjÖ®7@8€{È y]ÁK/e ºOYä]®È ö<4‹ºve#„àýDDDå…B‘U³v½—„ˆ‰G!"ï²FÁ§4ò7a¨iäºB‰œ›"ms:hqy³p·ÊÄQ‰@b@úÃ"2s³evîOÝ›-õž…0çQKÝKyg|wîø{$ÃQù¤Üwîø{$r€°Ç£ûóž¦4ÊP€(øYï¨T¯^E-žˆˆˆJOî±¼ßóNü¼§BŒ=…Qð2F^ãv<J…„Õ¾“ƒˆˆˆJ˜B©pCÎ=vxtïƒ9Ç}ü6•9ŸQð³l8 PðYM""¢òK¡àŒü—/ò:£rê ¿ó¢à=yõ¾”ˆˆˆJ‹î±½à=º?óöÝDYðìƒî¥ ~ÏQÅ {l×÷Õzº„¡ïëº |„5Ï?Uº_M¡ïÆI½÷Aº„QðÓ'ír;{mÇü@T®Ä>xðñö.åJˆ¨Œ±×ét?•Òú¿¹¿ðŠÈj^?ââ ¾?¨?¼:tp‘Æ‘‘‘ µ:ŽŽŽP*s®$N}ïCDDFaÒ¸7ÐõéŽùúŸùÉ\\ ¿Œ…Ÿ}‚wg} ¥B «–ÁÁÁ¾Hu˜2e懈ŒŠ( x{y¡j•*xö™§ÑñÉöÅ:n"*ž€ Ê/°Us$%§®FDâ^l,š6jww7@êU‹¼Ý,]½‡ŽÇâùsP£ C» DDFáÔé³è¢ ’’’péòUÔ¨^ 5k¢FõjP*°µ³-±í·CûvP*¸uçÂþûç.\Àáã'1sꤪ€ˆŠKÎ@0Bé7z”öÿ˾ý»öÀÐÁÑ´QC¾ŠºÝŸ9ÿ²}[løi BÏ_@vvlms6ë“gÏB£Ñà©öAP*ørîÇV¬Ã¼:Ç¿1ÎÎ΀+øì˯qüTö„R©ÄoׯreÔ®U×®Gá¿ðËhÞ´1àTÈY9†Ž;;{ü°ú“uLÿ`6®DD`ÞÇï£QÃúÈÊÊÂëoMAfv–.˜__o¤¤¤âå7ÞB³&0ûý&§»^:1üE,Y¾ »vï×cuäÕýDP qüÔi(•JôîÞA­ñÝúq9">Þ^ûÚ«hÒ°@£Ñà×ßÿÄÁ#ÇpÿÁT«Zà D›VÍ­¸$‰JVõjUq1ü2>üt>æ¼? …º‘Q7PÍß¿Äë±üqLÁŽ;£ô¿þÅ’oð÷ÎÝhP¿.‚Z·Â™sçñÙK Qk0fÄËpsqÁÏ¿þއðíÚ•‰cG£ã“O Fõj€žÝº`èó´mvh9s@ffBÏ_@ÍêÕP­Šÿ£z`^í[.†_~é ““‘žž³aa€.^º ![µÒ?íz¦¿]›œv£oÝ2«Ž¼¶ö<‚³ç/ ZU<ŒÇ?mÁ” 3+ Þž¸}_~µ ™™Y€V¯ûþ666hÕ¼®E^Çœ ñßÅË¥¿^°cga7kæ4Tñ«„¨7ñáÜùøpî|DFÝ@%|4ómËÛ¶?ϨEÞ¸Ó¡çѪE3¼=a&ƒv­}·îÜJåŽQ¯ GZz:fÍ[€Ó¡çÑ»{74oÒO¢fµª€ÝžÁçûkÛ}2('@œ: »ðÒ32С]Eu´kÓðß•+€sþƒ§‡lllzþàß‹—m[µ0{úœœàää„´´t¨Õj“uäqqqÆò…ŸcÎû3ð€~€®OwÄg½¥_ÌCõªþxŸ€˜[·û ;÷ìCõjU±ðÓO0cÊDŒ{}$`럛]+QYãíå…¹¼›"¢oâúhøúxcö3PÉǧÄë)ÂM”Eˆ-D ‘û/Ï͘[€ÓgÏaÀðùúMJN†€À3OwÀÁ£ÇzþªøUÆ+CkÛÚvóoƒ~~¾¨Y‘Q7sç6Nœ>x¢}`¡mU@˜¬£aýz¨âW —.]Fhpî¿hÛ¦%îÝ»sþ…Z£Æ¿ááð÷óƒŸ_%ƒûƒ‚ÓŸ™™‰ôôtøUö…ÒFiÖü¥Ò ¥õëÔ(lÚ÷ëÕ©ƒè˜[HLNƒ‡¡ÑhЪy3(m”xê‰vXöí÷ˆŽ‰á¾‹Ê5[ØÛ=zŠÊÎÖvvv¥²^ó¢äêê hÓªF½<4ß{ºAx{zäþO@¡4ï[gžl„Ȩ8uú,N ͹|aຨ9u´mÝüý._@Däu êß>DhØ¿ûï"®^»Ž~½ä¾”÷ü¿ÿAšÕk˜]GAy¯ê²±yôZzz@­Qk_ËÈÈ„B¡€£ƒƒT½DeÉÃø|ôé|ÜŒ¹¥Ý¶oÞº…?]€ÙÌ€§‡ªDëá=ìØG—§Àë5ªúC©Tâòå«pwuCU¿*ÚÎÎÖÀÙsaØsà0¼¼ÄøûHKM)ŽQääìO/_¸{zš\iY§iæÖy#ò*jÔ5ø~y˜€uš£¢ÕYÖÝŠ0 TþX=@!{ï6R’’PÙ¿:ÜUÖ…Q‰ ñ¸{+™Yéð©TÅà Ë:­[§1åeXçãY§1œ†¢³Æ4PÙdÕ!„@ÂÃ8¤$%¡^£fÖlÚlî*¸«={àÍѯÃÎή„«"z<ܹ{kÖ®Ãá£Çð .No?>>ÞèÓ«ƾ6ªÌl‹yáÁÑÑ#_Žž=º£’¯/îÞ»‡ÿíÜ…u7áç_ƒïL .ír©”•™aì/²vÐ3T«‡J…ñoŽÅ€~}K¸"ó=xð6n‚B©Ä„±cJ»œBJâ/Jk(u–‡ó”§ZMÙðfÏûIIIFû‹}€õ?ü€ñe`[ =¦ +¾þ M7Ò¾W­jU¼>j$‚‚‚ðÖä)ØòÛVôx¶Z4ãåŒÇY¹¸‰2ï ·êûµ¥]ŠQñ øtþ„_º\Ú¥àÔáƒz»/>› økÇŽR®¨âY¹æ;¼óþ&î?Ëȶ¸å·ß#_ž/<èjÖ¤1F¼4ðËÖm%V•Meæ&ÊS‡zmÿÁC˜þÞÚßÿÚ±ƾQ¤Êò³ì⦾Z`þÂÅøeë6œ; Ô+JaXï"lç§;Èùë§do3o\mŸêdV†–AÑÉ͓ҫ·bÕin}ßz Ë¼iønÝ|·n}¡×׬øvvö˜2ýÀW_|ŒÌ ¼ñÖ%µ-šnÿLh( ggößãÙnXõÝ÷8}æ¬YíRÅUf.aè“w°Ë“³¡•]Ñ7o¼½}JµŽŒÌL,_µ;÷ì-óóŒ¨"ع{/V®ùNï{övhÔ°>V|µP§vmü~©$Ë3KBB" ’¯¯Ñþ*WÊy?>!¡Øk¢²­ÔŸÂÈÈÌÄŠU«±s¯y;kÞ-ÛÖ­Û·±tù „œ>ƒ§(•J%Û´.Õ:—­X…Í[~±z»Eaî¸N2ï/Êâª]¶ÝÒª·¢Õin}–¶_æŒã«eË ¾7yút,_²uj×\¸¦=!3Ž¢0§}•ʱ±pçî=T«ZÕ`wîÞ×ö_žP!Ë•úˆå+Í;Ø•¶‡ã1vÂ$ܽwÏh4€Êݽ„ªÒoçž½€5Ë¿As=79u´ìt1éW¾ªu‹عg/þ·k7^9Â`ÿìÚhÕ¼EI•FeT©ß‘w°Ë³fùÒ|½ Ž-nÛ4óÛúeëVܽw­Z´Àg³?†·—W¾÷}½?mùíƒÚZ¹F¹:¹;³lu¶‰aËÞ=…—·yNÚoÑp…Uœ:-©Ñzõå)/óÓÓÓ0ñ­7ñÁ¬Ùzß[òÅÔ©€ˆk×uj`ñó1rôX©qéö‡ ˆ{öbýÆMh×6M›4.ÔOØ¿ÿæ<Å¥P`È fµKW©Ÿ@äž­V—R!Æ]¹Ø¿_¡ðÇO†@n€(]=Ÿí†?ýÞœ8¥´K!z,tïÚ7cb°òÛÂ÷Adfdà¿K—<}`ñ󑙞QÒ%šÔ¼Y3 4?ÿºoM™ŠW_†žÏvCåJ•pçî=ü³k6lÜŒŒŒ ¨T*T¯^­´K¦RVê"ï`—§¬ôêÕ­ƒý‡á£ÙsñÑì¹zûquuÑ›ÚKÚ¸7^ìܽ÷ccK¹9%óeÑ•‡:ËCyÊS­†¼öê+ÈÊÊÆ÷ë7äûÊê7ÆOÌ×_þ3€¯OéÞt­+xâ!°å·mXýÝZ¬þ.ÿ£ó …žžxø0ã&MÁН—ÀËÓ³”ª¥ÒVꢼì^ú"nDGãÀá#HOO×ÛO`«Öeâã]ííí1yü8L?®´K!z¬Œ}}Ô¯‡¹ó>GbR²YÃôíÕ³˜«2Ÿ ¦OAg»a˯[qöÜyÄ=|Z·h!ƒ¢zµêxkJ0"®E2D<æJý) ;;{Lzk&½eÞÁ®´žnprrÂì>´j›æ’i³ÝÓ¥Ú>qp¿Tÿ–2wÌ­¿¸ê–]~¥UoE«Sv½ÍSë¯ì¼îôÔShðýwøný1òQÖ¾>>èÓ«'^9¢L<…¡«Y“¦hÖ¤©Á÷—/YŒñS‚qõZ$ÆN˜ŒåKÃÇÇ»ˆURySêg ˆˆ*¿Ê•ñþ;ÓK»Œbãááo焈ˆÈHL9Ö|[ÚeQ +õ§0JWÅ«óÄÁ}ÅÖvј7óë/®ºåÚ-½z+Vòë­\ûES^öÆX<=UX¶d‚g¼‹Ê•*Ë8¨lã""²ˆ§§Ö­^QÚeP))_¦EDDDe I+¦§0Êǵ0ÖYrÊË4°Në*/uÃi Òg ˆˆˆHšÕ„£³ ’Kÿk^“àèìbð}Ö)ÇTÆ”—i`r*JÆp¬§(Ó@e“U„B¡€Jå‰ûwo[³Y‹Ü¿{*•§ÞoÉcòŒÕiLy™Ö)¯"Ôi §Áº,*»¬   \ÜUpvuEä•ðRI½É‰ ˆ¼gWW¸¸«´u±Îâ©Ó˜ò2 ¬óñ¬ÓNƒõe¨l³êM”J¥666p÷ð†­=îß»èëÖ…IŽÎÎpWyÁÙÍ 666P* g$ÖiÝ:)/ÓÀ:Ï:á4XGQ§Ê.}1P™ÛÙ°Ëíœr;g®Ú¥¦$/Ò× jµZÛi4¢„>¡L”Jlll´¡¤Ë:­[§1åeXçãY§1œ†¢±Ö4Pñrvq à€d©Òr»¬Ü.€&·Ó²úcœ …B»’ØØØ”øãCy§Ç”J¥Ñ•ušÇÜ:MµQ¦uš§¢Õiª NCÑXc¨l*–Ï(­UwüæöÇ:Í¿5Ú(ÓÀ:ÍSÑê4Õ§¡èã§Š§X¿ £¼¬4¬³ä”—i`ÖU^ê4†Ó@”ïf!"""i DDD$ÍâKNüD1""¢ÇÏ@‘4"""’ÆADDDÒ,õêÕÓ~@ˆ¾îÒ¥KhÛ¶-¾ûî;ƒm4mÚŸþ¹ô¸-®,KOOGjjj‰µgÍyhª­ŒŒ ( DDXÿ#tÕj5&Mš4lØÿþûo‘Ûܲe z÷îêÕ«ÃÕÕ7ÆÔ©S‘””@ÿ¼5µ®ç1g»)Š‚µõèÑÇ×Ûï‹/¾ˆéÓ§(½mêöíÛ;v,àää„Zµjá•W^A\\œYÛ;ßÍaj›)émÔÚ,Ý Îc™uŚ˧¤˜Ú§eû7GQÛÒW_q­kßDyæÌh49Ÿj¹xñbìÙ³þù§ö}777“môïß­[·–·¥Ã•eŸ~ú)®^½ŠÍ›7—H{Öœ‡¥¹<¾ÿþ{ìÛ·aaaP*•ðòò²¸-!†ŠsçÎaÖ¬YhÙ²%C‡ÁÅ%çÆá¢,+kl7ƬíÅ_Dpp0233aoo¯í/##;vìÀž={”Î2ÌÈÈ@÷îÝѦMüùçŸðññALL <­0½\Kz-«*âþW—©}JY_núê+®š-º;:'''ØÚÚB¥RIµñé§ŸZ4nK‡£G¬9Ksy\¾|¨R¥J‘ÛZ¹r% GGGíëèÖ­[‘Û¬³ÝÈ8p Þ|óMì߿ݻw×¾¾k×.x{{£mÛ¶Jg†„„àêÕ«8{ö,lmsvE•+W®Ð§Š ¢ï­¹Oyå}‘–#7^ª¨  9€' Ÿþ¹èܹ³((00P¼ôÒK"((H¸¸¸ˆ-ZˆC‡å{Íš5ÚßwìØ!…³³³¨S§Ž˜9sf¡6‹2œ±þÔjµøì³ÏDýúõ…‡‡‡èÓ§ˆŒŒÌ7Î9sæˆÀÀ@áêê*Úµk'NŸ>-/^,7n,ÜÜÜDÿþýŽ{÷´ÃdddˆiÓ¦‰5j___ñÆoˆ¤¤¤BuÍŸ?_( ¡P(„­­­xë­·L?kÖ,Ѽys‘••%„"))IT«VM¬]»Ö`{Ææa`` øì³Ï .+có®`[YYYâÝwß5kÖ^^^âå—_ÄÕ«W¥æ‹©å2f̘|ÓÙ¢E‹|Ãfddˆàà`Q·n]áää$êׯ/6lØ wÅÐöoìX'S_``  çϟ׮]ÇUªT)))BãÂP}ú^Óe6@è®h‘‘‘€¸páB¡÷ÄR©QQQzgª¡vÍÎXéééÂÙÙ9ßA199Yx{{kÿ"-8-§OŸDLLŒöµ… jwš B©TæÛI=zTøûûë­¯à6gøƒ wwwñçŸ Ÿ|µX -+SóXwØ´´4áèè(N:¥}?--M»ã’™/æ,S{AuêÔÑ{"w#ÊwiÖ¬Y€¶Ë ‡†v ß~û­7nœhß¾½HKK3Y‹¾í¦8–{||¼ppp'NœB±oß>Q»víBõç-CS5ÄÇÇ ;;;ñï¿ÿ !„xûí·Å¼yó„‹‹‹¸|ù²ö5Ý3†$&&Šùóç ???acc#†*BCCÍž2ugee •J%Ž;¦·ÙQÜÛhA×]cÛ¬©íP—©ùbl_aশ Kö¿ºÓZÒûc@µ>}m¥§§ ±nÝ:!„uDÁù`i€(Ö/Ó*¨V­ZpqqArrr¡÷5j„gžyMš4Aß¾}1zôhtíÚÕd›æg¬¿k×®!++ mÚ´Ñöïââ‚öíÛ#<<\ïx7n HKKË÷ZÞ´]¾|ƒ Ò~MqB« IDATMVVMN“¹ÃwìØC‡ÅsÏ=‡õë×Ãßß߬¶Í¡»¬Í^6×®]ƒZ­Îw[÷ |dæ‹%Ë¥ û÷ïcóæÍ8räbccq÷î]½w#®^½ ___ÀÌ™31eÊÀĉMŽkíÚµ Addd¾{(dÇrW©TèÑ£¶mÛ†   üöÛoxñÅ-®A¥R¡S§NØ·o7nŒþù¿ÿþ;NŸ>¿ÿþ“'OÆž={°páB“Óëææ†wÞyÁÁÁؾ};/^ŒvíÚáĉÈÊÊ’Ú†LÕ‰¤¤$š¬ËŽš»îæÑÝfMm‡ºŠ2_ÌÖÔvaÉv®;­%½O1‡¥õéãàà€§žz /^´Z}úæƒ%Jüs ­Ä666ؽ{7¶oß<ÿüó0`€ÉöÌÎXéééP«ÕÈÎÎÎ7ŒƒƒƒÁ¾éÐ}-ï.ò'N 22‘‘‘¸yó¦öQ@S̾N:Ðh4prr2«]yÓ#³l222 V«¡V«õ¾/3_,Y.º’““Ѿ}{ÄÄÄà£>¶mÛТE ½ýººº¢V­Zؾ}{¾ñ¨T*¨T*888˜_—.]àææ†¯¿þÚd¿†×r2d¶mÛضm† R¤ž{î9ìÛ·ÑÑÑÐh4¨S§ €¿ÿþ±±±ˆŒŒDÇŽÍžn;;;<ÿüóØ·ojÖ¬‰-[¶HoC¦úíS0EUœÛ¨Ìº«+o›5µê*Ê|1gXSÛ…¥ÛyÞ´–ä>E†%õâàào$Šøµì†æƒ¬2÷AR;wƺuëpäÈüþû‰±êpúú«[·. :¤íO­V#$$Íš5³h:jÖ¬ 77·|$S²²²¤†Çüùóñå—_b„ ÚY_{Ö`Î<Ö7/uÉÌ—¢.—Ý×dÖcÊL€ˆ‹‹ÃÚµkƒÔÔT8p...ðöö¶ÊpÆússsÃk¯½†qãÆáÔ©S¸{÷.¦L™‚J•*å{ôM†Þyç¼ûî»Ø½{7Ôj5¢££ nhÕ«WÇÁƒ…””“ëÕjŒ5 ï¼óÞ~ûm´mÛÓ¦M3Ø^QÈ,777Œ1o¾ù&Nž<‰{÷îaΜ9Í—¢.—*Uª !!+V¬Àýû÷±iÓ&œ;wÎ`ÿ¯¿þ:ž}öYá믿FXX¢¢¢°eËAŸ>}´ýšþãÇcòäÉØµk"##qåÊÌž=!!!}:Ôj5èС¾ûî;DEEáÆX½zµÉú ¾Vp>XS±ÝD)„®®®âøñã…Þˆˆ}úô•*UŽŽŽ¢E‹bÇŽ&o21w8Sý¥¥¥‰I“&‰ªU«ŠJ•*‰—^zIÄÆÆœ–ôôôB7$ýóÏ?¢ZµjÚß5øòË/E£F„‹‹‹¨]»¶X¹r¥ÞiJMMýû÷®®®¢oß¾&‡Ÿ?¾hÚ´©ÈÌÌB%\]]Åž={ ¶ghêû]ˆGËÊÔ¼+8lJJŠ3fŒðõõU«Vï¿ÿ¾¨[·®v^ÉÌSËÅÔ OóçϾ¾¾ÂÓÓS øàáéé)²³³µ¯­X±"ßÍÅjµÚàô_ºtILš4I;___Ñ«W¯|7¸™ªãÿûŸ 0«ÿ¸¸8ñÊ+¯___¡R©D§NÄõë×MÎ;Cïç6jjÝ5µ5µê26_ Îã‚ã56¬¡í"<²ûß‚ÓZ’ûSÛQë &LÕ«W¢_¿~ùžPºsçŽèÝ»·pqqõêÕóæÍ*•Êh}ú^Ó°ð&J}çÄ”:!Â.·sÊ휸h'„Xd´BDDD¥G¡PLp@2€Ti¹]Vn— @“Ûi•™KDDDT~0@‘4"""’ÆADDDÒ ˆˆˆHIc€ """i DDD$‚ˆˆˆ¤1@‘4"""’ÆADDDÒ ˆˆˆHIc€ """i DDD$‚ˆˆˆ¤1@‘4"""’ÆADDDÒ ˆˆˆHIc€ """i DDD$‚ˆˆˆ¤1@‘4"""’ÆADDDÒ ˆˆˆHIc€ """i DDD$‚ˆˆˆ¤1@‘4"""’ÆADDDÒ ˆˆˆHIc€ """i DDD$‚ˆˆˆ¤1@‘4"""’ÆADDDÒ ˆˆˆHIc€ """i DDD$‚ˆˆˆ¤1@‘4"""’ÆADDDÒ ˆˆˆHIc€ """i DDD$‚ˆˆˆ¤1@‘4"""’ÆADDDÒ ˆˆˆHIc€ """i DDD$‚ˆˆˆ¤1@‘4"""’ÆADDDÒ ˆˆˆHIc€ """i DDD$‚ˆˆˆ¤1@‘4"""’ÆADDDÒ ˆˆˆHIc€ """i DDD$‚ˆˆˆ¤1@‘4"""’ÆADDDÒ ˆˆˆHIc€ """i DDD$‚ˆˆˆ¤1@‘4"""’ÆADDDÒ ˆˆˆHIc€ """i DDD$‚ˆˆˆ¤1@‘4"""’ÆADDDÒ ˆˆˆHIc€ """i DDD$‚ˆˆˆ¤1@‘4"""’ÆADDDÒ ˆˆˆHIc€ """i DDD$‚ˆˆˆ¤1@‘4"""’ÆADDDÒ ˆˆˆHIc€ """i DDD$‚ˆˆˆ¤1@‘4"""’ÆADDDÒ ˆˆˆHIc€ """i DDD$‚ˆˆˆ¤1@‘4"""’ÆADDDÒ ˆˆˆHIc€ """i DDD$‚ˆˆˆ¤1@‘4"""’ÆADDDÒ ˆˆˆHIc€ """i DDD$‚ˆˆˆ¤1@‘4"""’ÆADDDÒ ˆˆˆHIc€ """i DDD$‚ˆˆˆ¤1@‘4"""’ÆADDDÒ ˆˆˆHIc€ """i DDD$‚ˆˆˆ¤1@‘4"""’ÆADDDÒ ˆˆˆHIc€ """i DDD$‚ˆˆˆ¤1@‘4"""’ÆADDDÒ ˆˆˆHIc€ """i DDD$‚ˆˆˆ¤1@‘4"""’ÆADDDÒ ˆˆˆHIc€ """i DDD$‚ˆˆˆ¤1@‘4"""’ÆADDDÒ ˆˆˆHIc€ """i DDD$‚ˆˆˆ¤1@‘4"""’ÆADDDÒ ˆˆˆHIc€ """i DDD$‚ˆˆˆ¤1@‘4"""’ÆADDDÒ ˆˆˆHIc€ """i DDD$‚ˆˆˆ¤1@‘4"""’ÆADDDÒ ˆˆˆHIc€ """i DDD$‚ˆˆˆ¤1@‘4"""’ÆADDDÒ ˆˆˆHIc€ """i DDD$‚ˆˆˆ¤1@‘4"""’ÆADDDÒ ˆˆˆHIc€ """i DDD$‚ˆˆˆ¤1@‘4"""’ÆADDDÒ ˆˆˆHIc€ """i DDD$‚ˆˆˆ¤ÙZ:`ZjŠ5ë ""¢r„g ˆˆˆHIc€ """i DDD$‚ˆˆˆ¤1@‘4"""’ÆADDDÒ ˆˆˆHI³ø£¬ >Ùz›=„F˜7ŒR {ÂôƒÂZ…P‘p9‘9¬ >Ùzÿü—fõ«B¡0ï0"„À?ÿ=p³úY«*.G""2‡Õ.al>öÕ*{š}Ð…Bj•=±ùØCk•AEÄåHDDæ°Z€ÐHtª¨làíj…BaðTù‡³ç }§.…º·&l733í;uÁ͘[€a#^Æ›´ïgdf"==Ýì:`Ô˜qøã¯¿-~¿<)Žå˜gïþƒ˜:ã]ô{aºöìƒoŒÅ¶?¶±ââ3yÚ;øhÎ\½ï½?k6–._  ð:fLÁ~§u‹ˆ*«]Â`ö5ó†~vø¨Ÿ'R5˜¶åÑ~ŸðÆy#ßkJ¥ù¹§ÓSР~}íïë؈蘛˜óчf·ñ¸)Žå8wÞœ Ř×Gaâ[ã…ðK—áæêj…Š‹G·.Ï`ÉÒeÈÊÊ‚öõÌÌL?~ß,Y ð:fŒL¿DDe™•„é#ÏÓõ1­‡ìmðpRbr7Ž…EìßÞÎ...×ôæ¯[<ìãÊÚËqçî½ =‹k¿ƒ‹³³öõzuêX­æâйcGÌ_¸gBÏ¡]Û@íë§NŸ†»J…F [Ǹ>QEaÕÇ85šœÎÝQ‰Eƒ½Ñ ²ö5èßÂïöò„½MÎ)ò„4 ~=R¤qªÕj¬X½^†î}ûã³ ó½¯{ ø‡Í?aí?b÷ÞýèÐåY|±ø+deeá«eË1ø¥—Ñ©{/ yùUìØ¹«ÐxŽ;a¯ŽDמ}01xnDß4XSVV–._‰C†¡gÿç1ï‹EHM•»lRš¬½׬[‡7FÌ ê3ðœ:sFû{ø¥ËèôlOíï£ÆŒÃŽ»01xºöìƒ!§ÇOžÄ¨1ãйGo¼0üe,_½Fg:4X¿q†¼ü*ºõySg¾‡Ûwî˜l3››+‚ÛàÀáÃù^ßð0º=Ó9_;º—ŒÕ¤ï’Äã´nQÅaÝ!7G% òFc{Ì{Þ ý컨0®³;ò.¯Ç<ÌÆ¤Ÿ ,&Óh›YYÙHKKËשÕjíûËW}‹c'Oá‹ÏæbýšUptr4ØÖ+ÆbÔ+/£[—Î8²w¦O†ªU­Šùsç`ÓºïЧWOÌ™7QÑùÿ𾋹³>Æk×ÀËËã&¼—bá×ß *ú&Ö®Z kVáÖ­[X¶j•s°l°ærLOOGôÍ4mÒ¸Èu-úz)zôè†UË–¢EÓ&HJJÆŒ÷?B¿Þ½°ý—Ÿ±àÓ9xæé§´ý¯Y·{÷À¼ÙŸ`ý·+aog‡ñSÞFVV–Á6 êÖå<|"÷¬ŒF£ÁÁ#GÑU'@è2U“>ÓºED‡U„Z¸;)ááœÓ¬³½Ÿò—ƒ½Ñ¯Å£¿>ÏÞÈÄ›?>ÀÙPkŒ·ùë¶ßñLÏ>ùº}ȹ!ò—­Ûðîô©¨W§ªøù!xâxéº èÚ¨êï/ ‡?üw1<_?úõAÚð¯RïϘ…B=ûj+%5üùF|žž¨äë‹1£GáÀá#Òu•k.ǘ[·!„€§‡G‘ëóÚkèÛ³'êÖ© GGGܽ¬ìl<ùD;¸¹¹¢v@€ö²Bff&6ýßϘùv0êÔÎY¶¿7)))8tä˜Á6 êôT$&&âbxÎúz> ®..hØ@ÿ} Æj2äqZ·ˆ¨â°ú=×îgaâæX,ê o8Û+Ð¼š½¶Ÿ.¤âË ÈR›w§ÞÐÁƒ0e‚þPpëöm¨54¨WOûš%d»÷âÜ… HHH@ÜÃ8dyRÃÞÞ-š5ETÔBïÝˆŽ†F£ÁÌ>†"·šlu6RS“-¨¬tXs9úx{bbbànâ@jŠƒƒ}¾ßkÕ¬‰6-[bøÈQèðÄx®o´mÝ:g|·ï ;;;ß ‹NNNhÒ¤1®ßˆ2ØfA...h×6AãF°ïàÁ|—/ 2V“9*úºED‡uDî_¡×c³1iÓ|5Ì>®6r>ápÝ‘$¬=œ3oò7)+3FêÉ ]©©éx}Ütéô4F|•*WFðô&‡³·³Ëwg~W7À÷+—ÃËÓÓ¢šJ›5—£J¥‚—§'ŽrTª¦²ÄÚËqØ‹ƒ±qÓOˆ¹uË`?NNŽˆº^ø¯ns´nÙ¾;ß._Šƒ‡à~lì£u#ìѺ¡Ñh~é2êHµß±Cܺ}ÿìÞ {{[Ô«[×¢š zŒÖ-"ª8¬{„ùºë²0~S,&ýô…¥z?¯3FßM”™97ì¹89¡OϘ¿pþ»xÆc톶W©’/Ξ Ã;w‘––oo/¤¤¤à·m >>ÿÛ½W¯Dnó–_~é2>ŒÇÒ« jtê˜ssœJ¥ÂíÛw „€­­-^>ËV¯ÁÉÓ§¡Ñhp÷Þ=\¼tɹZò¬½‡ ~ ÔLj7ÞÄ/[ǵÈH܈¾‰ÿíÞƒÃGs†Í›6Åý;wîâÎݻضýO“u&&%áÏÿà~l,ÒÓÓq&ô<œœœàîî''ôëÝ .ÆÅðpÄ=|ˆÅK¿§‡‚tÉ4‡‹“Ú·k‡%K—£Û3],®ÉÇiÝ"¢ŠÃj—0” @£(øçûõØl\Í60! 4rã¯Û~ǯÛ~Ï÷Zë–-°ü«Å€·'OÄ’o–cêÌ÷agg‹¾={¢z5ƒíõêþ,Ž?á£F¡UËVX8ïSŒs V¯]‡kÖ (° ‚‚ `[·ÄŒ>BJj*Z6oŽeKÃÖ6gö òæ/\ŒkׯcþÜÙõÊËptpÀ⯖âνûðòôÄ+Ã^D£ OhQËÑÖÖß,^ˆ-¿mÃî}{±âÛ5°Q*PŸë˜0n,æ~¾ÃF¾o/ôëÝ ¶zNãëJJJÂÞ±lÕj¤¦¤¢Fõê˜7ûc8ØçÜ×0uò,[µï|𲳳ѮM –|9_ê“6ó<Û¥3:dðé skÒçqY·ˆ¨bÑ·'Uæv¶ìr;§Ü΀+€v©)É‹túè×[øý|&Jý 888ð Rp9‘)V} ƒˆˆˆ DDD$‚ˆˆˆ¤1@‘4"""’ÆADDDÒ ˆˆˆHIc€ """iVý$J]g®§bëéD»šŒ¨ØœE®éc‡'êºb`w´®å\\£&+JNŒÇý»w˜‡ô´4€£“ÜU^ð­ìWwR®*2®DeW±ˆ–ÝDø­4x«\àîî–>9£IÏÌÆÁˆ4l=ƒ†þNøe|µâ=YIä•p$&Ä¡Š Ô¬].n¤DÄÞ½ˆËÿÁ]å…€z K¹Rªˆ¸þ•mVý2-è4/T÷ó4:âè;á TãÀ»E(ŸŠKxØY89;£a³Ö&ú;ƒ´ÔT4lÖª„*£Ç×?¢’cé—iYõˆ–Ý4+<@u?Odhlð²›ûùpötíÕ<(ôÞšuëñáì9Ò5¾óþ‡˜öî…^ÿjù ô0)¹§IóDߌÁ“ÏtCbR’ô¸¬e؈װaã¦_ä•p³vÞаYk89;#òJ¸É~÷î?ˆ©3ÞE¿† kÏ>ñÆXlûc;`Ô˜qøã¯¿‹\»5edf"==ݪmrý3Íšë_Y˜ß™™™hß© nÆÜ*sµÉ*éuÊ6«ˆ3×SqñVªVö„Fx»ÚàÝ^Ø2¶2¶Œ­Œ÷z{ÀßÃVû~ÕÊž¸x+ g®§lW­Ñ`ɲåÖ*íÛ¶EèùóÐhò)8xÉ))8y2$ßë§ÏžEà àîæfµduzªÔ¯_"ãJNŒGbBœY;ï< ›µFbB’ã ö3wÞ,]±Ïv킯~‰•Ë¾Æ Àãì^Ã^ÿÃF|ºà «¶ÉõÏ8k¯ey~—åÚ )ÉuÊ>«ˆ­§áåîÐoW%¾æuád¯€“½OÖqÄÂÁ^ðrQjûórwÁÖÓ‰ÛØ¿BΜʼnÓV©³]P ’““qíšöµ¨èh¤¥§¡W÷î8rôX¾þCΜEû ¶V·¥Þ|ãu´kX"ãº÷ªø×®Š Ü¿{Gï{;wïEHèYü¸v zu5k ^:è×»:?ݱ¨%—+\ÿŒ³öúW–çwY®Í’\¨ì³Z€8v5.ÎŽÐhÓÑnŽ…›wsTbLGwm.ÎŽ8v5Ù`»înn˜<~¾\¼™™™ûÓh4X¿q†¼ü*ºõySg¾‡Ûw ïPªúû£zµª8z^ûÚñ§ðd»vèÔ±?žï/‚3gCÑ.0gƒ5fvìÜ…‰ÁÓеgœ9¬¬,|µl9¿ô2:uï…!/¿Š;wåç¨1ãðó/¿aÌø‰èÚ³^{s<.†‡K½¯{zÔ˜qX¿q^{s<žéÙ¯¼öο }_­Vcùê50dzô€y_,Âà—^)t UŸÄ„8øT®b²¿‚|*WAbBœÞ÷Ö¬[‡7F„‹³ñ'oΜ Õ;MæÎcK– ü´åW {u$º÷í¯]o~ØüÖþð#vïÝ]žÅ‹¿ÒÖ²tùJ 2 =û?y_,BjjºÑ:tqý3ÎÚë_Qæ·©}Š¡e­V«±bõ xqº÷íÏ,Ô[3×*ï¬ ¢b³`g÷èòD›šû ¬å íÏÎÎVû˜§!=Ÿ}~•*cæÍûY³nöî?€y³?ÁúoWÂÞÎã§¼¬¬Âm·j‹3¡ç´¿=qO¶o‡6­[!##ÿ]ÌÙ`"¯_GFFš6i¤íwÑ×KÑ£G7¬Z¶-š6ªU­Šùsç`ÓºïЧWOÌ™7QÑÑùƹ}Ç?˜0n,~úq=š5i„ S§#99Ùì÷ :qòfL‚ß6oD“&ñÞdz´ÓºlÕ·8~ò¾˜7ë¾] …Rè›1Fçqžô´4íÝî2\ÜܵÙåk/=Ñ7cдIc“mÄܾéÁ“ M“¹óØ’eóÃæŸð׎ðñûïaãºïг[7x¨TxeØPŒzåetëÒGöîÂôàÉ€…_ƒ¨è›X»j6¬Y…[·naÙªUFë(ˆëŸaÖ^ÿËç·9û}Ëzùªoqìä)|ñÙ\¬_³ ŽNŽëæº@å™Uo¢TkuÆa~¿y¦O‚Í?ÿ¢wåËÌÌĦÿû3ßFÚ¨êïß›‰””:r¬PÿíƒÚ"ôÜ9!‘‘° ah×6öö Ä‘cÇ!§Ï"°MkØØØh‡óÚkèÛ³'êÖ© GÇœàýQ; g¼#^ÿ*~Ú ?Ïàç yÓ¦ðõñÁäñoÁËS…]{öšý~A=»?‹õëÁÓÓ#^†qq¸ƒŒŒ üºu?ª‘ aIDATÞ>õêÔA??OoÞL.1·nCO3îuè×§5hPhšóæ±ì²Q«ÕX÷ÃFÌx; Ô‡¯ºwë'''½õ¥¤¦â?ÿÂ葯ÂÓÓ•|}1fô(8|Ädº¸þ•,Kæ·¹û”‚Ë##3¿HL?×*Ϭö95¼íž™{»œ&OGe c=ýÉ;$*!™YÙ¨ámgºýêÕ0lÈ ørñ|µ0ÿm1·ï ;;;ßÍ=NNNhÒ¤1®ßˆ*ÔVë–-‘š–†ëQQ¸{ïÔ«WWWÀÓO=‰Ÿ~þcG¿†³¡h_àzŸƒƒ}¡öâãã±s÷^œ»p ˆ{‡ #wï+•J4kÒ7nêÅÔûUñ󃓓RSÓpëöm¨54¨WOû¾¾gu qptBJR¢ô_)I‰pp,|àõñöÄÄÄÀ½¡ùÏëëN`Þ<–]6·nßAZZ5l`VM7¢£¡Ñh0ó£¡È«Ùêl¤¦æÿëL_º¸þfíõ°l~›»O)¸7â²µý%%§â¹–æ=–doow¦cɲåHIIѾ^µZÎ'Z††…i_Óh4¿tuôPU»ÜkÇOœÄSO´×¾®R©Ð¬ic¬Ýð#>ÿÛ½W¯Dêoͺõ8tä(âãã±fÝz¤¦¥â™NÍ~ß\.NNèÓ³æ/\„ÿ.^ÄÇñX»áG³‡wSyÀÕÍáagÌ&<ì \Ý<àfà/Àaƒ_@ƒõ1â7ñËÖßq-27¢oâ»÷àðQÓcsç±ìp*wwtêøÿíÝoheðozI{×?v`[íº6®u (ÃvÒù‡½Qp[Wݘvk†ÙÖÚÍJÅ?`Ù ÿ¼&íØt¬ &ˆB„½ADEÊ¡-Š[]е+[XÛd—Ú&õEú4O®w—KLi2¿8š]–K›<Íóíóüž»m8:p—ÆÇÒu Ÿ;·¼ª¢¢¢?þ4ŠÉÉËÐun·­û[ðÞàiü02‚h4ŠËSS¶Ä ÛŸ¹Õh@ê¯w:Ÿ)âq©þül ”«2 EÁPg9ŠÜÓËSV[ 0"wCå …ANôtwÁãN,ßèí9„ûîÝŠWúŽ Õw³3A }.‹?U7ÕÕAÓŠ† …mÜh4êh͵·ºÝÏu`ðÌØÛvß £±qåLã= 8qòöìkÃè/¿âä±~x<Ç÷§â¥žÃØR_Þ×^GÛÁvÌ--ÍËKþg»¢(¨òÖ" 9úÿmôô;އ¶7áùž^\¸p1é÷bÄögn5ÚÞëêgŠ ÿüÚ;Õ¬GØ(WeüZº®ãÉÁ+› £°PCª.wöó ˜ ‡qýºŽM·ªê(³¬x¿‘ø:ºðxsvíØžÖýÿÕÕ@;wïÅ·_~‚|û?A×uLøÿ@pö*×× ì–Ê3ú{Ââ’uX_³ññ>æ*¶?r±-ÐêK÷Z¿§¦iø¤³ç/éøügßÿ~ þ©Øšàš›=xðŽBìØ\†¯fºÄ2ïâØ6TU¦ô «iª¼µÎNc:pù1Ž­ˆ(P5”Ü´UÞ:—”ò}$[l$¤Ó({­Êå¼UUÅÖÛ=hðjˆDJ——læ¹\P'åi rîO¿~ÿ8¶Ôß+Þ?u­--)GUUx<—”"‰ð}$GØþHÈT[ ìä4@,þt]Ž¢(üå^#ÁÙ Î|ø޼ù6*Ê˰»¹5íLëX|)Ul$d²-Ъ2öéÆ>ßT²7€|*â5EˆÕ@ ¤ý­QV(,*~±ˆâ5aÿ Vÿ`Za· cÑpÛ¸Qî³ëã-û{'Ë8£KˆJ[ÄöDDD”+"HìãEŸo+Y€ˆJ_Å#pp`"""Ê rß.‡Û¾Þ¬ˆÒ8„!n‹'X°PXT|±úˆ|ÄÎá  ^CÁ3…­=yAôãóˆÕ8Èurˆ0f€SÉVaÃxâÄ +UÄC„(ºT ½T8¥E„‚åAÄÃCxiÂ,D˜² râ0K-b”Òý 8ADD”mŒ}yñ!6qÆI¹Âvá„Ý„U€Ã¼_.0@e³Ùqšj'”U „Kº-žÐ…Ä` î“G%“ÿGDDDkGIALeÌ6c-„|Œv#¢úÒ…Ä!$ö™M]0<e³Y¹&Â,<¬8y”Ì®Bž¦pî“‹1äi QÁJ""¢ìauZ9HÈE”rpH¹B`. We are also connecting to the application's ``activate`` event, where we will create the window. .. literalinclude:: examples/simple_example.py :lines: 7,9-10 In the ``on_activate`` callback we will create an empty window, and then display it using the :meth:`Gtk.Window.present` method. .. literalinclude:: examples/simple_example.py :lines: 18 Finally, we start the application using the :meth:`Gio.Application.run` method. Minimal Example without GtkApplication ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ In GTK 4, if you don't want to use :class:`Gtk.Application` you can use this replacement that will iterate the default main loop until all windows have been closed: .. attention:: Doing this is only useful for very specific use cases like tests. For app development you should always use :class:`Gtk.Application`. .. code:: python import gi gi.require_version('Gtk', '4.0') from gi.repository import GLib, Gtk win = Gtk.Window() win.present() while (len(Gtk.Window.get_toplevels()) > 0): GLib.MainContext.default().iteration(True) .. _extended-example: Extended Example ---------------- For something a little more useful, here's the PyGObject version of the classic "Hello World" program. .. image:: images/extended_example.png .. literalinclude:: examples/extended_example.py :linenos: This example differs from the simple example as we sub-class :class:`Gtk.ApplicationWindow` to define our own ``MyWindow`` class. .. seealso:: For more info about subclassing read :doc:`GObject Subclassing `. .. literalinclude:: examples/extended_example.py :lines: 7 In the class's constructor we have to call the constructor of the super class. In addition, we tell it to set the value of the property title to *Hello World*. Note that we are also receiving and passing ``**kargs``, so we can redirect other arguments passed on ``MyWindow`` construction to the base class. .. literalinclude:: examples/extended_example.py :lines: 8-9 The next three lines are used to create a button widget, connect to its ``clicked`` signal and add it as child to the top-level window. .. literalinclude:: examples/extended_example.py :lines: 11-13 Accordingly, the method `on_button_clicked` will be called if you click on the button. In this example we are using the method to print ``Hello World`` and calling the window :meth:`Gtk.Window.close` method to close the window. .. literalinclude:: examples/extended_example.py :lines: 15-17 The last block, outside of the class, is very similar to the simple example above, but instead of creating an instance of the generic :class:`Gtk.ApplicationWindow` or :class:`Gtk.Window` class, we create an instance of ``MyWindow``. .. _Getting Started with GTK: https://docs.gtk.org/gtk4/getting_started.html ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gtk4/layout-widgets.rst0000664000000000000000000002566615074674453021727 0ustar00rootroot.. currentmodule:: gi.repository Layout Containers ================= While many GUI toolkits require you to precisely place widgets in a window, using absolute positioning, GTK uses a different approach. Rather than specifying the position and size of each widget in the window, you can arrange your widgets in rows, columns, and/or tables. The size of your window can be determined automatically, based on the sizes of the widgets it contains. And the sizes of the widgets are, in turn, determined by the amount of text they contain, or the minimum and maximum sizes that you specify, and/or how you have requested that the available space should be shared between sets of widgets. You can perfect your layout by specifying padding distance and centering values for each of your widgets. GTK then uses all this information to resize and reposition everything sensibly and smoothly when the user manipulates the window. GTK widgets can parent other widgets hierarchically, and the way those widgets are displayed depend on the :class:`Gtk.LayoutManager` set in the :attr:`Gtk.Widget.props.layout_manager` property. For ease of use, GTK provides "pre made" containers that have default layout managers for different needs. Most of these containers implement the :class:`Gtk.Orientable` interface, it allows to set the widget orientation using :attr:`Gtk.Orientable.props.orientation`, you can either set :attr:`Gtk.Orientation.HORIZONTAL` or :attr:`Gtk.Orientation.VERTICAL`. Some containers / layout managers like :class:`Gtk.Box` allow you to influence the allocation of a child using the :attr:`Gtk.Widget.props.halign`, :attr:`Gtk.Widget.props.valign`, :attr:`Gtk.Widget.props.hexpand` and :attr:`Gtk.Widget.props.vexpand` properties. The main container widgets are: * :class:`Gtk.Box` * :class:`Gtk.CenterBox` * :class:`Gtk.HeaderBar` * :class:`Gtk.Grid` * :class:`Gtk.ListBox` * :class:`Gtk.FlowBox` * :class:`Gtk.Stack` * :class:`Gtk.Notebook` We are looking into each one in the following sections. Boxes ----- Boxes are invisible containers into which we can pack our widgets. When packing widgets into a horizontal box, the objects are inserted horizontally from left to right or right to left depending on whether :meth:`Gtk.Box.prepend` or :meth:`Gtk.Box.append` is used. You can also use the :meth:`Gtk.Box.insert_child_after` or :meth:`Gtk.Box.reorder_child_after` methods to insert a widget on a specific position. In a vertical box, widgets are packed from top to bottom or vice versa. You may use any combination of boxes inside or beside other boxes to create the desired effect. Example ^^^^^^^ Let's take a look at a slightly modified version of the :ref:`extended-example` with two buttons. .. image:: images/layout_box.png .. literalinclude:: examples/layout_box.py :linenos: First, we create a horizontally orientated box container where 6 pixels are placed between children. This box becomes the child of the top-level window. .. literalinclude:: examples/layout_box.py :lines: 11-12 Subsequently, we add two different buttons to the box container. .. literalinclude:: examples/layout_box.py :lines: 14-21 CenterBox --------- :class:`Gtk.CenterBox` arranges three children in a row or a column depending on its orientation, keeping the middle child centered as well as possible. To add children you use :meth:`Gtk.CenterBox.set_start_widget`, :meth:`Gtk.CenterBox.set_center_widget`, and :meth:`Gtk.CenterBox.set_end_widget`. Example ^^^^^^^ .. image:: images/layout_center.png .. literalinclude:: examples/layout_center.py :linenos: HeaderBar --------- A :class:`Gtk.HeaderBar` is similar to a horizontal :class:`Gtk.CenterBox`, it allows to place children at the start or the end. In addition, it allows a title to be displayed. The title will be centered with respect to the width of the box, even if the children at either side take up different amounts of space. :class:`Gtk.HeaderBar` is designed to be used as a window titlebar. This means that it can show typical window frame controls, such as minimize, maximize and close buttons, or the window icon. It is also draggable, meaning that you can move the parent window from it. You can use the :meth:`Gtk.Window.set_titlebar` method to set it as so. To add children you use :meth:`Gtk.HeaderBar.pack_start`, :meth:`Gtk.HeaderBar.pack_end`, and :meth:`Gtk.HeaderBar.set_title_widget` for the center one. By default if no ``title_widget`` is set it will have a label with the window's :attr:`Gtk.Window.props.title`. Example ^^^^^^^ .. image:: images/layout_headerbar.png .. literalinclude:: examples/layout_headerbar.py :linenos: Grid ---- :class:`Gtk.Grid` is a container which arranges its child widgets in rows and columns, but you do not need to specify the dimensions in the constructor. Children are added using :meth:`Gtk.Grid.attach`. They can span multiple rows or columns. The :meth:`Gtk.Grid.attach` method takes five parameters: 1. The ``child`` parameter is the :class:`Gtk.Widget` to add. 2. ``left`` is the column number to attach the left side of ``child`` to. 3. ``top`` indicates the row number to attach the top side of ``child`` to. 4. ``width`` and ``height`` indicate the number of columns that the ``child`` will span, and the number of rows that the ``child`` will span, respectively. It is also possible to add a child next to an existing child, using :meth:`Gtk.Grid.attach_next_to`, which also takes five parameters: 1. ``child`` is the :class:`Gtk.Widget` to add, as above. 2. ``sibling`` is an existing child widget of ``self`` (a :class:`Gtk.Grid` instance) or ``None``. The ``child`` widget will be placed next to ``sibling``, or if ``sibling`` is ``None``, at the beginning or end of the grid. 3. ``side`` is a :class:`Gtk.PositionType` indicating the side of ``sibling`` that ``child`` is positioned next to. 4. ``width`` and ``height`` indicate the number of columns and rows the ``child`` widget will span, respectively. Example ^^^^^^^ .. image:: images/layout_grid.png .. literalinclude:: examples/layout_grid.py :linenos: ListBox ------- A :class:`Gtk.ListBox` is a vertical container that contains :class:`Gtk.ListBoxRow` children. These rows can be dynamically sorted and filtered, and headers can be added dynamically depending on the row content. It also allows keyboard and mouse navigation and selection like a typical list. Although a :class:`Gtk.ListBox` must have only :class:`Gtk.ListBoxRow` children, you can add any kind of widget to it via :meth:`Gtk.ListBox.append` or :meth:`Gtk.ListBox.insert` and a :class:`Gtk.ListBoxRow` widget will automatically be inserted between the list and the widget. :class:`Gtk.ListBox` allows activating and selecting its children. Selection can be configured with :attr:`Gtk.ListBox.props.selection_mode`, selection modes are :attr:`Gtk.SelectionMode.NONE` (not selection at all), :attr:`Gtk.SelectionMode.SINGLE` (one or none elements can be selected), :attr:`Gtk.SelectionMode.BROWSE` (user can't deselect a currently selected element except by selecting another element) and :attr:`Gtk.SelectionMode.MULTIPLE` (any number of elements may be selected). It will emit the :func:`row-activated ` signal when a row is activated in any form, and :func:`row-selected ` when a row is selected. Example ^^^^^^^ .. image:: images/layout_listbox.png .. literalinclude:: examples/layout_listbox.py :linenos: FlowBox ------- A :class:`Gtk.FlowBox` is a container that positions child widgets in sequence according to its orientation. For instance, with the horizontal orientation, the widgets will be arranged from left to right, starting a new row under the previous row when necessary. Reducing the width in this case will require more rows, so a larger height will be requested. Likewise, with the vertical orientation, the widgets will be arranged from top to bottom, starting a new column to the right when necessary. Reducing the height will require more columns, so a larger width will be requested. :class:`Gtk.FlowBox` behaves similar to :class:`Gtk.ListBox`, we could say that is its "grid" counterpart. Just like :class:`Gtk.ListBox`, the children of a :class:`Gtk.FlowBox` can be dynamically sorted and filtered, and also activated and selected. Although a :class:`Gtk.FlowBox` must have only :class:`Gtk.FlowBoxChild` children, you can add any kind of widget to it via :meth:`Gtk.FlowBox.append` or :meth:`Gtk.FlowBox.insert`, and a :class:`Gtk.FlowBoxChild` widget will automatically be inserted between the box and the widget. Example ^^^^^^^ .. image:: images/layout_flowbox.png .. literalinclude:: examples/layout_flowbox.py :linenos: Stack and StackSwitcher ----------------------- A :class:`Gtk.Stack` is a container which only shows one of its children at a time. In contrast to :class:`Gtk.Notebook`, :class:`Gtk.Stack` does not provide a means for users to change the visible child. Instead, the :class:`Gtk.StackSwitcher` widget can be used with :class:`Gtk.Stack` to provide this functionality. Transitions between pages can be animated as slides or fades. This can be controlled with :attr:`Gtk.Stack.props.transition_type`. These animations respect the ``gtk-enable-animations`` setting. Transition speed can be adjusted with :attr:`Gtk.Stack.props.transition_duration`. The :class:`Gtk.StackSwitcher` widget acts as a controller for a :class:`Gtk.Stack`; it shows a row of buttons to switch between the various pages of the associated stack widget. :class:`Gtk.Stack` uses the auxiliary :class:`Gtk.StackPage` object. :class:`Gtk.Stack` will return a :class:`Gtk.StackPage` every time you add a new children, either with :meth:`Gtk.Stack.add_child`, :meth:`Gtk.Stack.add_named` or :meth:`Gtk.Stack.add_titled`. :class:`Gtk.StackPage` holds important properties for the stack's children, like the name, the title to display, or if the page needs attention, then this data can be used for example by :class:`Gtk.StackSwitcher`. It is possible to associate multiple :class:`Gtk.StackSwitcher` widgets with the same :class:`Gtk.Stack` widget. Example ^^^^^^^ .. image:: images/layout_stack.png .. literalinclude:: examples/layout_stack.py :linenos: Notebook -------- The :class:`Gtk.Notebook` is a container whose children are pages switched between using tabs. There are many configuration options for GtkNotebook. Among other things, you can choose on which edge the tabs appear (see :meth:`Gtk.Notebook.set_tab_pos`), whether, if there are too many tabs to fit the notebook should be made bigger or scrolling arrows added (see :meth:`Gtk.Notebook.set_scrollable`), and whether there will be a popup menu allowing the users to switch pages (see :meth:`Gtk.Notebook.popup_enable`, :meth:`Gtk.Notebook.popup_disable`). You can add children with :meth:`Gtk.Notebook.append_page`, it takes two widgets, the first is the widget to show as a page, and the second is the widget to show as the tab content. Example ^^^^^^^ .. image:: images/layout_notebook.png .. literalinclude:: examples/layout_notebook.py :linenos: ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gtk4/popovers.rst0000664000000000000000000000332615074674453020610 0ustar00rootroot.. currentmodule:: gi.repository Popovers ======== The :class:`Gtk.Popover` is an special kind of window used for displaying additional information and is often used with button menus and context menus. Popovers are attached to a parent widget and point to it. It's position can be configured with :attr:`Gtk.Popover.props.position`. :class:`Gtk.Popover` shows an arrow to visually connect where it points to, this can be disabled setting :attr:`Gtk.Popover.props.has_arrow` to ``False``. A :class:`Gtk.Popover` can be opened using :meth:`Gtk.Popover.popup` and hidden with :meth:`Gtk.Widget.hide`. GTK also provides :class:`Gtk.MenuButton`, it's an special button that can show and hide a :class:`Gtk.Popover` attached to it using :attr:`Gtk.MenuButton.props.popover`. Custom Popover -------------- A child widget can be added to a popover using :meth:`Gtk.Popover.set_child`. The parent of the popover can be set using :meth:`Gtk.Widget.set_parent`. Example ^^^^^^^ .. image:: images/popover.png .. literalinclude:: examples/popover.py :linenos: Menu Popover ------------ GTK also has :class:`Gtk.PopoverMenu`, it's a :class:`Gtk.Popover` subclass designed to display a menu model. A popover can be created from a :class:`Gio.MenuModel` using :meth:`Gtk.PopoverMenu.new_from_model` and can be changed after creation with :attr:`Gtk.PopoverMenu.props.menu_model`. :class:`Gtk.MenuButton` also can construct a :class:`Gtk.PopoverMenu` passing it a :class:`Gio.MenuModel` to :attr:`Gtk.MenuButton.props.menu_model`. .. seealso:: In :doc:`GTK Application ` we also showed examples of menu models. Example ^^^^^^^ .. image:: images/popover_menu.png .. literalinclude:: examples/popover_menu.py ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gtk4/textview.rst0000664000000000000000000001373215074674453020614 0ustar00rootroot.. currentmodule:: gi.repository Text View ========= The :class:`Gtk.TextView` widget can be used to display and edit large amounts of formatted text. Like the :class:`Gtk.ListView`, it has a model/view design. In this case the :class:`Gtk.TextBuffer` is the model which represents the text being edited. This allows two or more :class:`Gtk.TextView` widgets to share the same :class:`Gtk.TextBuffer`, and allows those text buffers to be displayed slightly differently. Or you could maintain several text buffers and choose to display each one at different times in the same :class:`Gtk.TextView` widget. .. seealso:: `Text Widget Overview`_ in the GTK documentation. The View -------- The :class:`Gtk.TextView` is the frontend with which the user can add, edit and delete textual data. They are commonly used to edit multiple lines of text. When creating a :class:`Gtk.TextView` it contains its own default :class:`Gtk.TextBuffer`, which is kept in the :attr:`Gtk.TextView.props.buffer` property. By default, text can be added, edited and removed from the :class:`Gtk.TextView`. You can disable this by changing :attr:`Gtk.TextView.props.editable`. If the text is not editable, you usually want to hide the text cursor with :attr:`Gtk.TextView.props.cursor_visible` as well. In some cases it may be useful to set the justification of the text with :attr:`Gtk.TextView.props.justification`. The text can be displayed at the left edge, (:attr:`Gtk.Justification.LEFT`), at the right edge (:attr:`Gtk.Justification.RIGHT`), centered (:attr:`Gtk.Justification.CENTER`), or distributed across the complete width (:attr:`Gtk.Justification.FILL`). Another default setting of the :class:`Gtk.TextView` widget is long lines of text will continue horizontally until a break is entered. To wrap the text and prevent it going off the edges of the screen set :attr:`Gtk.TextView.props.wrap_mode` similar to :doc:`/tutorials/gtk4/display-widgets/label`. The Model --------- The :class:`Gtk.TextBuffer` is the core of the :class:`Gtk.TextView` widget, and is used to hold whatever text is being displayed in the :class:`Gtk.TextView`. Setting and retrieving the contents is possible with :attr:`Gtk.TextBuffer.props.text`. However, most text manipulation is accomplished with *iterators*, represented by a :class:`Gtk.TextIter`. An iterator represents a position between two characters in the text buffer. Iterators are not valid indefinitely; whenever the buffer is modified in a way that affects the contents of the buffer, all outstanding iterators become invalid. Because of this, iterators can't be used to preserve positions across buffer modifications. To preserve a position, use :class:`Gtk.TextMark`. A text buffer contains two built-in marks; an "insert" mark (which is the position of the cursor) and the "selection_bound" mark. Both of them can be retrieved using :meth:`Gtk.TextBuffer.get_insert` and :meth:`Gtk.TextBuffer.get_selection_bound`, respectively. By default, the location of a :class:`Gtk.TextMark` is not shown. This can be changed by calling :meth:`Gtk.TextMark.set_visible`. Many methods exist to retrieve a :class:`Gtk.TextIter`. For instance, :meth:`Gtk.TextBuffer.get_start_iter` returns an iterator pointing to the first position in the text buffer, whereas :meth:`Gtk.TextBuffer.get_end_iter` returns an iterator pointing past the last valid character. Retrieving the bounds of the selected text can be achieved by calling :meth:`Gtk.TextBuffer.get_selection_bounds`. To insert text at a specific position use :meth:`Gtk.TextBuffer.insert`. Another useful method is :meth:`Gtk.TextBuffer.insert_at_cursor` which inserts text wherever the cursor may be currently positioned. To remove portions of the text buffer use :meth:`Gtk.TextBuffer.delete`. In addition, :class:`Gtk.TextIter` can be used to locate textual matches in the buffer using :meth:`Gtk.TextIter.forward_search` and :meth:`Gtk.TextIter.backward_search`. The start and end iters are used as the starting point of the search and move forwards/backwards depending on requirements. Tags ---- Text in a buffer can be marked with tags. A tag is an attribute that can be applied to some range of text. For example, a tag might be called "bold" and make the text inside the tag bold. However, the tag concept is more general than that; tags don't have to affect appearance. They can instead affect the behavior of mouse and key presses, "lock" a range of text so the user can't edit it, or countless other things. A tag is represented by a :class:`Gtk.TextTag` object. One :class:`Gtk.TextTag` can be applied to any number of text ranges in any number of buffers. Each tag is stored in a :class:`Gtk.TextTagTable`. A tag table defines a set of tags that can be used together. Each buffer has one tag table associated with it; only tags from that tag table can be used with the buffer. A single tag table can be shared between multiple buffers, however. To specify that some text in the buffer should have specific formatting, you must define a tag to hold that formatting information, and then apply that tag to the region of text using :meth:`Gtk.TextBuffer.create_tag` and :meth:`Gtk.TextBuffer.apply_tag`: .. code:: python tag = textbuffer.create_tag('orange_bg', background='orange') textbuffer.apply_tag(tag, start_iter, end_iter) The following are some of the common styles applied to text: * Background colour ("background" property) * Foreground colour ("foreground" property) * Underline ("underline" property) * Bold ("weight" property) * Italics ("style" property) * Strikethrough ("strikethrough" property) * Justification ("justification" property) * Size ("size" and "size-points" properties) * Text wrapping ("wrap-mode" property) You can also delete particular tags later using :meth:`Gtk.TextBuffer.remove_tag` or delete all tags in a given region by calling :meth:`Gtk.TextBuffer.remove_all_tags`. Example ------- .. image:: images/textview.png .. literalinclude:: examples/textview.py :linenos: .. _Text Widget Overview: https://docs.gtk.org/gtk4/section-text-widget.html ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/gtk4.rst0000664000000000000000000000063715074674453016735 0ustar00rootrootGTK4 ==== GTK is a library for creating graphical user interfaces. The main objects of GTK are "widgets" which are components such as buttons, text input, or windows. .. toctree:: :maxdepth: 2 :caption: Contents gtk4/introduction gtk4/basics gtk4/application gtk4/layout-widgets gtk4/controls gtk4/display-widgets gtk4/popovers gtk4/textview gtk4/clipboard gtk4/drag-and-drop ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/index.rst0000664000000000000000000000365615074674453017177 0ustar00rootroot========= Tutorials ========= These tutorials give an introduction to writing GTK/GNOME applications in Python. Prior to working through these tutorials, it is recommended that you have a reasonable grasp of the Python programming language. It is necessary for you to know how to create and run Python files, understand basic interpreter errors, and work with strings, integers, floats and boolean values. For the more advanced parts of these examples, good knowledge of lists and tuples will be needed. Although here we try to describe the most important classes and methods from GObject based libraries like GTK, it is not supposed to serve as an API reference. Please refer to the :ref:`api-references` list where you will find a detailed description of the API for each library. Also there's a `Python-specific reference `_ available. .. note:: Our tutorial list is still not as extensive as we would like, so if you have experience with PyGObject, contributing docs is a great way to help. Some areas that could use your help: libadwaita components, GLib and Gio features. .. _api-references: API References -------------- * `GObject `_ * `Gtk 4 `_ * `Gdk 4 `_ * `Gio `_ * `GLib `_ * `Adwaita `_ * `Python-specific references `_ Other Resources --------------- * The :devdocs:`GNOME Developer Documentation ` has some tutorials that include Python examples. .. toctree:: :maxdepth: 1 :hidden: :caption: Contents gobject gtk4 libadwaita gtk3 .. toctree:: :maxdepth: 1 :hidden: :caption: External Resources .. toctree:: :maxdepth: 1 :hidden: :caption: About ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/libadwaita/application.rst0000664000000000000000000000273215074674453022466 0ustar00rootroot.. currentmodule:: gi.repository Adwaita Application =================== :class:`Adw.Application` extends :class:`Gtk.Application` to ease some task related to creating applications for GNOME. .. seealso:: We previously touched :class:`Gtk.Application` in :doc:`this tutorial `. Adwaita also have :class:`Adw.ApplicationWindow`, it's a subclass of :class:`Gtk.ApplicationWindow` that provides the same "freform" features from :class:`Adw.Window`. .. note:: Using :class:`Adw.Application` will also call :func:`Adw.init` for you, this function initialize de library, making sure that translations, types, themes, icons and stylesheets needed by the library are set up properly. Stylesheets ----------- If you make use of :class:`Gio.Resource`, :class:`Adw.Application` will automatically load stylesheets located in the application's resource base path. This way you don't need to manually load stylesheets, and it will load the matching stylesheets depending on the system appearance settings exposed by :class:`Adw.StyleManager`. * ``style.css`` contains the base styles. * ``style-dark.css`` contains styles only used when :attr:`Adw.StyleManager.props.dark` is ``True``. * ``style-hc.css`` contains styles used when :attr:`Adw.StyleManager.props.high_contrast` is ``True``. * ``style-hc-dark.css`` contains styles used when :attr:`Adw.StyleManager.props.high_contrast` and :attr:`Adw.StyleManager.props.dark` are both ``True``. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/docs/tutorials/libadwaita.rst0000664000000000000000000000075315074674453020164 0ustar00rootrootAdwaita ======= `Adwaita `_ (``libadwaita``) offers application developers many widgets and objects to build GNOME applications scaling from desktop workstations to mobile phones. Adwaita is the library you must use if you want to build applications targeting the GNOME desktop and follow its `Human Interface Guidelines `_. .. toctree:: :maxdepth: 3 :caption: Contents libadwaita/application ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/__init__.py0000664000000000000000000001317215074674453015062 0ustar00rootroot# -*- Mode: Python; py-indent-offset: 4 -*- # vim: tabstop=4 shiftwidth=4 expandtab # # Copyright (C) 2005-2009 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 St, Fifth Floor, Boston, MA 02110-1301 # USA # 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 # noqa: F401 from ._gi import Repository from ._gi import PyGIDeprecationWarning # noqa: F401 from ._gi import PyGIWarning # noqa: F401 _versions = {} _overridesdir = os.path.join(os.path.dirname(__file__), 'overrides') # 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): version_list = tuple(map(int, version.split("."))) else: version_list = version if version_list > version_info: raise ValueError(( "pygobject's version %s required, and available version " "%s is not recent enough") % (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: raise ValueError('Namespace %s is already loaded with version %s' % (namespace, loaded_version)) if namespace in _versions and _versions[namespace] != version: raise ValueError('Namespace %s already requires version %s' % (namespace, _versions[namespace])) available_versions = repository.enumerate_versions(namespace) if not available_versions: raise ValueError('Namespace %s not available' % namespace) if version not in available_versions: raise ValueError('Namespace %s not available for version %s' % (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) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/_constants.py0000664000000000000000000000366115074674453015500 0ustar00rootroot# -*- 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 . 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 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/_error.py0000664000000000000000000000404215074674453014607 0ustar00rootroot# -*- Mode: Python; py-indent-offset: 4 -*- # vim: tabstop=4 shiftwidth=4 expandtab # # Copyright (C) 2014 Simon Feltman # # _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 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/_gtktemplate.py0000664000000000000000000002372115074674453016004 0ustar00rootroot# Copyright 2015 Dustin Spicuzza # 2018 Nikita Churaev # 2018 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, 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"] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/_option.py0000664000000000000000000003262515074674453014776 0ustar00rootroot# -*- Mode: Python -*- # pygobject - Python bindings for the GObject library # Copyright (C) 2006 Johannes Hoelzl # # glib/option.py: GOption command line parser # # 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 . """GOption command line parser Extends optparse to use the GOptionGroup, GOptionEntry and GOptionContext objects. So it is possible to use the gtk, gnome_program and gstreamer command line groups and contexts. Use this interface instead of the raw wrappers of GOptionContext and GOptionGroup in glib. """ import sys import optparse import warnings from optparse import OptParseError, OptionError, OptionValueError, \ BadOptionError, OptionConflictError from .module import get_introspection_module from gi import _gi, PyGIDeprecationWarning from gi._error import GError GLib = get_introspection_module('GLib') OPTION_CONTEXT_ERROR_QUARK = GLib.quark_to_string(GLib.option_error_quark()) __all__ = [ "OptParseError", "OptionError", "OptionValueError", "BadOptionError", "OptionConflictError", "Option", "OptionGroup", "OptionParser", "make_option", ] class Option(optparse.Option): """Represents a command line option To use the extended possibilities of the GOption API Option (and make_option) are extended with new types and attributes. Types: filename The supplied arguments are read as filename, GOption parses this type in with the GLib filename encoding. :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. For further help, see optparse.Option. """ TYPES = optparse.Option.TYPES + ( 'filename', ) ATTRS = optparse.Option.ATTRS + [ 'hidden', 'in_main', 'optional_arg', ] REMAINING = '--' + GLib.OPTION_REMAINING def __init__(self, *args, **kwargs): warnings.warn( "gi.repository.GLib.option.Option is deprecated, use gi.repository.GLib.OptionEntry instead", PyGIDeprecationWarning ) optparse.Option.__init__(self, *args, **kwargs) if not self._long_opts: raise ValueError("%s at least one long option name.") if len(self._long_opts) < len(self._short_opts): raise ValueError( "%s at least more long option names than short option names.") if not self.help: raise ValueError("%s needs a help message.", self._long_opts[0]) def _set_opt_string(self, opts): if self.REMAINING in opts: self._long_opts.append(self.REMAINING) optparse.Option._set_opt_string(self, opts) if len(self._short_opts) > len(self._long_opts): raise OptionError("goption.Option needs more long option names " "than short option names") def _to_goptionentries(self): flags = 0 if self.hidden: flags |= GLib.OptionFlags.HIDDEN if self.in_main: flags |= GLib.OptionFlags.IN_MAIN if self.takes_value(): if self.optional_arg: flags |= GLib.OptionFlags.OPTIONAL_ARG else: flags |= GLib.OptionFlags.NO_ARG if self.type == 'filename': flags |= GLib.OptionFlags.FILENAME for (long_name, short_name) in zip(self._long_opts, self._short_opts): 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:], b'\0', flags, self.help, self.metavar) class OptionGroup(optparse.OptionGroup): """A group of command line options. :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. For further help, see optparse.OptionGroup. """ def __init__(self, name, description, help_description="", option_list=None, defaults=None, translation_domain=None): warnings.warn( "gi.repository.GLib.option.OptionGroup is deprecated, use gi.repository.GLib.OptionContext instead", PyGIDeprecationWarning ) optparse.OptionContainer.__init__(self, Option, 'error', description) self.name = name self.parser = None self.help_description = help_description if defaults: self.defaults = defaults self.values = None self.translation_domain = translation_domain if option_list: for option in option_list: self.add_option(option) def _create_option_list(self): self.option_list = [] self._create_option_mappings() def _to_goptiongroup(self, parser): def callback(option_name, option_value, group): if option_name.startswith('--'): opt = self._long_opt[option_name] else: opt = self._short_opt[option_name] try: opt.process(option_name, option_value, self.values, parser) except OptionValueError: error = sys.exc_info()[1] gerror = GError(str(error)) gerror.domain = OPTION_CONTEXT_ERROR_QUARK gerror.code = GLib.OptionError.BAD_VALUE gerror.message = str(error) raise gerror group = _gi.OptionGroup(self.name, self.description, self.help_description, callback) if self.translation_domain: group.set_translation_domain(self.translation_domain) entries = [] for option in self.option_list: entries.extend(option._to_goptionentries()) group.add_entries(entries) return group def get_option_group(self, parser=None): """ Returns the corresponding GOptionGroup object. Can be used as parameter for gnome_program_init(), gtk_init(). """ self.set_values_to_defaults() return self._to_goptiongroup(parser) def set_values_to_defaults(self): for option in self.option_list: default = self.defaults.get(option.dest) if isinstance(default, str): opt_str = option.get_opt_string() self.defaults[option.dest] = option.check_value( opt_str, default) self.values = optparse.Values(self.defaults) class OptionParser(optparse.OptionParser): """Command line parser with GOption support. :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. .. 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(). Only glib.option.OptionGroup and glib.option.Option instances should be passed as groups and options. For further help, see optparse.OptionParser. """ def __init__(self, *args, **kwargs): warnings.warn( "gi.repository.GLib.option.OptionParser is deprecated, use gi.repository.GLib.OptionContext instead", PyGIDeprecationWarning ) if 'option_class' not in kwargs: kwargs['option_class'] = Option self.help_enabled = kwargs.pop('help_enabled', True) self.ignore_unknown_options = kwargs.pop('ignore_unknown_options', False) optparse.OptionParser.__init__(self, add_help_option=False, *args, **kwargs) def set_usage(self, usage): if usage is None: self.usage = '' elif usage.startswith("%prog"): self.usage = usage[len("%prog"):] else: self.usage = usage def _to_goptioncontext(self, values): if self.description: parameter_string = self.usage + " - " + self.description else: parameter_string = self.usage 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, _gi.OptionGroup): g_group = option_group else: g_group = option_group.get_option_group(self) context.add_group(g_group) def callback(option_name, option_value, group): if option_name.startswith('--'): opt = self._long_opt[option_name] else: opt = self._short_opt[option_name] opt.process(option_name, option_value, values, self) main_group = _gi.OptionGroup(None, None, None, callback) main_entries = [] for option in self.option_list: main_entries.extend(option._to_goptionentries()) main_group.add_entries(main_entries) context.set_main_group(main_group) return context def add_option_group(self, *args, **kwargs): if isinstance(args[0], str): optparse.OptionParser.add_option_group(self, OptionGroup(self, *args, **kwargs)) return elif len(args) == 1 and not kwargs: if isinstance(args[0], OptionGroup): if not args[0].parser: args[0].parser = self if args[0].parser is not self: raise ValueError("invalid OptionGroup (wrong parser)") if isinstance(args[0], _gi.OptionGroup): self.option_groups.append(args[0]) return optparse.OptionParser.add_option_group(self, *args, **kwargs) def _get_all_options(self): options = self.option_list[:] for group in self.option_groups: if isinstance(group, optparse.OptionGroup): options.extend(group.option_list) return options def _process_args(self, largs, rargs, values): context = self._to_goptioncontext(values) # _process_args() returns the remaining parameters in rargs. # The prepended program name is used to all g_set_prgname() # The program name is cut away so it doesn't appear in the result. rargs[:] = context.parse([sys.argv[0]] + rargs)[1:] def parse_args(self, args=None, values=None): try: options, args = optparse.OptionParser.parse_args( self, args, values) except GError: error = sys.exc_info()[1] if error.domain != OPTION_CONTEXT_ERROR_QUARK: raise if error.code == GLib.OptionError.BAD_VALUE: raise OptionValueError(error.message) elif error.code == GLib.OptionError.UNKNOWN_OPTION: raise BadOptionError(error.message) elif error.code == GLib.OptionError.FAILED: raise OptParseError(error.message) else: raise for group in self.option_groups: for key, value in group.values.__dict__.items(): options.ensure_value(key, value) return options, args make_option = Option ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/_ossighelper.py0000664000000000000000000002053215074674453016004 0ustar00rootroot# 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 . from __future__ import print_function import os import socket import signal import asyncio 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 PyOS_setsig = _gi.pyos_setsig # 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() class DummyEventLoop(): @classmethod @contextmanager def paused(cls): yield @classmethod @contextmanager def running(cls, quit_func): with wakeup_on_signal(): yield def get_event_loop(ctx): """Return the correct GLibEventLoop or a dummy that just registers the signal wakeup mechanism.""" # Try to use the running loop. If there is none, get the policy and # try getting one in the hope that this will give us an event loop for the # correct context. loop = asyncio._get_running_loop() if loop is None: try: loop = asyncio.get_event_loop_policy().get_event_loop_for_context(ctx) except: pass if loop and hasattr(loop, '_context'): if ctx is not None and hash(loop._context) == hash(ctx): return loop return DummyEventLoop ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/_propertyhelper.py0000664000000000000000000003352315074674453016550 0ustar00rootroot# -*- Mode: Python; py-indent-offset: 4 -*- # pygobject - Python bindings for the GObject library # Copyright (C) 2007 Johan Dahlin # # 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 # 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 . 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 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 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 :py:func:`property`: .. code-block:: python class AnotherObject(GObject.Object): value = 0 @GObject.Property def prop(self): 'Read only property.' return 1 @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 = { int: TYPE_INT, bool: TYPE_BOOLEAN, float: TYPE_DOUBLE, str: TYPE_STRING, object: TYPE_PYOBJECT, } _min_value_lookup = { TYPE_UINT: 0, TYPE_ULONG: 0, TYPE_UINT64: 0, # Remember that G_MINFLOAT and G_MINDOUBLE are something different. TYPE_FLOAT: -G_MAXFLOAT, TYPE_DOUBLE: -G_MAXDOUBLE, TYPE_INT: G_MININT, TYPE_LONG: G_MINLONG, TYPE_INT64: -2 ** 63, } _max_value_lookup = { TYPE_UINT: G_MAXUINT, TYPE_ULONG: G_MAXULONG, TYPE_INT64: 2 ** 63 - 1, TYPE_UINT64: 2 ** 64 - 1, TYPE_FLOAT: G_MAXFLOAT, TYPE_DOUBLE: G_MAXDOUBLE, TYPE_INT: G_MAXINT, TYPE_LONG: G_MAXLONG, } _default_lookup = { TYPE_INT: 0, TYPE_UINT: 0, TYPE_LONG: 0, TYPE_ULONG: 0, TYPE_INT64: 0, TYPE_UINT64: 0, TYPE_STRING: '', TYPE_FLOAT: 0.0, TYPE_DOUBLE: 0.0, } class __metaclass__(type): def __repr__(self): return "" def __init__(self, getter=None, setter=None, type=None, default=None, nick='', blurb='', flags=_gi.PARAM_READWRITE, minimum=None, maximum=None): self.name = None if type is None: type = object self.type = self._type_from_python(type) self.default = self._get_default(default) self._check_default() if not isinstance(nick, str): raise TypeError("nick must be a string") self.nick = nick 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 # we don't want the lengthy Property class documentation showing up # on instances. self.__doc__ = blurb self.flags = flags # Call after setting blurb for potential __doc__ usage. if getter and not setter: setter = self._readonly_setter elif setter and not getter: getter = self._writeonly_getter elif not setter and not getter: getter = self._default_getter setter = self._default_setter self.getter(getter) # do not call self.setter() here, as this defines the property name # already self.fset = setter if minimum is not None: if minimum < self._get_minimum(): raise TypeError( "Minimum for type %s cannot be lower than %d" % (self.type, self._get_minimum())) else: minimum = self._get_minimum() self.minimum = minimum if maximum is not None: if maximum > self._get_maximum(): raise TypeError( "Maximum for type %s cannot be higher than %d" % (self.type, self._get_maximum())) else: maximum = self._get_maximum() self.maximum = maximum self._exc = None def __repr__(self): return '' % ( self.name or '(uninitialized)', self.type.name) def __get__(self, instance, klass): if instance is None: return self self._exc = None value = self.fget(instance) if self._exc: exc = self._exc self._exc = None raise exc return value def __set__(self, instance, value): if instance is None: raise TypeError self._exc = None instance.set_property(self.name, value) if self._exc: exc = self._exc self._exc = None raise exc def __call__(self, fget): """Allows application of the getter along with init arguments.""" return self.getter(fget) def getter(self, fget): """Set the getter function to fget. For use as a decorator.""" if fget.__doc__: # Always clobber docstring and blurb with the getter docstring. self.blurb = fget.__doc__ self.__doc__ = fget.__doc__ self.fget = fget return self def setter(self, fset): """Set the setter function to fset. For use as a decorator.""" self.fset = fset # with a setter decorator, we must ignore the name of the method in # install_properties, as this does not need to be a valid property name # and does not define the property name. So set the name here. if not self.name: self.name = self.fget.__name__ return self def _type_from_python(self, type_): if type_ in self._type_from_pytype_lookup: return self._type_from_pytype_lookup[type_] elif (isinstance(type_, type) and 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, TYPE_ULONG, TYPE_INT64, TYPE_UINT64, TYPE_FLOAT, TYPE_DOUBLE, TYPE_POINTER, TYPE_BOXED, TYPE_PARAM, TYPE_OBJECT, TYPE_STRING, TYPE_PYOBJECT, TYPE_GTYPE, TYPE_STRV, TYPE_VARIANT): return type_ else: raise TypeError("Unsupported type: %r" % (type_,)) def _get_default(self, default): if default is not None: return default return self._default_lookup.get(self.type, None) def _check_default(self): ptype = self.type default = self.default if (ptype == TYPE_BOOLEAN and (default not in (True, False))): raise TypeError( "default must be True or False, not %r" % (default,)) elif ptype == TYPE_PYOBJECT: if default is not None: raise TypeError("object types does not have default values") elif ptype == TYPE_GTYPE: if default is not None: raise TypeError("GType types does not have default values") elif ptype.is_a(TYPE_ENUM): if default is None: raise TypeError("enum properties needs a default value") elif not _gi.GType(default).is_a(ptype): raise TypeError("enum value %s must be an instance of %r" % (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 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 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)) def _get_minimum(self): return self._min_value_lookup.get(self.type, None) def _get_maximum(self): return self._max_value_lookup.get(self.type, None) # # Getter and Setter # def _default_setter(self, instance, value): setattr(instance, '_property_helper_' + self.name, value) def _default_getter(self, instance): return getattr(instance, '_property_helper_' + self.name, self.default) def _readonly_setter(self, instance, value): self._exc = TypeError("%s property of %s is read-only" % ( self.name, type(instance).__name__)) def _writeonly_getter(self, instance): self._exc = TypeError("%s property of %s is write-only" % ( self.name, type(instance).__name__)) # # Public API # def get_pspec_args(self): ptype = self.type if ptype in (TYPE_INT, TYPE_UINT, TYPE_LONG, TYPE_ULONG, TYPE_INT64, TYPE_UINT64, TYPE_FLOAT, TYPE_DOUBLE): args = self.minimum, self.maximum, self.default elif (ptype == TYPE_STRING or ptype == TYPE_BOOLEAN or ptype.is_a(TYPE_ENUM) or ptype.is_a(TYPE_FLAGS) or ptype.is_a(TYPE_VARIANT)): args = (self.default,) elif ptype in (TYPE_PYOBJECT, TYPE_GTYPE): args = () elif ptype.is_a(TYPE_OBJECT) or ptype.is_a(TYPE_BOXED): args = () else: raise NotImplementedError(ptype) return (self.type, self.nick, self.blurb) + args + (self.flags,) def install_properties(cls): """ Scans the given class for instances of Property and merges them into the classes __gproperties__ dict if it exists or adds it if not. """ gproperties = cls.__dict__.get('__gproperties__', {}) props = [] for name, prop in cls.__dict__.items(): if isinstance(prop, Property): # not same as the built-in # if a property was defined with a decorator, it may already have # a name; if it was defined with an assignment (prop = Property(...)) # we set the property's name to the member name if not prop.name: prop.name = name # we will encounter the same property multiple times in case of # custom setter methods if prop.name in gproperties: if gproperties[prop.name] == prop.get_pspec_args(): continue raise ValueError('Property %s was already found in __gproperties__' % prop.name) gproperties[prop.name] = prop.get_pspec_args() props.append(prop) if not props: return cls.__gproperties__ = gproperties if 'do_get_property' in cls.__dict__ or 'do_set_property' in cls.__dict__: for prop in props: if prop.fget != prop._default_getter or prop.fset != prop._default_setter: raise TypeError( "GObject subclass %r defines do_get/set_property" " and it also uses a property with a custom setter" " or getter. This is not allowed" % (cls.__name__,)) def obj_get_property(self, pspec): name = pspec.name.replace('-', '_') return getattr(self, name, None) cls.do_get_property = obj_get_property def obj_set_property(self, pspec, value): name = pspec.name.replace('-', '_') prop = getattr(cls, name, None) if prop: prop.fset(self, value) cls.do_set_property = obj_set_property ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/_signalhelper.py0000664000000000000000000002212715074674453016137 0ustar00rootroot# -*- Mode: Python; py-indent-offset: 4 -*- # pygobject - Python bindings for the GObject library # Copyright (C) 2012 Simon Feltman # # 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 # 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 . from . import _gi class Signal(str): """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): """ Temporary binding object which can be used for connecting signals without specifying the signal name string to connect. """ def __new__(cls, name, *args, **kargs): return str.__new__(cls, name) def __init__(self, signal, gobj): str.__init__(self) self.signal = signal self.gobj = gobj def __repr__(self): return 'BoundSignal("%s")' % self def __call__(self, *args, **kargs): """Call the signals closure.""" return self.signal.func(self.gobj, *args, **kargs) def connect(self, callback, *args, **kargs): """Same as GObject.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.Object.connect except there is no need to specify the signal name. In addition concats "::" to the signal name when connecting; for use with notifications like "notify" when a property changes. """ return self.gobj.connect(self + '::' + detail, callback, *args, **kargs) def disconnect(self, handler_id): """Same as GObject.Object.disconnect.""" self.gobj.disconnect(handler_id) def emit(self, *args, **kargs): """Same as GObject.Object.emit except there is no need to specify the signal name.""" return self.gobj.emit(str(self), *args, **kargs) def __new__(cls, name='', *args, **kargs): if callable(name): name = name.__name__ return str.__new__(cls, name) def __init__(self, name='', func=None, flags=_gi.SIGNAL_RUN_FIRST, return_type=None, arg_types=None, doc='', accumulator=None, accu_data=None): if func is None and callable(name): func = name if func and not doc: doc = func.__doc__ str.__init__(self) if func and not (return_type or arg_types): return_type, arg_types = get_signal_annotations(func) if arg_types is None: arg_types = tuple() self.func = func self.flags = flags self.return_type = return_type self.arg_types = arg_types self.__doc__ = doc self.accumulator = accumulator self.accu_data = accu_data def __get__(self, instance, owner=None): """Returns a BoundSignal when accessed on an object instance.""" if instance is None: return self return self.BoundSignal(self, instance) def __call__(self, obj, *args, **kargs): """Allows for instantiated Signals to be used as a decorator or calling of the underlying signal method.""" # If obj is a GObject, than we call this signal as a closure otherwise # it is used as a re-application of a decorator. if isinstance(obj, _gi.GObject): self.func(obj, *args, **kargs) else: # If self is already an allocated name, use it otherwise create a new named # signal using the closure name as the name. if str(self): name = str(self) else: name = obj.__name__ # Return a new value of this type since it is based on an immutable string. return type(self)(name=name, func=obj, flags=self.flags, return_type=self.return_type, arg_types=self.arg_types, doc=self.__doc__, accumulator=self.accumulator, accu_data=self.accu_data) def copy(self, newName=None): """Returns a renamed copy of the Signal.""" return type(self)(name=newName, func=self.func, flags=self.flags, return_type=self.return_type, arg_types=self.arg_types, doc=self.__doc__, accumulator=self.accumulator, accu_data=self.accu_data) def get_signal_args(self): """Returns a tuple of: (flags, return_type, arg_types, accumulator, accu_data)""" return (self.flags, self.return_type, self.arg_types, self.accumulator, self.accu_data) class SignalOverride(Signal): """Specialized sub-class of Signal which can be used as a decorator for overriding existing signals on GObjects. :Example: .. code-block:: python class MyWidget(Gtk.Widget): @GObject.SignalOverride def configure_event(self): pass """ def get_signal_args(self): """Returns the string 'override'.""" return 'override' def get_signal_annotations(func): """Attempt pulling python 3 function annotations off of 'func' for use as a signals type information. Returns an ordered nested tuple of (return_type, (arg_type1, arg_type2, ...)). If the given function does not have annotations then (None, tuple()) is returned. """ arg_types = tuple() return_type = None if hasattr(func, '__annotations__'): # 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) if 'return' in spec.annotations: return_type = spec.annotations['return'] return return_type, arg_types def install_signals(cls): """Adds Signal instances on a GObject derived class into the '__gsignals__' dictionary to be picked up and registered as real GObject signals. """ gsignals = cls.__dict__.get('__gsignals__', {}) newsignals = {} for name, signal in cls.__dict__.items(): if isinstance(signal, Signal): signalName = str(signal) # Fixup a signal which is unnamed by using the class variable name. # Since Signal is based on string which immutable, # we must copy and replace the class variable. if not signalName: signalName = name signal = signal.copy(name) setattr(cls, name, signal) if signalName in gsignals: raise ValueError('Signal "%s" has already been registered.' % name) newsignals[signalName] = signal gsignals[signalName] = signal.get_signal_args() cls.__gsignals__ = gsignals # Setup signal closures by adding the specially named # method to the class in the form of "do_". for name, signal in newsignals.items(): if signal.func is not None: funcName = 'do_' + name.replace('-', '_') if not hasattr(cls, funcName): setattr(cls, funcName, signal.func) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/docstring.py0000664000000000000000000001510615074674453015316 0ustar00rootroot# -*- Mode: Python; py-indent-offset: 4 -*- # vim: tabstop=4 shiftwidth=4 expandtab # # Copyright (C) 2013 Simon Feltman # # docstring.py: documentation string generator for gi. # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 # USA from ._gi import \ VFuncInfo, \ FunctionInfo, \ CallableInfo, \ ObjectInfo, \ StructInfo, \ Direction, \ TypeTag #: Module storage for currently registered doc string generator function. _generate_doc_string_func = None def set_doc_string_generator(func): """Set doc string generator function :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): """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. """ return _generate_doc_string_func(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'] 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 += '=' in_args_strs.append(argstr) in_args_str = ', '.join(in_args_strs) # 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: 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_doc_dispatch) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/events.py0000664000000000000000000006071215074674453014631 0ustar00rootroot# -*- Mode: Python; py-indent-offset: 4 -*- # pygobject - Python bindings for the GObject library # Copyright (C) 2021 Benjamin Berg # # gi/asyncio.py: GObject asyncio integration # # 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 . __all__ = ['GLibEventLoopPolicy', 'GLibEventLoop'] import sys import asyncio from asyncio import coroutines import signal import threading import selectors import weakref import warnings from collections.abc import Mapping from contextlib import contextmanager from . import _ossighelper from gi.repository import GLib try: g_main_loop_run = super(GLib.MainLoop, GLib.MainLoop).run except AttributeError: g_main_loop_run = GLib.MainLoop.run class _GLibEventLoopMixin: """ Base functionally required for both proactor and selector. The proactor/selector is always available through _selector, and we assume it has the following extra functionality that we provide: * _source: the GSource subclass * _dispatching: boolean whether it is dispatching currently * attach/detach: add/remove the GSource from the main context In principle, we simply override run_forever to call into GLib, with the assumption that a GSource is registered which will then call back into the python mainloop _run_once handler when needed. This in turn calls self._selector.select(), which means we just need to make sure to return our already prepared events at that point. """ def __init__(self, main_context): # A mainloop in case we want to run our context assert main_context is not None self._context = main_context self._main_loop = GLib.MainLoop.new(self._context, False) self._quit_funcs = [] @contextmanager def paused(self): """This context manager ensures the EventLoop is *not* being iterated. It purely exist to handle the case where python code iterates the main context more gracefully.""" # Nothing to do if we are not running or dispatched by ourselves if not self.is_running() or self._selector._source._dispatching: yield return try: self._selector.detach() yield finally: self._selector.attach() @contextmanager def running(self, quit_func): """This context manager ensures the EventLoop is marked as running while other API is iterating its main context. The passed quit function is used to stop all recursion levels when stop() is called. """ assert self._context.acquire() self._quit_funcs.append(quit_func) # Nested main context iteration (by using glib API) if self.is_running(): try: yield finally: self._context.release() self._quit_funcs.pop() # Stop recursively if self._stopping: self._quit_funcs[-1]() return # Outermost nesting self._check_closed() self._set_coroutine_origin_tracking(self._debug) self._thread_id = threading.get_ident() old_agen_hooks = sys.get_asyncgen_hooks() sys.set_asyncgen_hooks(firstiter=self._asyncgen_firstiter_hook, finalizer=self._asyncgen_finalizer_hook) try: asyncio._set_running_loop(self) assert not self._selector._source._dispatching self._selector.attach() yield finally: self._selector.detach() self._context.release() self._thread_id = None asyncio._set_running_loop(None) try: self._set_coroutine_origin_tracking(False) except AttributeError: pass sys.set_asyncgen_hooks(*old_agen_hooks) self._quit_funcs.pop() assert len(self._quit_funcs) == 0 self._stopping = False def time(self): return GLib.get_monotonic_time() / 1000000 def _get_timeout_ms(self): if not self.is_running(): warnings.warn('GLibEventLoop is iterated without being marked as running. Missing override or invalid use of existing API!', RuntimeWarning) if self._stopping is True: warnings.warn('GLibEventLoop is not stopping properly. Missing override or invalid use of existing API!', RuntimeWarning) if self._ready: return 0 if self._scheduled: # The time is floor'ed here. # Python dispatches everything ready within the next _clock_resolution. timeout = int((self._scheduled[0]._when - self.time()) * 1000) return timeout if timeout >= 0 else 0 return -1 def stop(self): # Simply quit the mainloop self._stopping = True if self._quit_funcs: self._quit_funcs[-1]() def __repr__(self): return ( f'<{self.__class__.__name__} running={self.is_running()} ' f'closed={self.is_closed()} debug={self.get_debug()} ' f'ctx=0x{hash(self._context):X} loop=0x{hash(self._main_loop):X}>' ) class _GLibEventLoopRunMixin: # This class exists so we don't need to copy the ProactorEventLoop.run_forever, # instead, we change the MRO using a metaclass, so that super() sees this class # when called in ProactorEventLoop.run_forever. def run_forever(self): # NOTE: self._check_running was only added in 3.8 (with a typo in 3.7) if self.is_running(): raise RuntimeError('This event loop is already running') with _ossighelper.register_sigint_fallback(self._main_loop.quit): with self.running(self._main_loop.quit): g_main_loop_run(self._main_loop) class _SourceBase(GLib.Source): """Common Source functionality for both unix and win32""" def __init__(self, selector): super().__init__() self._dispatching = False # It is *not* safe to run the *python* part of the mainloop recursively. # This error must be caught further up in the chain, otherwise the # mainloop will be blocking without an obvious reason. self.set_can_recurse(False) self.set_name('python asyncio integration') self._selector = selector # NOTE: Avoid loop -> selector -> source -> loop reference cycle, # we need the source to be destroyed *after* the selector. Otherwise # we need a flag to deal with FDs being unregistered after __del__ has # been called on the source. self._loop = weakref.ref(selector._loop) self._ready = [] def dispatch(self, callback, args): # Now, wag the dog by its tail self._dispatching = True try: self._loop()._run_once() finally: self._dispatching = False return GLib.SOURCE_CONTINUE def _get_ready(self): if not self._dispatching: raise RuntimeError("gi.asyncio.Selector.select only works while it is dispatching!") ready = self._ready self._ready = [] return ready class _SelectorMixin: """A Mixin for common functionality of the Selector and Proactor.""" def __init__(self, context, loop): super().__init__() self._context = context self._loop = loop self._fd_to_key = {} self._source = _Source(self) def close(self): if self._source: self._source.destroy() self._source = None super().close() def select(self, timeout=None): return self._source._get_ready() def _real_select(self, timeout=None): return super().select(timeout) if sys.platform != 'win32': class GLibEventLoop(_GLibEventLoopMixin, _GLibEventLoopRunMixin, asyncio.SelectorEventLoop): """An asyncio event loop that runs the python mainloop inside GLib. Based on the asyncio.SelectorEventLoop""" _GLIB_SIGNALS = {signal.SIGHUP, signal.SIGINT, signal.SIGTERM, signal.SIGUSR1, signal.SIGUSR2, signal.SIGWINCH} # This is based on the selector event loop, but never actually runs select() # in the strict sense. # We use the selector to register all FDs with the main context using our # own GSource. For python timeouts/idle equivalent, we directly query them # from the context by providing the _get_timeout_ms function that the # GSource uses. This in turn accesses _ready and _scheduled to calculate # the timeout and whether python can dispatch anything non-FD based yet. # # The Selector select() method simply returns the information we already # collected. # # The rest is done by the mixin which overrides run_forever to simply # iterate the main context. def __init__(self, main_context): _GLibEventLoopMixin.__init__(self, main_context) # _UnixSelectorEventLoop uses _signal_handlers, we could do the same, # with the difference that close() would clean up the handlers for us. self.__signal_handlers = {} selector = _Selector(self._context, self) asyncio.SelectorEventLoop.__init__(self, selector) # Used by run_once to not busy loop if the timeout is floor'ed to zero self._clock_resolution = 1e-3 def add_signal_handler(self, sig, callback, *args): """Add a handler for UNIX signal""" if (coroutines.iscoroutine(callback) or coroutines.iscoroutinefunction(callback)): raise TypeError("coroutines cannot be used " "with add_signal_handler()") self._check_closed() # Can be useful while testing failures # assert sig != signal.SIGALRM if sig not in self._GLIB_SIGNALS: return super().add_signal_handler(sig, callback, *args) # Pure python demands that there is only one signal handler source, _, _ = self.__signal_handlers.get(sig, (None, None, None)) if source: source.destroy() # Setup a new source with a higher priority than our main one source = GLib.unix_signal_source_new(sig) source.set_name(f"asyncio signal watch for {sig}") source.set_priority(GLib.PRIORITY_HIGH) source.attach(self._context) source.set_callback(self._signal_cb, sig) self.__signal_handlers[sig] = (source, callback, args) del source def remove_signal_handler(self, sig): if sig not in self._GLIB_SIGNALS: return super().remove_signal_handler(sig) try: source, _, _ = self.__signal_handlers[sig] del self.__signal_handlers[sig] # Really unref the underlying GSource so that GLib resets the signal handler source.destroy() source._clear_boxed() # GLib does not restore the original signal handler. # Try to restore the python handler for SIGINT, this makes # Ctrl+C work after the mainloop has quit. if sig == signal.SIGINT and _ossighelper.PyOS_getsig(signal.SIGINT) == 0: if _ossighelper.startup_sigint_ptr > 0: _ossighelper.PyOS_setsig(signal.SIGINT, _ossighelper.startup_sigint_ptr) return True except KeyError: return False def _signal_cb(self, sig): source, cb, args = self.__signal_handlers.get(sig) # Pass over to python mainloop self.call_soon(cb, *args) def close(self): super().close() for s in list(self.__signal_handlers): self.remove_signal_handler(s) def _fileobj_to_fd(fileobj): # Note: SelectorEventloop should only be passing FDs if isinstance(fileobj, int): return fileobj else: return fileobj.fileno() class _Source(_SourceBase): def prepare(self): timeout = self._loop()._get_timeout_ms() # NOTE: Always return False, FDs are queried in check and the timeout # needs to be rechecked anyway. return False, timeout def check(self): ready = [] for key in self._selector._fd_to_key.values(): condition = self.query_unix_fd(key._tag) events = 0 # ERR/HUP/NVAL trigger both read/write (PRI cannot happen) if condition & ~GLib.IOCondition.OUT: events |= selectors.EVENT_READ if condition & ~GLib.IOCondition.IN: events |= selectors.EVENT_WRITE if events: ready.append((key, events)) self._ready = ready timeout = self._loop()._get_timeout_ms() if timeout == 0: return True return bool(ready) class _SelectorKey(selectors.SelectorKey): # Subclass to attach _tag pass class _FileObjectMapping(Mapping): def __init__(self, fd_dict): self.fd_dict = fd_dict def __len__(self): return len(self.fd_dict) def get(self, fileobj, default=None): fd = _fileobj_to_fd(fileobj) return self.fd_dict.get(fd, default) def __getitem__(self, fileobj): value = self.get(fileobj) if value is None: raise KeyError("{!r} is not registered".format(fileobj)) return value def __iter__(self): return iter(self.fd_dict) class _Selector(_SelectorMixin, selectors.BaseSelector): """A Selector for gi.events.GLibEventLoop registering python IO with GLib.""" def __init__(self, context, loop): super().__init__(context, loop) self._map = _FileObjectMapping(self._fd_to_key) def attach(self): self._source.attach(self._loop._context) def detach(self): self._source.destroy() self._source = _Source(self) # re-register the keys with the new source for key in self._fd_to_key.values(): self._register_key(key) def _register_key(self, key): condition = GLib.IOCondition(0) if key.events & selectors.EVENT_READ: condition |= GLib.IOCondition.IN if key.events & selectors.EVENT_WRITE: condition |= GLib.IOCondition.OUT key._tag = self._source.add_unix_fd(key.fd, condition) def register(self, fileobj, events, data=None): if (not events) or (events & ~(selectors.EVENT_READ | selectors.EVENT_WRITE)): raise ValueError("Invalid events: {!r}".format(events)) fd = _fileobj_to_fd(fileobj) if fd in self._fd_to_key: raise KeyError("{!r} (FD {}) is already registered" .format(fileobj, fd)) key = _SelectorKey(fileobj, fd, events, data) self._register_key(key) self._fd_to_key[fd] = key return key def unregister(self, fileobj): # NOTE: may be called after __del__ has been called. fd = _fileobj_to_fd(fileobj) key = self._fd_to_key[fd] if self._source: self._source.remove_unix_fd(key._tag) del self._fd_to_key[fd] return key # We could override modify, but it is only slightly when the "events" change. def get_key(self, fileobj): return self._map[fileobj] def get_map(self): """Return a mapping of file objects or file descriptors to selector keys.""" return self._map else: class _PushRunMixinBackMeta(type): # This metaclass changes the MRO so that when run_forever is called, it # first calls asyncio.ProactorEventLoop and then chains into # _GLibEventLoopRunMixin.run_forever using super(). # The alternative would be to copy asyncio.ProactorEventLoop.run_forever def mro(cls): mro = type.mro(cls) idx = mro.index(_GLibEventLoopRunMixin) return [*mro[:idx], mro[idx + 1], mro[idx], *mro[idx + 2:]] class GLibEventLoop(_GLibEventLoopMixin, _GLibEventLoopRunMixin, asyncio.ProactorEventLoop, metaclass=_PushRunMixinBackMeta): """An asyncio event loop that runs the python mainloop inside GLib. Based on the asyncio.WindowsProactorEventLoopPolicy""" # This is based on the Windows ProactorEventLoop def __init__(self, main_context): _GLibEventLoopMixin.__init__(self, main_context) proactor = _Proactor(self._context, self) # Sets both self._proactor and self._selector to the proactor asyncio.ProactorEventLoop.__init__(self, proactor) # Used by run_once to not busy loop if the timeout is floor'ed to zero self._clock_resolution = 1e-3 class _Source(_SourceBase): def __init__(self, proactor): self._proactor = proactor super().__init__(proactor) # None denotes it is disabled (and will also not handle timeouts) self._poll_fd = None def enable(self): assert self._poll_fd is None self._poll_fd = GLib.PollFD(self._proactor._iocp, GLib.IO_IN) self.add_poll(self._poll_fd) def disable(self): self.remove_poll(self._poll_fd) self._poll_fd = None def prepare(self): # Disabled, do not handle timeouts either if self._poll_fd is None: return False, -1 timeout = self._loop()._get_timeout_ms() return bool(self._ready), timeout def check(self): if self._poll_fd is None: return False if self._poll_fd.revents: self._ready.extend(self._proactor._real_select(0)) if self._ready: return True if self._loop()._get_timeout_ms() == 0: return True return False class _Proactor(_SelectorMixin, asyncio.IocpProactor): """A Proactor for gi.events.GLibEventLoop registering python IO with GLib.""" def __init__(self, context, loop): super().__init__(context, loop) # We always use the same Source on windows, it disables itself self._source = _Source(self) self._source.attach(context) def attach(self): self._source.enable() def detach(self): self._source.disable() class GLibEventLoopPolicy(asyncio.AbstractEventLoopPolicy): """An asyncio event loop policy that runs the GLib main loop. The policy allows creating a new EventLoop for threads other than the main thread. For the main thread, you can use get_event_loop() to retrieve the correct mainloop and run it. Note that, unlike GLib, python does not support running the EventLoop recursively. You should never iterate the GLib.MainContext from within the python EventLoop as doing so prevents asyncio events from being dispatched. As such, do not use API such as GLib.MainLoop.run or Gtk.Dialog.run. Instead use the proper asynchronous patterns to prevent entirely blocking asyncio. """ def __init__(self): self._loops = {} self._child_watcher = None def get_event_loop(self): """Get the event loop for the current context. Returns an event loop object for the thread default GLib.MainContext or in case of the main thread for the default GLib.MainContext. An exception will be thrown if there is no GLib.MainContext for the current thread. In that case, using new_event_loop() will create a new main context and main loop which can subsequently attached to the thread by calling set_event_loop(). Returns a new GLibEventLoop or raises an exception.""" # Get the thread default main context ctx = GLib.MainContext.get_thread_default() # If there is none, and we are on the main thread, then use the default context if ctx is None and threading.current_thread() is threading.main_thread(): ctx = GLib.MainContext.default() # We do not create a main context implicitly; # we create a mainloop for an existing context though if ctx is None: raise RuntimeError('There is no main context set for thread %r.' % threading.current_thread().name) return self.get_event_loop_for_context(ctx) def get_event_loop_for_context(self, ctx): """Get the event loop for a specific context.""" # Note: We cannot attach it to ctx, as getting the default will always # return a new python wrapper. But, we can use hash() as that returns # the pointer to the C structure. try: loop = self._loops[hash(ctx)] if not loop.is_closed(): return loop except KeyError: pass self._loops[hash(ctx)] = GLibEventLoop(ctx) if self._child_watcher and ctx == GLib.MainContext.default(): self._child_watcher.attach_loop(self.get_event_loop()) return self._loops[hash(ctx)] def set_event_loop(self, loop): """Set the event loop for the current context (python thread) to loop. This is only permitted if the thread has no thread default main context with the main thread using the default main context. """ # Only accept glib event loops, otherwise things will just mess up assert loop is None or isinstance(loop, GLibEventLoop) ctx = ctx_td = GLib.MainContext.get_thread_default() if ctx is None and threading.current_thread() is threading.main_thread(): ctx = GLib.MainContext.default() if loop is None: # We do permit unsetting the current loop/context old = self._loops.pop(hash(ctx), None) if old: if hash(old._context) != hash(ctx): warnings.warn('GMainContext was changed unknowingly by asyncio integration!', RuntimeWarning) if ctx_td: GLib.MainContext.pop_thread_default(ctx_td) else: # Only allow attaching if the thread has no main context yet if ctx: raise RuntimeError('Thread %r already has a main context, get_event_loop() will create a new loop if needed' % threading.current_thread().name) GLib.MainContext.push_thread_default(loop._context) self._loops[hash(loop._context)] = loop def new_event_loop(self): """Create and return a new event loop that iterates a new GLib.MainContext.""" return GLibEventLoop(GLib.MainContext()) # NOTE: We do *not* provide a GLib based ChildWatcher implementation! # This is *intentional* and *required*. The issue is that python provides # API which uses wait4() internally. GLib at the same time uses a thread to # handle SIGCHLD signals, which causes a race condition resulting in a # critical warning. # We just provide a reasonable sane child watcher and disallow the user # from choosing one as e.g. MultiLoopChildWatcher is problematic. # # TODO: Use PidfdChildWatcher when available if sys.platform != 'win32': def get_child_watcher(self): if self._child_watcher is None: self._child_watcher = asyncio.ThreadedChildWatcher() if threading.current_thread() is threading.main_thread(): self._child_watcher.attach_loop(self.get_event_loop()) return self._child_watcher ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/gimodule.c0000664000000000000000000022613715074674453014731 0ustar00rootroot/* -*- Mode: C; c-basic-offset: 4 -*- * vim: tabstop=4 shiftwidth=4 expandtab * * Copyright (C) 2005-2009 Johan Dahlin * * gimodule.c: wrapper for the gobject-introspection 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 St, Fifth Floor, Boston, MA 02110-1301 * USA */ #include #include #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-async.h" #include "pygi-source.h" #include "pygi-ccallback.h" #include "pygi-closure.h" #include "pygi-type.h" #include "pygi-boxed.h" #include "pygi-fundamental.h" #include "pygi-info.h" #include "pygi-struct.h" #include "pygobject-object.h" #include "pygoptioncontext.h" #include "pygoptiongroup.h" #include "pygspawn.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; static int _gi_exec (PyObject *module); /* 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; 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 PyObject * pyg_param_spec_new (GParamSpec *pspec) { PyErr_SetString (PyExc_NotImplementedError, "Creating ParamSpecs through pyg_param_spec_new is no longer supported"); return NULL; } static GParamSpec * pyg_param_spec_from_object (PyObject *tuple) { PyErr_SetString (PyExc_NotImplementedError, "Creating ParamSpecs through pyg_param_spec_from_object is no longer supported"); return NULL; } 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 = pygi_fundamental_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) NULL, (GClassFinalizeFunc) NULL, NULL, /* class_data */ 0, /* instance_size */ 0, /* n_preallocs */ (GInstanceInitFunc) NULL }; gchar *new_type_name; if (PyType_IsSubtype(class, &PyGObject_Type)) { type_info.class_init = (GClassInitFunc) pyg_object_class_init; type_info.instance_init = pygobject__g_instance_init; } /* 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; GType base_gtype = pyg_type_from_object((PyObject *) class->tp_base); if (base_gtype == G_TYPE_INVALID) { PyErr_SetString(PyExc_TypeError, "argument must be a Fundamental or GObject subclass"); return NULL; } /* Check if type already registered */ if (pyg_type_from_object((PyObject *) class) == base_gtype) { 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, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "g_type", NULL }; PyObject *py_g_type; GType g_type; if (!PyArg_ParseTupleAndKeywords (args, kwargs, "O!:enum_add", kwlist, &PyGTypeWrapper_Type, &py_g_type)) { return NULL; } g_type = pyg_type_from_object (py_g_type); if (g_type == G_TYPE_INVALID) { return NULL; } return flags_enum_from_gtype (g_type, pyg_enum_add); } static PyObject * _wrap_pyg_enum_register_new_gtype_and_add (PyObject *self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "info", NULL }; PyGIBaseInfo *py_info; GIEnumInfo *info; gint n_values; GEnumValue *g_enum_values; int i; const gchar *namespace; const gchar *type_name; gchar *full_name; GType g_type; if (!PyArg_ParseTupleAndKeywords (args, kwargs, "O:enum_add_make_new_gtype", kwlist, (PyObject *)&py_info)) { return NULL; } if (!GI_IS_ENUM_INFO (py_info->info) || g_base_info_get_type ((GIBaseInfo *) py_info->info) != GI_INFO_TYPE_ENUM) { PyErr_SetString (PyExc_TypeError, "info must be an EnumInfo with info type GI_INFO_TYPE_ENUM"); return NULL; } info = (GIEnumInfo *)py_info->info; n_values = g_enum_info_get_n_values (info); /* The new memory is zero filled which fulfills the registration * function requirement that the last item is zeroed out as a terminator. */ g_enum_values = g_new0 (GEnumValue, n_values + 1); for (i = 0; i < n_values; i++) { GIValueInfo *value_info; GEnumValue *enum_value; const gchar *name; const gchar *c_identifier; value_info = g_enum_info_get_value (info, i); name = g_base_info_get_name ((GIBaseInfo *) value_info); c_identifier = g_base_info_get_attribute ((GIBaseInfo *) value_info, "c:identifier"); enum_value = &g_enum_values[i]; enum_value->value_nick = g_strdup (name); enum_value->value = (gint)g_value_info_get_value (value_info); if (c_identifier == NULL) { enum_value->value_name = enum_value->value_nick; } else { enum_value->value_name = g_strdup (c_identifier); } g_base_info_unref ((GIBaseInfo *) value_info); } /* Obfuscate the full_name by prefixing it with "Py" to avoid conflicts * with real GTypes. See: https://bugzilla.gnome.org/show_bug.cgi?id=692515 */ namespace = g_base_info_get_namespace ((GIBaseInfo *) info); type_name = g_base_info_get_name ((GIBaseInfo *) info); full_name = g_strconcat ("Py", namespace, type_name, NULL); /* If enum registration fails, free all the memory allocated * for the values array. This needs to leak when successful * as GObject keeps a reference to the data as specified in the docs. */ g_type = g_enum_register_static (full_name, g_enum_values); if (g_type == G_TYPE_INVALID) { for (i = 0; i < n_values; i++) { GEnumValue *enum_value = &g_enum_values[i]; /* Only free value_name if it is different from value_nick to avoid * a double free. The pointer might have been is re-used in the case * c_identifier was NULL in the above loop. */ if (enum_value->value_name != enum_value->value_nick) g_free ((gchar *) enum_value->value_name); g_free ((gchar *) enum_value->value_nick); } PyErr_Format (PyExc_RuntimeError, "Unable to register enum '%s'", full_name); g_free (g_enum_values); g_free (full_name); return NULL; } g_free (full_name); return pyg_enum_add (NULL, type_name, NULL, g_type); } static PyObject * _wrap_pyg_flags_add (PyObject *self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "g_type", NULL }; PyObject *py_g_type; GType g_type; if (!PyArg_ParseTupleAndKeywords (args, kwargs, "O!:flags_add", kwlist, &PyGTypeWrapper_Type, &py_g_type)) { return NULL; } g_type = pyg_type_from_object (py_g_type); if (g_type == G_TYPE_INVALID) { return NULL; } return flags_enum_from_gtype (g_type, pyg_flags_add); } static PyObject * _wrap_pyg_flags_register_new_gtype_and_add (PyObject *self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "info", NULL }; PyGIBaseInfo *py_info; GIEnumInfo *info; gint n_values; GFlagsValue *g_flags_values; int i; const gchar *namespace; const gchar *type_name; gchar *full_name; GType g_type; if (!PyArg_ParseTupleAndKeywords (args, kwargs, "O:flags_add_make_new_gtype", kwlist, (PyObject *)&py_info)) { return NULL; } if (!GI_IS_ENUM_INFO (py_info->info) || g_base_info_get_type ((GIBaseInfo *) py_info->info) != GI_INFO_TYPE_FLAGS) { PyErr_SetString (PyExc_TypeError, "info must be an EnumInfo with info type GI_INFO_TYPE_FLAGS"); return NULL; } info = (GIEnumInfo *)py_info->info; n_values = g_enum_info_get_n_values (info); /* The new memory is zero filled which fulfills the registration * function requirement that the last item is zeroed out as a terminator. */ g_flags_values = g_new0 (GFlagsValue, n_values + 1); for (i = 0; i < n_values; i++) { GIValueInfo *value_info; GFlagsValue *flags_value; const gchar *name; const gchar *c_identifier; value_info = g_enum_info_get_value (info, i); name = g_base_info_get_name ((GIBaseInfo *) value_info); c_identifier = g_base_info_get_attribute ((GIBaseInfo *) value_info, "c:identifier"); flags_value = &g_flags_values[i]; flags_value->value_nick = g_strdup (name); flags_value->value = (guint)g_value_info_get_value (value_info); if (c_identifier == NULL) { flags_value->value_name = flags_value->value_nick; } else { flags_value->value_name = g_strdup (c_identifier); } g_base_info_unref ((GIBaseInfo *) value_info); } /* Obfuscate the full_name by prefixing it with "Py" to avoid conflicts * with real GTypes. See: https://bugzilla.gnome.org/show_bug.cgi?id=692515 */ namespace = g_base_info_get_namespace ((GIBaseInfo *) info); type_name = g_base_info_get_name ((GIBaseInfo *) info); full_name = g_strconcat ("Py", namespace, type_name, NULL); /* If enum registration fails, free all the memory allocated * for the values array. This needs to leak when successful * as GObject keeps a reference to the data as specified in the docs. */ g_type = g_flags_register_static (full_name, g_flags_values); if (g_type == G_TYPE_INVALID) { for (i = 0; i < n_values; i++) { GFlagsValue *flags_value = &g_flags_values[i]; /* Only free value_name if it is different from value_nick to avoid * a double free. The pointer might have been is re-used in the case * c_identifier was NULL in the above loop. */ if (flags_value->value_name != flags_value->value_nick) g_free ((gchar *) flags_value->value_name); g_free ((gchar *) flags_value->value_nick); } PyErr_Format (PyExc_RuntimeError, "Unable to register flags '%s'", full_name); g_free (g_flags_values); g_free (full_name); return NULL; } g_free (full_name); 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 */ } static PyObject * _wrap_pyg_register_interface_info (PyObject *self, PyObject *args) { PyObject *py_g_type; GType g_type; GInterfaceInfo *info; if (!PyArg_ParseTuple (args, "O!:register_interface_info", &PyGTypeWrapper_Type, &py_g_type)) { return NULL; } g_type = pyg_type_from_object (py_g_type); if (!g_type_is_a (g_type, G_TYPE_INTERFACE)) { PyErr_SetString (PyExc_TypeError, "must be an interface"); return NULL; } info = g_new0 (GInterfaceInfo, 1); info->interface_init = (GInterfaceInitFunc) initialize_interface; pyg_register_interface_info (g_type, info); g_free (info); Py_RETURN_NONE; } static void find_vfunc_info (GIBaseInfo *vfunc_info, GType implementor_gtype, gpointer *implementor_class_ret, gpointer *implementor_vtable_ret, GIFieldInfo **field_info_ret) { GType ancestor_g_type = 0; 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; ancestor_g_type = g_registered_type_info_get_g_type ( (GIRegisteredTypeInfo *) ancestor_info); implementor_class = g_type_class_ref (implementor_gtype); if (is_interface) { GTypeInstance *implementor_iface_class; implementor_iface_class = g_type_interface_peek (implementor_class, ancestor_g_type); if (implementor_iface_class == NULL) { g_type_class_unref (implementor_class); PyErr_Format (PyExc_RuntimeError, "Couldn't find GType of implementor of interface %s. " "Forgot to set __gtype_name__?", g_type_name (ancestor_g_type)); return; } *implementor_vtable_ret = implementor_iface_class; struct_info = g_interface_info_get_iface_struct ( (GIInterfaceInfo*) ancestor_info); } else { struct_info = g_object_info_get_class_struct ( (GIObjectInfo*) ancestor_info); *implementor_vtable_ret = implementor_class; } *implementor_class_ret = implementor_class; field_info = g_struct_info_find_field (struct_info, g_base_info_get_name ( (GIBaseInfo*) vfunc_info)); if (field_info != NULL) { GITypeInfo *type_info; type_info = g_field_info_get_type (field_info); if (g_type_info_get_tag (type_info) == GI_TYPE_TAG_INTERFACE) { *field_info_ret = field_info; } else { g_base_info_unref (field_info); } g_base_info_unref (type_info); } g_base_info_unref (struct_info); } static PyObject * _wrap_pyg_hook_up_vfunc_implementation (PyObject *self, PyObject *args) { PyGIBaseInfo *py_info; PyObject *py_type; PyObject *py_function; GType implementor_gtype = 0; gpointer implementor_class = NULL; gpointer implementor_vtable = NULL; GIFieldInfo *field_info = NULL; gpointer *method_ptr = NULL; PyGICClosure *closure = NULL; PyGIClosureCache *cache = NULL; if (!PyArg_ParseTuple (args, "O!O!O:hook_up_vfunc_implementation", &PyGIBaseInfo_Type, &py_info, &PyGTypeWrapper_Type, &py_type, &py_function)) return NULL; implementor_gtype = pyg_type_from_object (py_type); g_assert (G_TYPE_IS_CLASSED (implementor_gtype)); find_vfunc_info (py_info->info, implementor_gtype, &implementor_class, &implementor_vtable, &field_info); if (field_info != NULL) { GITypeInfo *type_info; GIBaseInfo *interface_info; GICallbackInfo *callback_info; gint offset; type_info = g_field_info_get_type (field_info); interface_info = g_type_info_get_interface (type_info); g_assert (g_base_info_get_type (interface_info) == GI_INFO_TYPE_CALLBACK); callback_info = (GICallbackInfo*) interface_info; offset = g_field_info_get_offset (field_info); method_ptr = G_STRUCT_MEMBER_P (implementor_vtable, offset); 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); g_base_info_unref (field_info); } g_type_class_unref (implementor_class); Py_RETURN_NONE; } #if 0 /* Not used, left around for future reference */ static PyObject * _wrap_pyg_has_vfunc_implementation (PyObject *self, PyObject *args) { PyGIBaseInfo *py_info; PyObject *py_type; PyObject *py_ret; gpointer implementor_class = NULL; gpointer implementor_vtable = NULL; GType implementor_gtype = 0; GIFieldInfo *field_info = NULL; if (!PyArg_ParseTuple (args, "O!O!:has_vfunc_implementation", &PyGIBaseInfo_Type, &py_info, &PyGTypeWrapper_Type, &py_type)) return NULL; implementor_gtype = pyg_type_from_object (py_type); g_assert (G_TYPE_IS_CLASSED (implementor_gtype)); py_ret = Py_False; find_vfunc_info (py_info->info, implementor_gtype, &implementor_class, &implementor_vtable, &field_info); if (field_info != NULL) { gpointer *method_ptr; gint offset; offset = g_field_info_get_offset (field_info); method_ptr = G_STRUCT_MEMBER_P (implementor_vtable, offset); if (*method_ptr != NULL) { py_ret = Py_True; } g_base_info_unref (field_info); } g_type_class_unref (implementor_class); Py_INCREF(py_ret); return py_ret; } #endif static PyObject * _wrap_pyg_variant_type_from_string (PyObject *self, PyObject *args) { char *type_string; PyObject *py_type; PyObject *py_variant = NULL; if (!PyArg_ParseTuple (args, "s:variant_type_from_string", &type_string)) { return NULL; } py_type = pygi_type_import_by_name ("GLib", "VariantType"); py_variant = pygi_boxed_new ( (PyTypeObject *) py_type, type_string, FALSE, 0); return py_variant; } #define CHUNK_SIZE 8192 static PyObject* pyg_channel_read(PyObject* self, PyObject *args, PyObject *kwargs) { int max_count = -1; PyObject *py_iochannel, *ret_obj = NULL; gsize total_read = 0; GError* error = NULL; GIOStatus status = G_IO_STATUS_NORMAL; GIOChannel *iochannel = NULL; if (!PyArg_ParseTuple (args, "Oi:pyg_channel_read", &py_iochannel, &max_count)) { return NULL; } if (!pyg_boxed_check (py_iochannel, G_TYPE_IO_CHANNEL)) { PyErr_SetString(PyExc_TypeError, "first argument is not a GLib.IOChannel"); return NULL; } if (max_count == 0) return PyBytes_FromString (""); iochannel = pyg_boxed_get (py_iochannel, GIOChannel); while (status == G_IO_STATUS_NORMAL && (max_count == -1 || total_read < (gsize)max_count)) { gsize single_read; char* buf; gsize buf_size; 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 = PyBytes_FromStringAndSize ((char *)NULL, buf_size); if (ret_obj == NULL) goto failure; } else if (buf_size + total_read > (gsize)PyBytes_Size (ret_obj)) { if (_PyBytes_Resize (&ret_obj, buf_size + total_read) == -1) goto failure; } 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 (pygi_error_check (&error)) goto failure; total_read += single_read; } if ( total_read != (gsize)PyBytes_Size (ret_obj) ) { if (_PyBytes_Resize (&ret_obj, total_read) == -1) goto failure; } return ret_obj; failure: Py_XDECREF(ret_obj); 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, pygi_fundamental_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_pyig_pyos_setsig (PyObject *self, PyObject *args) { int sig_num; PyObject *sig_handler; if (!PyArg_ParseTuple (args, "iO!:pyos_setsig", &sig_num, &PyLong_Type, &sig_handler)) return NULL; return PyLong_FromVoidPtr ((void *)(PyOS_setsig (sig_num, (PyOS_sighandler_t) PyLong_AsVoidPtr (sig_handler)))); } 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 }, { "flags_register_new_gtype_and_add", (PyCFunction) _wrap_pyg_flags_register_new_gtype_and_add, METH_VARARGS | METH_KEYWORDS }, { "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_type_from_string", (PyCFunction) _wrap_pyg_variant_type_from_string, METH_VARARGS }, { "source_new", (PyCFunction) pygi_source_new, METH_NOARGS }, { "pyos_getsig", (PyCFunction) _wrap_pyig_pyos_getsig, METH_VARARGS }, { "pyos_setsig", (PyCFunction) _wrap_pyig_pyos_setsig, 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_register_foreign_struct, }; const gpointer PyGParamSpec_Type_Stub = NULL; 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 */ (PyTypeObject *) &PyGParamSpec_Type_Stub, 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; 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; } /** * 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; } /** * 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; } static PyModuleDef_Slot _gi_slots[] = { {Py_mod_exec, _gi_exec}, {0, NULL} }; static struct PyModuleDef __gimodule = { PyModuleDef_HEAD_INIT, "_gi", NULL, 0, _gi_functions, _gi_slots, 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) { return PyModuleDef_Init(&__gimodule); } static int _gi_exec (PyObject *module) { PyObject *api; PyObject *module_dict = PyModule_GetDict (module); int ret; #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 ((ret = pygi_foreign_init ()) < 0) return ret; if ((ret = pygi_error_register_types (module)) < 0) return ret; if ((ret = pygi_repository_register_types (module)) < 0) return ret; if ((ret = pygi_info_register_types (module)) < 0) return ret; if ((ret = pygi_type_register_types (module_dict)) < 0) return ret; if ((ret = pygi_pointer_register_types (module_dict)) < 0) return ret; if ((ret = pygi_struct_register_types (module)) < 0) return ret; if ((ret = pygi_gboxed_register_types (module_dict)) < 0) return ret; if ((ret = pygi_fundamental_register_types (module)) < 0) return ret; if ((ret = pygi_boxed_register_types (module)) < 0) return ret; if ((ret = pygi_ccallback_register_types (module)) < 0) return ret; if ((ret = pygi_resulttuple_register_types (module)) < 0) return ret; if ((ret = pygi_async_register_types (module) < 0)) return ret; if ((ret = pygi_spawn_register_types (module_dict)) < 0) return ret; if ((ret = pygi_option_context_register_types (module_dict)) < 0) return ret; if ((ret = pygi_option_group_register_types (module_dict)) < 0) return ret; if ((ret = pygi_register_api (module_dict)) < 0) return ret; if ((ret = pygi_register_constants (module)) < 0) return ret; if ((ret = pygi_register_version_tuples (module_dict)) < 0) return ret; if ((ret = pygi_register_warnings (module_dict)) < 0) return ret; if ((ret = pyi_object_register_types (module_dict)) < 0) return ret; if ((ret = pygi_interface_register_types (module_dict)) < 0) return ret; if ((ret = pygi_enum_register_types (module_dict)) < 0) return ret; if ((ret = pygi_flags_register_types (module_dict)) < 0) return ret; PyGIWarning = PyErr_NewException ("gi.PyGIWarning", PyExc_Warning, NULL); if (PyGIWarning == NULL) return -1; PyGIDeprecationWarning = PyErr_NewException("gi.PyGIDeprecationWarning", PyExc_DeprecationWarning, NULL); /* 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 = PyCapsule_New ( (void *) &CAPI, "gi._API", NULL); if (api == NULL) { return -1; } PyModule_AddObject (module, "_API", api); return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/gimodule.h0000664000000000000000000000113215074674453014720 0ustar00rootroot#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_*/ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/importer.py0000664000000000000000000001247315074674453015167 0ustar00rootroot# -*- Mode: Python; py-indent-offset: 4 -*- # vim: tabstop=4 shiftwidth=4 expandtab # # Copyright (C) 2005-2009 Johan Dahlin # 2015 Christoph Reiter # # importer.py: dynamic importer for introspected libraries. # # 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 sys import warnings import importlib from contextlib import contextmanager 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", "GioUnix", "GioWin32"): # 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. def __init__(self, path): self.path = path def _find_module_check(self, fullname): if not fullname.startswith(self.path): return False path, namespace = fullname.rsplit('.', 1) return path == self.path def find_spec(self, fullname, path=None, target=None): if self._find_module_check(fullname): return importlib.util.spec_from_loader(fullname, self) def find_module(self, fullname, path=None): if self._find_module_check(fullname): return self 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 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/meson.build0000664000000000000000000000372115074674453015112 0ustar00rootrootsources = [ 'pygboxed.c', 'pygenum.c', 'pygflags.c', 'pyginterface.c', 'pygobject-object.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-async.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-fundamental.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 = [ 'events.py', '_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') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/module.py0000664000000000000000000002337315074674453014614 0ustar00rootroot# -*- Mode: Python; py-indent-offset: 4 -*- # vim: tabstop=4 shiftwidth=4 expandtab # # Copyright (C) 2007-2009 Johan Dahlin # # module.py: dynamic module for introspected libraries. # # 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 importlib from threading import Lock import gi from ._gi import \ Repository, \ FunctionInfo, \ RegisteredTypeInfo, \ EnumInfo, \ ObjectInfo, \ InterfaceInfo, \ ConstantInfo, \ StructInfo, \ UnionInfo, \ CallbackInfo, \ Struct, \ Boxed, \ Fundamental, \ CCallback, \ enum_add, \ enum_register_new_gtype_and_add, \ flags_add, \ flags_register_new_gtype_and_add, \ GInterface from .types import \ GObjectMeta, \ StructMeta from ._constants import \ TYPE_NONE, \ TYPE_BOXED, \ TYPE_POINTER, \ TYPE_ENUM, \ TYPE_FLAGS repository = Repository.get_default() # Cache of IntrospectionModules that have been loaded. _introspection_modules = {} def get_parent_for_object(object_info): parent_object_info = object_info.get_parent() if not parent_object_info: # 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 if object_info.get_fundamental() and gtype.is_instantiatable(): return Fundamental # Otherwise use builtins.object as the base return object namespace = parent_object_info.get_namespace() name = parent_object_info.get_name() module = importlib.import_module('gi.repository.' + namespace) return getattr(module, name) def get_interfaces_for_object(object_info): interfaces = [] for interface_info in object_info.get_interfaces(): namespace = interface_info.get_namespace() name = interface_info.get_name() module = importlib.import_module('gi.repository.' + namespace) interfaces.append(getattr(module, name)) return interfaces class IntrospectionModule(object): """An object which wraps an introspection typelib. This wrapping creates a python module like representation of the typelib using gi repository as a foundation. Accessing attributes of the module will dynamically pull them in and create wrappers for the members. 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 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: raise AttributeError("%r object has no attribute %r" % ( self.__name__, name)) if isinstance(info, EnumInfo): g_type = info.get_g_type() with self._lock: 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())) 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() # Create a wrapper. if isinstance(info, ObjectInfo): parent = get_parent_for_object(info) interfaces = tuple(interface for interface in get_interfaces_for_object(info) if not issubclass(parent, interface)) bases = (parent,) + interfaces metaclass = GObjectMeta elif isinstance(info, CallbackInfo): bases = (CCallback,) metaclass = GObjectMeta elif isinstance(info, InterfaceInfo): bases = (GInterface,) metaclass = GObjectMeta elif isinstance(info, (StructInfo, UnionInfo)): if g_type.is_a(TYPE_BOXED): bases = (Boxed,) elif (g_type.is_a(TYPE_POINTER) or g_type == TYPE_NONE or g_type.fundamental == g_type): bases = (Struct,) else: raise TypeError("unable to create a wrapper for %s.%s" % (info.get_namespace(), info.get_name())) metaclass = StructMeta else: raise NotImplementedError(info) 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 elif isinstance(info, ConstantInfo): wrapper = info.get_value() else: raise NotImplementedError(info) # Cache the newly created wrapper which will then be # available directly on this introspection module instead of being # lazily constructed through the __getattr__ we are currently in. self.__dict__[name] = wrapper return wrapper def __repr__(self): path = repository.get_typelib_path(self._namespace) return "" % (self._namespace, path) 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()) # update *set* because some repository attributes have already been # wrapped by __getattr__() and included in self.__dict__; but skip # Callback types, as these are not real objects which we can actually # get namespace_infos = repository.get_infos(self._namespace) result.update(info.get_name() for info in namespace_infos if not isinstance(info, CallbackInfo)) return list(result) 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] version = gi.get_required_version(namespace) module = IntrospectionModule(namespace, version) _introspection_modules[namespace] = module return module ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/overrides/GIMarshallingTests.py0000664000000000000000000000430215074674453021024 0ustar00rootroot# -*- Mode: Python; py-indent-offset: 4 -*- # vim: tabstop=4 shiftwidth=4 expandtab # # Copyright (C) 2010 Simon van der Linden # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 # USA from ..overrides import override from ..module import get_introspection_module GIMarshallingTests = get_introspection_module('GIMarshallingTests') __all__ = [] OVERRIDES_CONSTANT = 7 __all__.append('OVERRIDES_CONSTANT') class OverridesStruct(GIMarshallingTests.OverridesStruct): def __new__(cls, long_): return GIMarshallingTests.OverridesStruct.__new__(cls) def __init__(self, long_): GIMarshallingTests.OverridesStruct.__init__(self) self.long_ = long_ def method(self): return GIMarshallingTests.OverridesStruct.method(self) / 7 OverridesStruct = override(OverridesStruct) __all__.append('OverridesStruct') class OverridesObject(GIMarshallingTests.OverridesObject): def __new__(cls, long_): return GIMarshallingTests.OverridesObject.__new__(cls) def __init__(self, long_): GIMarshallingTests.OverridesObject.__init__(self) # FIXME: doesn't work yet # self.long_ = long_ @classmethod def new(cls, long_): self = GIMarshallingTests.OverridesObject.new() # FIXME: doesn't work yet # self.long_ = long_ return self def method(self): """Overridden doc string.""" return GIMarshallingTests.OverridesObject.method(self) / 7 OverridesObject = override(OverridesObject) __all__.append('OverridesObject') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/overrides/GLib.py0000664000000000000000000007244515074674453016152 0ustar00rootroot# -*- Mode: Python; py-indent-offset: 4 -*- # vim: tabstop=4 shiftwidth=4 expandtab # # Copyright (C) 2010 Tomeu Vizoso # Copyright (C) 2011, 2012 Canonical Ltd. # # 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 import sys import socket from .._ossighelper import register_sigint_fallback, get_event_loop from ..module import get_introspection_module from .._gi import (variant_type_from_string, source_new, source_set_callback, io_channel_read) from ..overrides import override, deprecated, deprecated_attr from gi import PyGIDeprecationWarning, version_info GLib = get_introspection_module('GLib') __all__ = [] from gi import _option as option option # pyflakes __all__.append('option') # Types and functions still needed from static bindings 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('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) # 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'] class _VariantCreator(object): _LEAF_CONSTRUCTORS = { 'b': GLib.Variant.new_boolean, 'y': GLib.Variant.new_byte, 'n': GLib.Variant.new_int16, 'q': GLib.Variant.new_uint16, 'i': GLib.Variant.new_int32, 'u': GLib.Variant.new_uint32, 'x': GLib.Variant.new_int64, 't': GLib.Variant.new_uint64, 'h': GLib.Variant.new_handle, 'd': GLib.Variant.new_double, 's': GLib.Variant.new_string, 'o': GLib.Variant.new_object_path, 'g': GLib.Variant.new_signature, 'v': GLib.Variant.new_variant, } 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). 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: 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. format_string is a standard GVariant type signature, value is a Python object whose structure has to match the signature. Examples: GLib.Variant('i', 1) GLib.Variant('(is)', (1, 'hello')) GLib.Variant('(asa{sv})', ([], {'foo': GLib.Variant('b', True), 'bar': GLib.Variant('i', 2)})) """ if not GLib.VariantType.string_is_valid(format_string): raise TypeError("Invalid GVariant format string '%s'", format_string) creator = _VariantCreator() 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): 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) def __repr__(self): if hasattr(self, 'format_string'): f = self.format_string else: f = self.get_type_string() return "GLib.Variant('%s', %s)" % (f, self.print_(False)) def __eq__(self, other): try: return self.equal(other) except TypeError: return False def __ne__(self, other): try: return not self.equal(other) except TypeError: return True def __hash__(self): # We're not using just hash(self.unpack()) because otherwise we'll have # hash collisions between the same content in different variant types, # which will cause a performance issue in set/dict/etc. return hash((self.get_type_string(), self.unpack())) def unpack(self): """Decompose a GVariant into a native Python object.""" type_string = self.get_type_string() # simple values la = LEAF_ACCESSORS.get(type_string) if la: return getattr(self, la)() # tuple if type_string.startswith('('): return tuple(self.get_child_value(i).unpack() for i in range(self.n_children())) # dictionary if type_string.startswith('a{'): res = {} for i in range(self.n_children()): v = self.get_child_value(i) res[v.get_child_value(0).unpack()] = v.get_child_value(1).unpack() return res # array if type_string.startswith('a'): return [self.get_child_value(i).unpack() for i in range(self.n_children())] # variant (just unbox transparently) if type_string.startswith('v'): return self.get_variant().unpack() # maybe if type_string.startswith('m'): if not self.n_children(): return None return self.get_child_value(0).unpack() 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. 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 [] if not signature.startswith('('): return [signature] result = [] head = '' tail = signature[1:-1] # eat the surrounding () while tail: c = tail[0] head += c tail = tail[1:] if c in ('m', 'a'): # prefixes, keep collecting continue if c in ('(', '{'): # consume until corresponding )/} level = 1 up = c if up == '(': down = ')' else: down = '}' while level > 0: c = tail[0] head += c tail = tail[1:] if c == up: level += 1 elif c == down: level -= 1 # otherwise we have a simple type result.append(head) head = '' return result # # Pythonic iterators # def __len__(self): if self.get_type_string() in ['s', 'o', 'g']: return len(self.get_string()) # Array, dict, tuple if self.get_type_string().startswith('a') or self.get_type_string().startswith('('): return self.n_children() raise TypeError('GVariant type %s does not have a length' % self.get_type_string()) def __getitem__(self, key): # dict if self.get_type_string().startswith('a{'): try: val = self.lookup_value(key, variant_type_from_string('*')) if val is None: raise KeyError(key) return val.unpack() except TypeError: # lookup_value() only works for string keys, which is certainly # the common case; we have to do painful iteration for other # key types for i in range(self.n_children()): v = self.get_child_value(i) if v.get_child_value(0).unpack() == key: return v.get_child_value(1).unpack() raise KeyError(key) # array/tuple if self.get_type_string().startswith('a') or self.get_type_string().startswith('('): key = int(key) if key < 0: key = self.n_children() + key if key < 0 or key >= self.n_children(): raise IndexError('list index out of range') return self.get_child_value(key).unpack() # string if self.get_type_string() in ['s', 'o', 'g']: return self.get_string().__getitem__(key) raise TypeError('GVariant type %s is not a container' % self.get_type_string()) # # Pythonic bool operations # def __nonzero__(self): return self.__bool__() def __bool__(self): if self.get_type_string() in ['y', 'n', 'q', 'i', 'u', 'x', 't', 'h', 'd']: return self.unpack() != 0 if self.get_type_string() in ['b']: return self.get_boolean() if self.get_type_string() in ['s', 'o', 'g']: return len(self.get_string()) != 0 # Array, dict, tuple if self.get_type_string().startswith('a') or self.get_type_string().startswith('('): return self.n_children() != 0 # unpack works recursively, hence bool also works recursively return bool(self.unpack()) def keys(self): if not self.get_type_string().startswith('a{'): raise TypeError('GVariant type %s is not a dictionary' % self.get_type_string()) res = [] for i in range(self.n_children()): v = self.get_child_value(i) res.append(v.get_child_value(0).unpack()) return res def get_string(self): value, length = GLib.Variant.get_string(self) return value setattr(Variant, 'get_string', get_string) __all__.append('Variant') def markup_escape_text(text, length=-1): if isinstance(text, bytes): 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']: 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) __all__.append('IO_' + n) for n in ['APPEND', 'GET_MASK', 'IS_READABLE', 'IS_SEEKABLE', 'MASK', 'NONBLOCK', 'SET_MASK']: 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']: 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']: 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']: 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']: 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): # Backwards compatible constructor API def __new__(cls, context=None): return GLib.MainLoop.new(context, False) def __init__(self, context=None): pass def run(self): with register_sigint_fallback(self.quit): with get_event_loop(self.get_context()).running(self.quit): super(MainLoop, self).run() MainLoop = override(MainLoop) __all__.append('MainLoop') class MainContext(GLib.MainContext): # Backwards compatible API with default value def iteration(self, may_block=True): with get_event_loop(self).paused(): 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 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'): # We destroy and finalize the box from here, as GLib might hold # a reference (e.g. while the source is pending), delaying the # finalize call until a later point. self.destroy() self.finalize() self._clear_boxed() def finalize(self): pass def set_callback(self, fn, user_data=None): if hasattr(self, '__pygi_custom_source'): # use our custom pygi_source_set_callback() if for a GSource object # with custom functions source_set_callback(self, fn, user_data) else: # otherwise, for Idle and Timeout, use the standard method super(Source, self).set_callback(fn, user_data) def get_current_time(self): return GLib.get_real_time() * 0.000001 get_current_time = deprecated(get_current_time, 'GLib.Source.get_time() or GLib.get_real_time()') # as get/set_priority are introspected, we can't use the static # property(get_priority, ..) here def __get_priority(self): return self.get_priority() def __set_priority(self, value): self.set_priority(value) priority = property(__get_priority, __set_priority) def __get_can_recurse(self): return self.get_can_recurse() def __set_can_recurse(self, value): self.set_can_recurse(value) can_recurse = property(__get_can_recurse, __set_can_recurse) Source = override(Source) __all__.append('Source') class Idle(Source): def __new__(cls, priority=GLib.PRIORITY_DEFAULT): source = GLib.idle_source_new() source.__class__ = cls return source def __init__(self, priority=GLib.PRIORITY_DEFAULT): super(Source, self).__init__() if priority != GLib.PRIORITY_DEFAULT: self.set_priority(priority) __all__.append('Idle') class Timeout(Source): def __new__(cls, interval=0, priority=GLib.PRIORITY_DEFAULT): source = GLib.timeout_source_new(interval) source.__class__ = cls return source def __init__(self, interval=0, priority=GLib.PRIORITY_DEFAULT): if priority != GLib.PRIORITY_DEFAULT: self.set_priority(priority) __all__.append('Timeout') # backwards compatible API def idle_add(function, *user_data, **kwargs): priority = kwargs.get('priority', GLib.PRIORITY_DEFAULT_IDLE) return GLib.idle_add(priority, function, *user_data) __all__.append('idle_add') def timeout_add(interval, function, *user_data, **kwargs): priority = kwargs.get('priority', GLib.PRIORITY_DEFAULT) return GLib.timeout_add(priority, interval, function, *user_data) __all__.append('timeout_add') def timeout_add_seconds(interval, function, *user_data, **kwargs): priority = kwargs.get('priority', GLib.PRIORITY_DEFAULT) return GLib.timeout_add_seconds(priority, interval, function, *user_data) __all__.append('timeout_add_seconds') # 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 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) # shift the arguments around user_data = cb_and_user_data callback = condition condition = priority_ if not callable(callback): raise TypeError('third argument must be callable') # backwards compatibility: Call with priority kwarg if 'priority' in kwargs: warnings.warn('Calling io_add_watch with priority keyword argument is deprecated, put it as second positional argument', PyGIDeprecationWarning) priority_ = kwargs['priority'] else: priority_ = GLib.PRIORITY_DEFAULT else: if len(cb_and_user_data) < 1 or not callable(cb_and_user_data[0]): raise TypeError('expecting callback as fourth argument') callback = cb_and_user_data[0] user_data = cb_and_user_data[1:] # backwards compatibility: Allow calling with fd if isinstance(channel, int): 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: callback(channel, cond, *data) real_channel = GLib.IOChannel.unix_new(channel.fileno()) else: assert isinstance(channel, GLib.IOChannel) func_fdtransform = callback real_channel = channel 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') # backwards compatible API class IOChannel(GLib.IOChannel): def __new__(cls, filedes=None, filename=None, mode=None, hwnd=None): if filedes is not None: return GLib.IOChannel.unix_new(filedes) if filename is not None: return GLib.IOChannel.new_file(filename, mode or 'r') if hwnd is not None: 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) def readline(self, size_hint=-1): # note, size_hint is just to maintain backwards compatible API; the # old static binding did not actually use it (status, buf, length, terminator_pos) = self.read_line() if buf is None: return '' return buf def readlines(self, size_hint=-1): # note, size_hint is just to maintain backwards compatible API; # the old static binding did not actually use it lines = [] status = GLib.IOStatus.NORMAL while status == GLib.IOStatus.NORMAL: (status, buf, length, terminator_pos) = self.read_line() # note, this appends an empty line after EOF; this is # bug-compatible with the old static bindings if buf is None: buf = '' lines.append(buf) return lines def write(self, buf, buflen=-1): if not isinstance(buf, bytes): buf = buf.encode('UTF-8') if buflen == -1: buflen = len(buf) (status, written) = self.write_chars(buf, buflen) return written def writelines(self, lines): for line in lines: self.write(line) _whence_map = {0: GLib.SeekType.SET, 1: GLib.SeekType.CUR, 2: GLib.SeekType.END} def seek(self, offset, whence=0): try: w = self._whence_map[whence] except KeyError: raise ValueError("invalid 'whence' value") return self.seek_position(offset, w) def add_watch(self, condition, callback, *user_data, **kwargs): priority = kwargs.get('priority', GLib.PRIORITY_DEFAULT) return io_add_watch(self, priority, condition, callback, *user_data) add_watch = deprecated(add_watch, 'GLib.io_add_watch()') def __iter__(self): return self def __next__(self): (status, buf, length, terminator_pos) = self.read_line() if status == GLib.IOStatus.NORMAL: return buf raise StopIteration IOChannel = override(IOChannel) __all__.append('IOChannel') class PollFD(GLib.PollFD): def __new__(cls, fd, events): pollfd = GLib.PollFD() pollfd.__class__ = cls return pollfd def __init__(self, fd, events): self.fd = fd self.events = events PollFD = override(PollFD) __all__.append('PollFD') # 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', PyGIDeprecationWarning) pid = priority_or_pid callback = pid_or_callback if len(args) == 0: priority = kwargs.get('priority', GLib.PRIORITY_DEFAULT) elif len(args) == 1: user_data = args priority = kwargs.get('priority', GLib.PRIORITY_DEFAULT) elif len(args) == 2: 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 '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: 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 # 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') 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') # backwards compatible API with default argument, and ignoring bytes_read # output argument def filename_from_utf8(utf8string, len=-1): return GLib.filename_from_utf8(utf8string, len)[0] __all__.append('filename_from_utf8') 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") ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/overrides/GObject.py0000664000000000000000000006004215074674453016640 0ustar00rootroot# -*- Mode: Python; py-indent-offset: 4 -*- # vim: tabstop=4 shiftwidth=4 expandtab # # Copyright (C) 2012 Canonical Ltd. # Author: Martin Pitt # Copyright (C) 2012-2013 Simon Feltman # Copyright (C) 2012 Bastian Winkler # # 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 functools import warnings from collections import namedtuple import gi.module 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 GObjectModule = gi.module.get_introspection_module('GObject') __all__ = [] from gi import _option as option option = option # API aliases for backwards compatibility for name in ['markup_escape_text', 'get_application_name', 'set_application_name', 'get_prgname', 'set_prgname', 'main_depth', 'filename_display_basename', 'filename_display_name', 'filename_from_utf8', 'uri_list_extract_uris', 'MainLoop', 'MainContext', 'main_context_default', 'source_remove', 'Source', 'Idle', 'Timeout', 'PollFD', 'idle_add', 'timeout_add', 'timeout_add_seconds', 'io_add_watch', 'child_watch_add', 'get_current_time', 'spawn_async']: globals()[name] = getattr(GLib, name) deprecated_attr("GObject", name, "GLib." + name) __all__.append(name) # 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', 'IO_STATUS_ERROR', 'IO_STATUS_NORMAL', 'IO_STATUS_EOF', 'IO_STATUS_AGAIN', 'IO_FLAG_APPEND', 'IO_FLAG_NONBLOCK', 'IO_FLAG_IS_READABLE', 'IO_FLAG_IS_WRITEABLE', 'IO_FLAG_IS_SEEKABLE', 'IO_FLAG_MASK', 'IO_FLAG_GET_MASK', 'IO_FLAG_SET_MASK', 'SPAWN_LEAVE_DESCRIPTORS_OPEN', 'SPAWN_DO_NOT_REAP_CHILD', 'SPAWN_SEARCH_PATH', 'SPAWN_STDOUT_TO_DEV_NULL', 'SPAWN_STDERR_TO_DEV_NULL', 'SPAWN_CHILD_INHERITS_STDIN', 'SPAWN_FILE_AND_ARGV_ZERO', 'OPTION_FLAG_HIDDEN', 'OPTION_FLAG_IN_MAIN', 'OPTION_FLAG_REVERSE', 'OPTION_FLAG_NO_ARG', 'OPTION_FLAG_FILENAME', 'OPTION_FLAG_OPTIONAL_ARG', 'OPTION_FLAG_NOALIAS', 'OPTION_ERROR_UNKNOWN_OPTION', 'OPTION_ERROR_BAD_VALUE', 'OPTION_ERROR_FAILED', 'OPTION_REMAINING', 'glib_version']: 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) 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 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']: new_name = name.split("_", 1)[-1] globals()[name] = getattr(GLib, new_name) deprecated_attr("GObject", name, "GLib." + new_name) __all__.append(name) TYPE_INVALID = GObjectModule.type_from_name('invalid') TYPE_NONE = GObjectModule.type_from_name('void') TYPE_INTERFACE = GObjectModule.type_from_name('GInterface') TYPE_CHAR = GObjectModule.type_from_name('gchar') TYPE_UCHAR = GObjectModule.type_from_name('guchar') TYPE_BOOLEAN = GObjectModule.type_from_name('gboolean') TYPE_INT = GObjectModule.type_from_name('gint') TYPE_UINT = GObjectModule.type_from_name('guint') TYPE_LONG = GObjectModule.type_from_name('glong') TYPE_ULONG = GObjectModule.type_from_name('gulong') TYPE_INT64 = GObjectModule.type_from_name('gint64') TYPE_UINT64 = GObjectModule.type_from_name('guint64') TYPE_ENUM = GObjectModule.type_from_name('GEnum') TYPE_FLAGS = GObjectModule.type_from_name('GFlags') TYPE_FLOAT = GObjectModule.type_from_name('gfloat') TYPE_DOUBLE = GObjectModule.type_from_name('gdouble') TYPE_STRING = GObjectModule.type_from_name('gchararray') TYPE_POINTER = GObjectModule.type_from_name('gpointer') TYPE_BOXED = GObjectModule.type_from_name('GBoxed') TYPE_PARAM = GObjectModule.type_from_name('GParam') TYPE_OBJECT = GObjectModule.type_from_name('GObject') TYPE_PYOBJECT = GObjectModule.type_from_name('PyObject') TYPE_GTYPE = GObjectModule.type_from_name('GType') TYPE_STRV = GObjectModule.type_from_name('GStrv') TYPE_VARIANT = GObjectModule.type_from_name('GVariant') TYPE_GSTRING = GObjectModule.type_from_name('GString') TYPE_VALUE = GObjectModule.Value.__gtype__ TYPE_UNICHAR = TYPE_UINT __all__ += ['TYPE_INVALID', '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', 'TYPE_GSTRING', 'TYPE_UNICHAR', 'TYPE_VALUE'] # Deprecated, use GLib directly 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 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://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 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 = _gi.GBoxed GEnum = _gi.GEnum GFlags = _gi.GFlags GInterface = _gi.GInterface GObject = _gi.GObject GObjectWeakRef = _gi.GObjectWeakRef GPointer = _gi.GPointer GType = _gi.GType Warning = _gi.Warning __all__ += ['GBoxed', 'GEnum', 'GFlags', 'GInterface', 'GObject', 'GObjectWeakRef', 'GPointer', 'GType', 'Warning'] 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 = _gi.type_register __all__ += ['features', 'list_properties', 'new', 'pygobject_version', 'threads_init', 'type_register'] class Value(GObjectModule.Value): def __init__(self, value_type=None, py_value=None): GObjectModule.Value.__init__(self) if value_type is not None: self.init(value_type) if py_value is not None: self.set_value(py_value) @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. _gi._gvalue_set(self, boxed) def get_boxed(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 if gtype == TYPE_CHAR: self.set_char(py_value) elif gtype == TYPE_UCHAR: self.set_uchar(py_value) elif gtype == TYPE_STRING: 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_FLAGS): self.set_flags(py_value) elif gtype == TYPE_POINTER: self.set_pointer(py_value) elif gtype == TYPE_GTYPE: self.set_gtype(py_value) elif gtype == TYPE_VARIANT: self.set_variant(py_value) else: # 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 if gtype == TYPE_CHAR: return self.get_char() elif gtype == TYPE_UCHAR: return self.get_uchar() 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 == TYPE_POINTER: return self.get_pointer() elif gtype == TYPE_GTYPE: return self.get_gtype() elif gtype == TYPE_VARIANT: # get_variant was missing annotations # https://gitlab.gnome.org/GNOME/glib/merge_requests/492 return self.dup_variant() else: try: return _gi._gvalue_get(self) except TypeError: if gtype == TYPE_INVALID: return None raise def __repr__(self): return '' % (self.__g_type.name, self.get_value()) Value = override(Value) __all__.append('Value') def type_from_name(name): type_ = GObjectModule.type_from_name(name) if type_ == TYPE_INVALID: raise RuntimeError('unknown type name: %s' % name) return type_ __all__.append('type_from_name') def type_parent(type_): parent = GObjectModule.type_parent(type_) if parent == TYPE_INVALID: raise RuntimeError('no parent for type') return parent __all__.append('type_parent') def _validate_type_for_signal_method(type_): if hasattr(type_, '__gtype__'): type_ = type_.__gtype__ if not type_.is_instantiatable() and not type_.is_interface(): raise TypeError('type must be instantiable or an interface, got %s' % type_) def signal_list_ids(type_): _validate_type_for_signal_method(type_) return GObjectModule.signal_list_ids(type_) __all__.append('signal_list_ids') 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') 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): if type_ is not None: id_or_name = signal_lookup(id_or_name, type_) res = GObjectModule.signal_query(id_or_name) assert res is not None if res.signal_id == 0: return None # 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)) __all__.append('signal_query') class _HandlerBlockManager(object): def __init__(self, obj, handler_id): self.obj = obj self.handler_id = handler_id def __enter__(self): pass def __exit__(self, exc_type, exc_value, traceback): 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. :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: .. code-block:: python with GObject.signal_handler_block(obj, id): pass """ GObjectModule.signal_handler_block(obj, handler_id) return _HandlerBlockManager(obj, handler_id) __all__.append('signal_handler_block') def signal_parse_name(detailed_signal, itype, force_detail_quark): """Parse a detailed signal name into (signal_id, detail). :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) if res: return signal_id, detail else: raise ValueError('%s: unknown signal name: %s' % (itype, detailed_signal)) __all__.append('signal_parse_name') 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') # GObject accumulators with pure Python implementations # These return a tuple of (continue_emission, accumulation_result) def signal_accumulator_first_wins(ihint, return_accu, handler_return, user_data=None): # Stop emission but return the result of the last handler return (False, handler_return) __all__.append('signal_accumulator_first_wins') def signal_accumulator_true_handled(ihint, return_accu, handler_return, user_data=None): # 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 = _gi.add_emission_hook signal_new = _gi.signal_new __all__ += ['add_emission_hook', 'signal_new'] class _FreezeNotifyManager(object): def __init__(self, obj): self.obj = obj def __enter__(self): pass def __exit__(self, exc_type, exc_value, traceback): self.obj.thaw_notify() def _signalmethod(func): # Function wrapper for signal functions used as instance methods. # This is needed when the signal functions come directly from GI. # (they are not already wrapped) @functools.wraps(func) def meth(*args, **kwargs): return func(*args, **kwargs) return meth class Object(GObjectModule.Object): def _unsupported_method(self, *args, **kargs): raise RuntimeError('This method is currently unsupported.') def _unsupported_data_method(self, *args, **kargs): raise RuntimeError('Data access methods are unsupported. ' 'Use normal Python attributes instead') # Generic data methods are not needed in python as it can be handled # with standard attribute access: https://bugzilla.gnome.org/show_bug.cgi?id=641944 get_data = _unsupported_data_method get_qdata = _unsupported_data_method set_data = _unsupported_data_method steal_data = _unsupported_data_method steal_qdata = _unsupported_data_method replace_data = _unsupported_data_method replace_qdata = _unsupported_data_method # The following methods as unsupported until we verify # they work as gi methods. bind_property_full = _unsupported_method compat_control = _unsupported_method interface_find_property = _unsupported_method interface_install_property = _unsupported_method interface_list_properties = _unsupported_method notify_by_pspec = _unsupported_method watch_closure = _unsupported_method # Make all reference management methods private but still accessible. _ref = GObjectModule.Object.ref _ref_sink = GObjectModule.Object.ref_sink _unref = GObjectModule.Object.unref _force_floating = GObjectModule.Object.force_floating ref = _unsupported_method ref_sink = _unsupported_method unref = _unsupported_method force_floating = _unsupported_method # 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 = _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. .. code-block:: python 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 # 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 # def stop_emission(self, detailed_signal): """Deprecated, please use stop_emission_by_name.""" warnings.warn(self.stop_emission.__doc__, PyGIDeprecationWarning, stacklevel=2) return self.stop_emission_by_name(detailed_signal) emit_stop_by_name = stop_emission Object = override(Object) 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'] @override class ParamSpec(GObjectModule.ParamSpec): @property def nick(self): return self._nick @nick.setter def nick(self, nick): self._nick = nick @property def blurb(self): return self._blurb @blurb.setter def blurb(self, blurb): self._blurb = blurb GParamSpec = ParamSpec deprecated_attr("GObject", "GParamSpec", "GObject.ParamSpec") __all__ += ["ParamSpec", "GParamSpec"] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/overrides/Gdk.py0000664000000000000000000003747515074674453016046 0ustar00rootroot# -*- Mode: Python; py-indent-offset: 4 -*- # vim: tabstop=4 shiftwidth=4 expandtab # # Copyright (C) 2009 Johan Dahlin # 2010 Simon van der Linden # # 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 sys import warnings from ..overrides import override, strip_boolean_result from ..module import get_introspection_module from gi import PyGIDeprecationWarning, require_version Gdk = get_introspection_module('Gdk') GDK3 = Gdk._version == '3.0' GDK4 = Gdk._version == '4.0' __all__ = [] # 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 if 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 __eq__(self, other): if not isinstance(other, Gdk.Color): 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=%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))) 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))) def to_floats(self): """Return (red_float, green_float, blue_float) triple.""" 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.""" return Color(int(red * Color.MAX_VALUE), int(green * Color.MAX_VALUE), int(blue * Color.MAX_VALUE)) Color = override(Color) __all__.append('Color') 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) self.red = red self.green = green self.blue = blue self.alpha = alpha 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.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.""" yield self.red yield self.green yield self.blue yield self.alpha def to_color(self): """Converts this RGBA into a Color instance which excludes alpha.""" return Color(int(self.red * Color.MAX_VALUE), int(self.green * Color.MAX_VALUE), int(self.blue * Color.MAX_VALUE)) @classmethod def from_color(cls, color): """Returns a new RGBA instance given a Color instance.""" return cls(color.red_float, color.green_float, color.blue_float) RGBA = override(RGBA) __all__.append('RGBA') if 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 GDK3: class Window(Gdk.Window): def __new__(cls, parent, attributes, attributes_mask): # Gdk.Window had to be made abstract, # this override allows using the standard constructor return Gdk.Window.new(parent, attributes, attributes_mask) def __init__(self, parent, attributes, attributes_mask): pass def cairo_create(self): return Gdk.cairo_create(self) Window = override(Window) __all__.append('Window') if 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 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 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) else: raise ValueError("Wrong number of parameters") 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 '' % 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 __len__(self): return len(self.get_files()) def __getitem__(self, index): return self.get_files()[index] FileList = override(FileList) __all__.append('FileList') # constants if GDK3: SELECTION_PRIMARY = Gdk.atom_intern('PRIMARY', True) __all__.append('SELECTION_PRIMARY') SELECTION_SECONDARY = Gdk.atom_intern('SECONDARY', True) __all__.append('SELECTION_SECONDARY') SELECTION_CLIPBOARD = Gdk.atom_intern('CLIPBOARD', True) __all__.append('SELECTION_CLIPBOARD') TARGET_BITMAP = Gdk.atom_intern('BITMAP', True) __all__.append('TARGET_BITMAP') TARGET_COLORMAP = Gdk.atom_intern('COLORMAP', True) __all__.append('TARGET_COLORMAP') TARGET_DRAWABLE = Gdk.atom_intern('DRAWABLE', True) __all__.append('TARGET_DRAWABLE') TARGET_PIXMAP = Gdk.atom_intern('PIXMAP', True) __all__.append('TARGET_PIXMAP') TARGET_STRING = Gdk.atom_intern('STRING', True) __all__.append('TARGET_STRING') SELECTION_TYPE_ATOM = Gdk.atom_intern('ATOM', True) __all__.append('SELECTION_TYPE_ATOM') SELECTION_TYPE_BITMAP = Gdk.atom_intern('BITMAP', True) __all__.append('SELECTION_TYPE_BITMAP') SELECTION_TYPE_COLORMAP = Gdk.atom_intern('COLORMAP', True) __all__.append('SELECTION_TYPE_COLORMAP') SELECTION_TYPE_DRAWABLE = Gdk.atom_intern('DRAWABLE', True) __all__.append('SELECTION_TYPE_DRAWABLE') SELECTION_TYPE_INTEGER = Gdk.atom_intern('INTEGER', True) __all__.append('SELECTION_TYPE_INTEGER') SELECTION_TYPE_PIXMAP = Gdk.atom_intern('PIXMAP', True) __all__.append('SELECTION_TYPE_PIXMAP') SELECTION_TYPE_WINDOW = Gdk.atom_intern('WINDOW', True) __all__.append('SELECTION_TYPE_WINDOW') SELECTION_TYPE_STRING = Gdk.atom_intern('STRING', True) __all__.append('SELECTION_TYPE_STRING') if GDK3: import sys initialized, argv = Gdk.init_check(sys.argv) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/overrides/GdkPixbuf.py0000664000000000000000000000327415074674453017212 0ustar00rootroot# Copyright 2018 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, 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') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/overrides/Gio.py0000664000000000000000000005266315074674453016053 0ustar00rootroot# -*- Mode: Python; py-indent-offset: 4 -*- # vim: tabstop=4 shiftwidth=4 expandtab # # Copyright (C) 2010 Ignacio Casal Quinteiro # # 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 contextlib import suppress from .._ossighelper import register_sigint_fallback, get_event_loop from ..overrides import ( override, deprecated_attr, deprecated_init, wrap_list_store_equal_func, wrap_list_store_sort_func, ) from .._gi import CallableInfo from ..module import get_introspection_module from gi import PyGIWarning from gi.repository import GLib import sys Gio = get_introspection_module('Gio') __all__ = [] class Application(Gio.Application): def run(self, *args, **kwargs): with register_sigint_fallback(self.quit): with get_event_loop(GLib.MainContext.default()).running(self.quit): 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 def __next__(self): file_info = self.next_file(None) if file_info is not None: return file_info else: raise StopIteration FileEnumerator = override(FileEnumerator) __all__.append('FileEnumerator') class MenuItem(Gio.MenuItem): def set_attribute(self, attributes): for (name, format_string, value) in attributes: self.set_attribute_value(name, GLib.Variant(format_string, value)) MenuItem = override(MenuItem) __all__.append('MenuItem') class Settings(Gio.Settings): '''Provide dictionary-like access to GLib.Settings.''' __init__ = deprecated_init(Gio.Settings.__init__, arg_names=('schema', 'path', 'backend')) def __contains__(self, key): return key in self.list_keys() 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 return True def __getitem__(self, key): # get_value() aborts the program on an unknown key 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 key not in self: raise KeyError('unknown key: %r' % (key,)) # determine type string of this key range = self.get_range(key) type_ = range.get_child_value(0).get_string() v = range.get_child_value(1) if type_ == 'type': # v is boxed empty array, type of its elements is the allowed value type type_str = v.get_child_value(0).get_type_string() assert type_str.startswith('a') type_str = type_str[1:] elif type_ == 'enum': # v is an array with the allowed values assert v.get_child_value(0).get_type_string().startswith('a') type_str = v.get_child_value(0).get_child_value(0).get_type_string() 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_)) self.set_value(key, GLib.Variant(type_str, value)) def keys(self): return self.list_keys() Settings = override(Settings) __all__.append('Settings') class _DBusProxyMethodCall: '''Helper class to implement DBusProxy method calls.''' def __init__(self, dbus_proxy, method_name): self.dbus_proxy = dbus_proxy self.method_name = method_name def __async_result_handler(self, obj, result, user_data): (result_callback, error_callback, real_user_data) = user_data try: ret = obj.call_finish(result) except Exception: etype, e = sys.exc_info()[:2] # return exception as value if error_callback: error_callback(obj, e, real_user_data) else: result_callback(obj, e, real_user_data) return result_callback(obj, self._unpack_result(ret), real_user_data) def __call__(self, *args, **kwargs): # the first positional argument is the signature, unless we are calling # a method without arguments; then signature is implied to be '()'. if args: signature = args[0] args = args[1:] if not isinstance(signature, str): raise TypeError('first argument must be the method signature string: %r' % signature) else: signature = '()' arg_variant = GLib.Variant(signature, tuple(args)) if 'result_handler' in kwargs: # asynchronous call user_data = (kwargs['result_handler'], kwargs.get('error_handler'), kwargs.get('user_data')) self.dbus_proxy.call(self.method_name, arg_variant, kwargs.get('flags', 0), kwargs.get('timeout', -1), None, self.__async_result_handler, user_data) else: # synchronous call result = self.dbus_proxy.call_sync(self.method_name, arg_variant, kwargs.get('flags', 0), kwargs.get('timeout', -1), None) return self._unpack_result(result) @classmethod def _unpack_result(klass, result): '''Convert a D-BUS return variant into an appropriate return value''' result = result.unpack() # to be compatible with standard Python behaviour, unbox # single-element tuples and return None for empty result tuples if len(result) == 1: result = result[0] elif len(result) == 0: result = None return result class DBusProxy(Gio.DBusProxy): '''Provide comfortable and pythonic method calls. This marshalls the method arguments into a GVariant, invokes the call_sync() method on the DBusProxy object, and unmarshalls the result GVariant back into a Python tuple. The first argument always needs to be the D-Bus signature tuple of the method call. Example: proxy = Gio.DBusProxy.new_sync(...) result = proxy.MyMethod('(is)', 42, 'hello') The exception are methods which take no arguments, like proxy.MyMethod('()'). For these you can omit the signature and just write proxy.MyMethod(). Optional keyword arguments: - timeout: timeout for the call in milliseconds (default to D-Bus timeout) - flags: Combination of Gio.DBusCallFlags.* - result_handler: Do an asynchronous method call and invoke result_handler(proxy_object, result, user_data) when it finishes. - error_handler: If the asynchronous call raises an exception, error_handler(proxy_object, exception, user_data) is called when it finishes. If error_handler is not given, result_handler is called with the exception object as result instead. - user_data: Optional user data to pass to result_handler for asynchronous calls. Example for asynchronous calls: def mymethod_done(proxy, result, user_data): if isinstance(result, Exception): # handle error else: # do something with result proxy.MyMethod('(is)', 42, 'hello', result_handler=mymethod_done, user_data='data') ''' 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 def find_with_equal_func(self, item, equal_func, *user_data): # find_with_equal_func() is not suited for language bindings, # see: https://gitlab.gnome.org/GNOME/glib/-/issues/2447. # Use find_with_equal_func_full() instead. equal_func = wrap_list_store_equal_func(equal_func) return self.find_with_equal_func_full(item, equal_func, *user_data) ListStore = override(ListStore) __all__.append('ListStore') class DataInputStream(Gio.DataInputStream): def __iter__(self): return self def __next__(self): line = self.read_line_utf8(None)[0] if line is not None: return line else: raise StopIteration DataInputStream = override(DataInputStream) __all__.append('DataInputStream') class File(Gio.File): def __fspath__(self): path = self.peek_path() # A file isn't guaranteed to have a path associated and returning # `None` here will result in a `TypeError` trying to subscribe to it. if path is None or path == '': raise TypeError('File has no associated path.') return path File = override(File) __all__.append("File") GioPlatform = None with suppress(ImportError): from gi.repository import GioUnix as GioPlatform if not GioPlatform: with suppress(ImportError): from gi.repository import GioWin32 as GioPlatform if GioPlatform: # Add support for using platform-specific Gio symbols. gio_globals = globals() platform_name = f"{GioPlatform._namespace[len(Gio._namespace):]}" platform_name_lower = platform_name.lower() for attr in dir(GioPlatform): if attr.startswith("_"): continue original_attr = getattr(GioPlatform, attr) wrapper_attr = attr if isinstance( original_attr, CallableInfo ) and original_attr.get_symbol().startswith(f"g_{platform_name_lower}_"): wrapper_attr = f"{platform_name_lower}_{attr}" else: try: gtype = getattr(original_attr, "__gtype__") if gtype.name.startswith(f"G{platform_name}"): wrapper_attr = f"{platform_name}{attr}" except AttributeError: pass if wrapper_attr == attr and hasattr(Gio, wrapper_attr): try: name = original_attr.__name__[0] except (AttributeError, IndexError): name = original_attr # Fallback if we don't have the original name. if name.islower(): wrapper_attr = f"{platform_name_lower}_{attr}" elif "_" in name: wrapper_attr = f"{platform_name.upper()}_{attr}" elif name: wrapper_attr = f"{platform_name}{attr}" if ( wrapper_attr in __all__ or wrapper_attr in gio_globals or hasattr(Gio, wrapper_attr) ): continue gio_globals[wrapper_attr] = original_attr deprecated_attr( Gio._namespace, wrapper_attr, f"{GioPlatform._namespace}.{attr}" ) __all__.append(wrapper_attr) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/overrides/GioUnix.py0000664000000000000000000001223215074674453016703 0ustar00rootroot# Copyright 2025 Simon McVittie # SPDX-License-Identifier: LGPL-2.1-or-later from ..module import get_introspection_module from ..overrides import override from gi.repository import GLib GioUnix = get_introspection_module("GioUnix") __all__ = [] if (GLib.MAJOR_VERSION, GLib.MINOR_VERSION) < (2, 86): # In older versions of GLib there was some confusion between the # platform-specific classes in GioUnix and their equivalents in Gio, # resulting in functions like g_desktop_app_info_get_action_name() # being assumed to be a global function that happened to take a # Gio.DesktopAppInfo first parameter, instead of being a method on a # GioUnix.DesktopAppInfo instance. There are not very many classes and # methods in GioUnix, so we can wrap them and provide the intended API. @override class DesktopAppInfo(GioUnix.DesktopAppInfo): def get_action_name(self, action_name): return GioUnix.DesktopAppInfo.get_action_name(self, action_name) def get_boolean(self, key): return GioUnix.DesktopAppInfo.get_boolean(self, key) def get_categories(self): return GioUnix.DesktopAppInfo.get_categories(self) def get_filename(self): return GioUnix.DesktopAppInfo.get_filename(self) def get_generic_name(self): return GioUnix.DesktopAppInfo.get_generic_name(self) def get_is_hidden(self): return GioUnix.DesktopAppInfo.get_is_hidden(self) def get_keywords(self): return GioUnix.DesktopAppInfo.get_keywords(self) def get_locale_string(self, key): return GioUnix.DesktopAppInfo.get_locale_string(self, key) def get_nodisplay(self): return GioUnix.DesktopAppInfo.get_nodisplay(self) def get_show_in(self, desktop_env=None): return GioUnix.DesktopAppInfo.get_show_in(self, desktop_env) def get_startup_wm_class(self): return GioUnix.DesktopAppInfo.get_startup_wm_class(self) def get_string(self, key): return GioUnix.DesktopAppInfo.get_string(self, key) def get_string_list(self, key): return GioUnix.DesktopAppInfo.get_string_list(self, key) def has_key(self, key): return GioUnix.DesktopAppInfo.has_key(self, key) def launch_action(self, action_name, launch_context=None): GioUnix.DesktopAppInfo.launch_action( self, action_name, launch_context, ) def launch_uris_as_manager( self, uris, launch_context, spawn_flags, user_setup=None, user_setup_data=None, pid_callback=None, pid_callback_data=None, ): return GioUnix.DesktopAppInfo.launch_uris_as_manager( self, uris, launch_context, spawn_flags, user_setup, user_setup_data, pid_callback, pid_callback_data, ) def launch_uris_as_manager_with_fds( self, uris, launch_context, spawn_flags, user_setup, user_setup_data, pid_callback, pid_callback_data, stdin_fd, stdout_fd, stderr_fd, ): return GioUnix.DesktopAppInfo.launch_uris_as_manager_with_fds( self, uris, launch_context, spawn_flags, user_setup, user_setup_data, pid_callback, pid_callback_data, stdin_fd, stdout_fd, stderr_fd, ) def list_actions(self): return GioUnix.DesktopAppInfo.list_actions(self) __all__.append("DesktopAppInfo") @override class FDMessage(GioUnix.FDMessage): def append_fd(self, fd): return GioUnix.FDMessage.append_fd(self, fd) def get_fd_list(self): return GioUnix.FDMessage.get_fd_list(self) def steal_fds(self): return GioUnix.FDMessage.steal_fds(self) __all__.append("FDMessage") @override class InputStream(GioUnix.InputStream): def get_close_fd(self): return GioUnix.InputStream.get_close_fd(self) def get_fd(self): return GioUnix.InputStream.get_fd(self) def set_close_fd(self, close_fd): GioUnix.InputStream.set_close_fd(self, close_fd) __all__.append("InputStream") @override class MountMonitor(GioUnix.MountMonitor): def set_rate_limit(self, limit_msec): GioUnix.MountMonitor.set_rate_limit(limit_msec) __all__.append("MountMonitor") @override class OutputStream(GioUnix.OutputStream): def get_close_fd(self): return GioUnix.OutputStream.get_close_fd(self) def get_fd(self): return GioUnix.OutputStream.get_fd(self) def set_close_fd(self, close_fd): GioUnix.OutputStream.set_close_fd(self, close_fd) __all__.append("OutputStream") ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/overrides/Gtk.py0000664000000000000000000017320015074674453016051 0ustar00rootroot# -*- Mode: Python; py-indent-offset: 4 -*- # vim: tabstop=4 shiftwidth=4 expandtab # # Copyright (C) 2009 Johan Dahlin # 2010 Simon van der Linden # # 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 sys import warnings from gi.repository import GObject, GLib from .._ossighelper import register_sigint_fallback, get_event_loop 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 Gtk = get_introspection_module('Gtk') GTK3 = Gtk._version == '3.0' GTK4 = Gtk._version == '4.0' __all__ = [] 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) class _FreezeNotifyManager(object): def __init__(self, obj): self.obj = obj def __enter__(self): pass 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) 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) Gtk.Widget.style_get_property(self, property_name, value) return value.get_value() Widget = override(Widget) __all__.append('Widget') if GTK3: class Container(Gtk.Container, Widget): def __len__(self): return len(self.get_children()) def __contains__(self, child): return child in self.get_children() def __iter__(self): return iter(self.get_children()) def __bool__(self): return True 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() 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] 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') else: Container = object class Editable(Gtk.Editable): def insert_text(self, text, position): return super(Editable, self).insert_text(text, -1, position) get_selection_bounds = strip_boolean_result(Gtk.Editable.get_selection_bounds, fail_ret=()) Editable = override(Editable) __all__.append("Editable") 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 /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 /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, 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 /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=name, label=label, tooltip=tooltip, stock_id=stock_id, value=entry_value) if GTK3: 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, str): raise TypeError('buffer must be a string') length = _get_utf8_length(buffer) 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') class ComboBox(Gtk.ComboBox, Container): get_active_iter = strip_boolean_result(Gtk.ComboBox.get_active_iter) ComboBox = override(ComboBox) __all__.append('ComboBox') if GTK3: class Box(Gtk.Box): __init__ = deprecated_init(Gtk.Box.__init__, arg_names=('homogeneous', 'spacing'), category=PyGTKDeprecationWarning) Box = override(Box) __all__.append('Box') 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') if GTK3: class MenuItem(Gtk.MenuItem): __init__ = deprecated_init(Gtk.MenuItem.__init__, arg_names=('label',), category=PyGTKDeprecationWarning) MenuItem = override(MenuItem) __all__.append('MenuItem') def _get_utf8_length(string): assert isinstance(string, str) if not isinstance(string, bytes): string = string.encode("utf-8") return len(string) class Builder(Gtk.Builder): if GTK4: from .._gtktemplate import define_builder_scope BuilderScope = define_builder_scope() 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)) 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: .. code-block:: python 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, str): raise TypeError('buffer must be a string') 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, str): raise TypeError('buffer must be a string') length = _get_utf8_length(buffer) return Gtk.Builder.add_objects_from_string(self, buffer, length, object_ids) Builder = override(Builder) __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, *args, **kwargs): if not initialized: raise RuntimeError( "Gtk couldn't be initialized. " "Use Gtk.init_check() if you want to handle this case.") _window_init(self, *args, **kwargs) 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) if add_buttons: self.add_buttons(*add_buttons) def run(self, *args, **kwargs): with register_sigint_fallback(self.destroy): with get_event_loop(GLib.MainContext.default()).running(self.destroy): 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): """ The add_buttons() method adds several buttons to the Gtk.Dialog using the button data passed as arguments to the method. This method is the same as calling the Gtk.Dialog.add_button() repeatedly. The button data pairs - button text (or stock ID) and a response ID integer are passed individually. For example: .. 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: try: t, r = b[0:2] except ValueError: raise ValueError('Must pass an even number of arguments') b = b[2:] yield t, r for text, response in _button(args): self.add_button(text, response) Dialog = override(Dialog) __all__.append('Dialog') 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) def format_secondary_text(self, message_format): self.set_property('secondary-use-markup', False) self.set_property('secondary-text', message_format) def format_secondary_markup(self, message_format): self.set_property('secondary-use-markup', True) self.set_property('secondary-text', message_format) MessageDialog = override(MessageDialog) __all__.append('MessageDialog') if GTK3: class ColorSelectionDialog(Gtk.ColorSelectionDialog): __init__ = deprecated_init(Gtk.ColorSelectionDialog.__init__, arg_names=('title',), category=PyGTKDeprecationWarning) ColorSelectionDialog = override(ColorSelectionDialog) __all__.append('ColorSelectionDialog') class FileChooserDialog(Gtk.FileChooserDialog): __init__ = deprecated_init(Gtk.FileChooserDialog.__init__, arg_names=('title', 'parent', 'action', 'buttons'), category=PyGTKDeprecationWarning) FileChooserDialog = override(FileChooserDialog) __all__.append('FileChooserDialog') if GTK3: class FontSelectionDialog(Gtk.FontSelectionDialog): __init__ = deprecated_init(Gtk.FontSelectionDialog.__init__, arg_names=('title',), category=PyGTKDeprecationWarning) FontSelectionDialog = override(FontSelectionDialog) __all__.append('FontSelectionDialog') 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) RecentChooserDialog = override(RecentChooserDialog) __all__.append('RecentChooserDialog') class IconView(Gtk.IconView): 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') if GTK3: class ToolButton(Gtk.ToolButton): __init__ = deprecated_init(Gtk.ToolButton.__init__, arg_names=('stock_id',), category=PyGTKDeprecationWarning) 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') 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 create_tag(self, tag_name=None, **properties): """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 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 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) :returns: A new tag. """ tag = Gtk.TextTag(name=tag_name, **properties) self.get_tag_table().add(tag) return tag def create_mark(self, mark_name, where, left_gravity=False): return Gtk.TextBuffer.create_mark(self, mark_name, where, left_gravity) def set_text(self, text, length=-1): Gtk.TextBuffer.set_text(self, text, length) def insert(self, iter, text, length=-1): if not isinstance(text, str): raise TypeError('text must be a string, not %s' % type(text)) Gtk.TextBuffer.insert(self, iter, text, length) def insert_with_tags(self, iter, text, *tags): start_offset = iter.get_offset() self.insert(iter, text) if not tags: return start = self.get_iter_at_offset(start_offset) for tag in tags: self.apply_tag(tag, start, iter) def insert_with_tags_by_name(self, iter, text, *tags): tag_objs = [] for tag in tags: tag_obj = self.get_tag_table().lookup(tag) if not tag_obj: raise ValueError('unknown text tag: %s' % tag) tag_objs.append(tag_obj) self.insert_with_tags(iter, text, *tag_objs) def insert_at_cursor(self, text, length=-1): 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) TextIter = override(TextIter) __all__.append('TextIter') class TreeModel(Gtk.TreeModel): def __len__(self): return self.iter_n_children(None) def __bool__(self): return True def _getiter(self, key): if isinstance(key, Gtk.TreeIter): return key elif isinstance(key, int) and key < 0: index = len(self) + key if index < 0: raise IndexError("row index is out of bounds: %d" % key) return self.get_iter(index) else: try: aiter = self.get_iter(key) except ValueError: 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 else: return TreePath(path) def __getitem__(self, key): aiter = self._getiter(key) return TreeModelRow(self, aiter) def __setitem__(self, key, value): row = self[key] self.set_row(row.iter, value) def __delitem__(self, key): aiter = self._getiter(key) self.remove(aiter) def __iter__(self): return TreeModelRowIter(self, self.get_iter_first()) get_iter_first = strip_boolean_result(Gtk.TreeModel.get_iter_first) iter_children = strip_boolean_result(Gtk.TreeModel.iter_children) iter_nth_child = strip_boolean_result(Gtk.TreeModel.iter_nth_child) iter_parent = strip_boolean_result(Gtk.TreeModel.iter_parent) get_iter_from_string = strip_boolean_result(Gtk.TreeModel.get_iter_from_string, ValueError, 'invalid tree path') def get_iter(self, path): path = self._coerce_path(path) success, aiter = super(TreeModel, self).get_iter(path) if not success: raise ValueError("invalid tree path '%s'" % path) return aiter def iter_next(self, aiter): next_iter = aiter.copy() success = super(TreeModel, self).iter_next(next_iter) if success: return next_iter def iter_previous(self, aiter): prev_iter = aiter.copy() success = super(TreeModel, self).iter_previous(prev_iter) if success: return prev_iter def _convert_row(self, row): # TODO: Accept a dictionary for row # model.append(None,{COLUMN_ICON: icon, COLUMN_NAME: name}) if isinstance(row, str): raise TypeError('Expected a list or tuple, but got str') n_columns = self.get_n_columns() if len(row) != n_columns: raise ValueError('row sequence has the incorrect number of elements') result = [] columns = [] for cur_col, value in enumerate(row): # do not try to set None values, they are causing warnings if value is None: continue result.append(self._convert_value(cur_col, value)) columns.append(cur_col) return (result, columns) def set_row(self, treeiter, row): converted_row, columns = self._convert_row(row) for column in columns: self.set_value(treeiter, column, row[column]) def _convert_value(self, column, value): '''Convert value to a GObject.Value of the expected type''' if isinstance(value, GObject.Value): return value return GObject.Value(self.get_column_type(column), value) def get(self, treeiter, *columns): n_columns = self.get_n_columns() values = [] for col in columns: if not isinstance(col, int): raise TypeError("column numbers must be ints") if col < 0 or col >= n_columns: raise ValueError("column number is out of range") values.append(self.get_value(treeiter, col)) return tuple(values) # # Signals supporting python iterables as tree paths # def row_changed(self, path, iter): return super(TreeModel, self).row_changed(self._coerce_path(path), iter) def row_inserted(self, path, iter): return super(TreeModel, self).row_inserted(self._coerce_path(path), iter) def row_has_child_toggled(self, path, iter): return super(TreeModel, self).row_has_child_toggled(self._coerce_path(path), iter) def row_deleted(self, path): return super(TreeModel, self).row_deleted(self._coerce_path(path)) def rows_reordered(self, path, iter, new_order): return super(TreeModel, self).rows_reordered(self._coerce_path(path), iter, new_order) TreeModel = override(TreeModel) __all__.append('TreeModel') class TreeSortable(Gtk.TreeSortable, ): get_sort_column_id = strip_boolean_result(Gtk.TreeSortable.get_sort_column_id, fail_ret=(None, None)) def set_sort_func(self, sort_column_id, sort_func, user_data=None): super(TreeSortable, self).set_sort_func(sort_column_id, sort_func, user_data) def set_default_sort_func(self, sort_func, user_data=None): super(TreeSortable, self).set_default_sort_func(sort_func, user_data) TreeSortable = override(TreeSortable) __all__.append('TreeSortable') if GTK3: class TreeModelSort(Gtk.TreeModelSort): __init__ = deprecated_init(Gtk.TreeModelSort.__init__, arg_names=('model',), category=PyGTKDeprecationWarning) 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): def __init__(self, *column_types): 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_values(position, columns, row) else: treeiter = Gtk.ListStore.insert(self, position) return treeiter def append(self, row=None): if row: return self._do_insert(-1, row) # gtk_list_store_insert() does not know about the "position == -1" # case, so use append() here else: return Gtk.ListStore.append(self) def prepend(self, row=None): return self._do_insert(0, row) def insert(self, position, row=None): return self._do_insert(position, row) def insert_before(self, sibling, row=None): if row is not None: if sibling is None: position = -1 else: position = self.get_path(sibling).get_indices()[-1] return self._do_insert(position, row) return Gtk.ListStore.insert_before(self, sibling) def insert_after(self, sibling, row=None): if row is not None: if sibling is None: position = 0 else: position = self.get_path(sibling).get_indices()[-1] + 1 return self._do_insert(position, row) 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(cols, vals): if len(cols) != len(vals): raise TypeError('The number of columns do not match the number of 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.') 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): _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): _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') class TreeModelRow(object): def __init__(self, model, iter_or_path): if not isinstance(model, Gtk.TreeModel): raise TypeError("expected Gtk.TreeModel, %s found" % type(model).__name__) self.model = model if isinstance(iter_or_path, Gtk.TreePath): self.iter = model.get_iter(iter_or_path) 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__) @property def path(self): return self.model.get_path(self.iter) @property def next(self): return self.get_next() @property def previous(self): return self.get_previous() @property def parent(self): return self.get_parent() def get_next(self): next_iter = self.model.iter_next(self.iter) if next_iter: return TreeModelRow(self.model, next_iter) def get_previous(self): prev_iter = self.model.iter_previous(self.iter) if prev_iter: return TreeModelRow(self.model, prev_iter) def get_parent(self): parent_iter = self.model.iter_parent(self.iter) if parent_iter: return TreeModelRow(self.model, parent_iter) def __getitem__(self, key): if isinstance(key, int): if key >= self.model.get_n_columns(): raise IndexError("column index is out of bounds: %d" % key) elif key < 0: key = self._convert_negative_index(key) return self.model.get_value(self.iter, key) elif isinstance(key, slice): start, stop, step = key.indices(self.model.get_n_columns()) alist = [] 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, slice or tuple, not %s" % type(key).__name__) def __setitem__(self, key, value): if isinstance(key, int): if key >= self.model.get_n_columns(): raise IndexError("column index is out of bounds: %d" % key) elif key < 0: key = self._convert_negative_index(key) self.model.set_value(self.iter, key, value) elif isinstance(key, slice): start, stop, step = key.indices(self.model.get_n_columns()) indexList = range(start, stop, step) if len(indexList) != len(value): raise ValueError( "attempt to assign sequence of size %d to slice of size %d" % (len(value), len(indexList))) 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("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 if new_index < 0: raise IndexError("column index is out of bounds: %d" % index) return new_index def iterchildren(self): child_iter = self.model.iter_children(self.iter) return TreeModelRowIter(self.model, child_iter) __all__.append('TreeModelRow') class TreeModelRowIter(object): def __init__(self, model, aiter): self.model = model self.iter = aiter def __next__(self): if not self.iter: raise StopIteration row = TreeModelRow(self.model, self.iter) self.iter = self.model.iter_next(self.iter) return row def __iter__(self): return self __all__.append('TreeModelRowIter') class TreePath(Gtk.TreePath): def __new__(cls, path=0): if isinstance(path, int): path = str(path) elif not isinstance(path, str): path = ":".join(str(val) for val in path) if len(path) == 0: raise TypeError("could not parse subscript '%s' as a tree path" % path) try: return TreePath.new_from_string(path) except TypeError: raise TypeError("could not parse subscript '%s' as a tree path" % path) def __init__(self, *args, **kwargs): super(TreePath, self).__init__() def __str__(self): return self.to_string() or "" def __lt__(self, other): return other is not None and self.compare(other) < 0 def __le__(self, other): return other is not None and self.compare(other) <= 0 def __eq__(self, other): return other is not None and self.compare(other) == 0 def __ne__(self, other): return other is None or self.compare(other) != 0 def __gt__(self, other): return other is None or self.compare(other) > 0 def __ge__(self, other): return other is None or self.compare(other) >= 0 def __iter__(self): return iter(self.get_indices()) def __len__(self): return self.get_depth() 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) def _do_insert(self, parent, position, row): if row is not None: row, columns = self._convert_row(row) treeiter = self.insert_with_values(parent, position, columns, row) else: treeiter = Gtk.TreeStore.insert(self, parent, position) return treeiter def append(self, parent, row=None): return self._do_insert(parent, -1, row) def prepend(self, parent, row=None): return self._do_insert(parent, 0, row) def insert(self, parent, position, row=None): return self._do_insert(parent, position, row) def insert_before(self, parent, sibling, row=None): if row is not None: 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) return Gtk.TreeStore.insert_before(self, parent, sibling) def insert_after(self, parent, sibling, row=None): if row is not None: 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 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(cols, vals): if len(cols) != len(vals): raise TypeError('The number of columns do not match the number of 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.') 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): _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): _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): 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) 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) 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): path = TreePath(path) super(TreeView, self).scroll_to_cell(path, column, use_align, row_align, col_align) def set_cursor(self, path, column=None, start_editing=False): if not isinstance(path, Gtk.TreePath): path = TreePath(path) super(TreeView, self).set_cursor(path, column, start_editing) def get_cell_area(self, path, column=None): if not isinstance(path, Gtk.TreePath): path = TreePath(path) return super(TreeView, self).get_cell_area(path, column) def insert_column_with_attributes(self, position, title, cell, **kwargs): column = TreeViewColumn() column.set_title(title) column.pack_start(cell, False) self.insert_column(column, position) column.set_attributes(cell, **kwargs) TreeView = override(TreeView) __all__.append('TreeView') class TreeViewColumn(Gtk.TreeViewColumn): def __init__(self, title='', cell_renderer=None, **attributes): Gtk.TreeViewColumn.__init__(self, title=title) if cell_renderer: self.pack_start(cell_renderer, True) for (name, value) in attributes.items(): self.add_attribute(cell_renderer, name, value) cell_get_position = strip_boolean_result(Gtk.TreeViewColumn.cell_get_position) def set_cell_data_func(self, cell_renderer, func, func_data=None): super(TreeViewColumn, self).set_cell_data_func(cell_renderer, func, func_data) def set_attributes(self, cell_renderer, **attributes): Gtk.CellLayout.clear_attributes(self, cell_renderer) for (name, value) in attributes.items(): Gtk.CellLayout.add_attribute(self, cell_renderer, name, value) TreeViewColumn = override(TreeViewColumn) __all__.append('TreeViewColumn') class TreeSelection(Gtk.TreeSelection): def select_path(self, path): if not isinstance(path, Gtk.TreePath): path = TreePath(path) super(TreeSelection, self).select_path(path) def get_selected(self): success, model, aiter = super(TreeSelection, self).get_selected() if success: return (model, aiter) else: return (model, None) # for compatibility with PyGtk def get_selected_rows(self): rows, model = super(TreeSelection, self).get_selected_rows() return (model, rows) TreeSelection = override(TreeSelection) __all__.append('TreeSelection') 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) 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) Button = override(Button) __all__.append('Button') class LinkButton(Gtk.LinkButton): __init__ = deprecated_init(Gtk.LinkButton.__init__, arg_names=('uri', 'label'), category=PyGTKDeprecationWarning) LinkButton = override(LinkButton) __all__.append('LinkButton') 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): 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) # 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']) Adjustment = override(Adjustment) __all__.append('Adjustment') 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) def attach(self, child, left_attach, right_attach, top_attach, bottom_attach, xoptions=Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL, yoptions=Gtk.AttachOptions.EXPAND | Gtk.AttachOptions.FILL, xpadding=0, ypadding=0): Gtk.Table.attach(self, child, left_attach, right_attach, top_attach, bottom_attach, xoptions, yoptions, xpadding, ypadding) Table = override(Table) __all__.append('Table') class ScrolledWindow(Gtk.ScrolledWindow): __init__ = deprecated_init(Gtk.ScrolledWindow.__init__, arg_names=('hadjustment', 'vadjustment'), category=PyGTKDeprecationWarning) ScrolledWindow = override(ScrolledWindow) __all__.append('ScrolledWindow') if GTK3: class HScrollbar(Gtk.HScrollbar): __init__ = deprecated_init(Gtk.HScrollbar.__init__, arg_names=('adjustment',), category=PyGTKDeprecationWarning) HScrollbar = override(HScrollbar) __all__.append('HScrollbar') class VScrollbar(Gtk.VScrollbar): __init__ = deprecated_init(Gtk.VScrollbar.__init__, arg_names=('adjustment',), category=PyGTKDeprecationWarning) VScrollbar = override(VScrollbar) __all__.append('VScrollbar') if GTK3: class Paned(Gtk.Paned): def pack1(self, child, resize=False, shrink=True): super(Paned, self).pack1(child, resize, shrink) def pack2(self, child, resize=True, shrink=True): super(Paned, self).pack2(child, resize, shrink) Paned = override(Paned) __all__.append('Paned') 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: 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 def __init__(self, *args, **kwargs): return super(IconSet, self).__init__() IconSet = override(IconSet) __all__.append('IconSet') class Viewport(Gtk.Viewport): __init__ = deprecated_init(Gtk.Viewport.__init__, arg_names=('hadjustment', 'vadjustment'), category=PyGTKDeprecationWarning) Viewport = override(Viewport) __all__.append('Viewport') class TreeModelFilter(Gtk.TreeModelFilter): def set_visible_func(self, func, data=None): super(TreeModelFilter, self).set_visible_func(func, data) def set_value(self, iter, column, value): # Delegate to child model iter = self.convert_iter_to_child_iter(iter) self.get_model().set_value(iter, column, value) TreeModelFilter = override(TreeModelFilter) __all__.append('TreeModelFilter') if GTK3 or GTK4: 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') 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) def main(*args, **kwargs): with register_sigint_fallback(Gtk.main_quit): with get_event_loop(GLib.MainContext.default()).running(Gtk.main_quit): return _Gtk_main(*args, **kwargs) _Gtk_main_iteration = Gtk.main_iteration _Gtk_main_iteration_do = Gtk.main_iteration_do @override(Gtk.main_iteration) def main_iteration(): with get_event_loop(GLib.MainContext.default()).paused(): return _Gtk_main_iteration() @override(Gtk.main_iteration) def main_iteration_do(blocking): with get_event_loop(GLib.MainContext.default()).paused(): return _Gtk_main_iteration_do(blocking) 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) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/overrides/Pango.py0000664000000000000000000000335615074674453016374 0ustar00rootroot# -*- Mode: Python; py-indent-offset: 4 -*- # vim: tabstop=4 shiftwidth=4 expandtab # # Copyright (C) 2010 Paolo Borelli # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 # USA from ..overrides import override from ..module import get_introspection_module Pango = get_introspection_module('Pango') __all__ = [] class FontDescription(Pango.FontDescription): def __new__(cls, string=None): if string is not None: return Pango.font_description_from_string(string) else: return Pango.FontDescription.__new__(cls) def __init__(self, *args, **kwargs): return super(FontDescription, self).__init__() FontDescription = override(FontDescription) __all__.append('FontDescription') class Layout(Pango.Layout): def __new__(cls, context): return Pango.Layout.new(context) 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') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/overrides/__init__.py0000664000000000000000000003121415074674453017061 0ustar00rootrootimport functools import types import warnings import importlib import sys from gi import PyGIDeprecationWarning from gi._gi import CallableInfo, pygobject_new_full from gi._constants import \ TYPE_NONE, \ TYPE_INVALID # support overrides in different directories than our gi module from pkgutil import extend_path __path__ = extend_path(__path__, __name__) # 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. """ namespace = introspection_module.__name__.rsplit(".", 1)[-1] module_key = 'gi.repository.' + namespace # 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 spec = importlib.util.find_spec(override_package_name) override_loader = spec.loader if spec is not None else None # 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 override_mod = importlib.import_module(override_package_name) 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. 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: 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""" @functools.wraps(fn) def wrapped(*args, **kwargs): warnings.warn('%s is deprecated; use %s instead' % (fn.__name__, replacement), PyGIDeprecationWarning, stacklevel=2) return fn(*args, **kwargs) 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. 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) if ret[0]: if len(ret) == 2: return ret[1] else: return ret[1:] else: if exc_type: 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 def wrap_list_store_equal_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 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/overrides/keysyms.py0000664000000000000000000000325115074674453017026 0ustar00rootroot# -*- Mode: Python; py-indent-offset: 4 -*- # pygtk - Python bindings for the GTK toolkit. # Copyright (C) 1998-2003 James Henstridge # # gtk/keysyms.py: list of keysyms. # # 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 . 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_ 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_parenleft = 0x14a5 Armenian_guillemotright = 0x14a6 Armenian_guillemotleft = 0x14a7 Armenian_em_dash = 0x14a8 Armenian_dot = 0x14a9 Armenian_mijaket = 0x14a9 Armenian_comma = 0x14ab Armenian_en_dash = 0x14ac Armenian_ellipsis = 0x14ae ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/overrides/meson.build0000664000000000000000000000042315074674453017110 0ustar00rootrootpython_sources = [ 'GLib.py', 'Gtk.py', 'Gdk.py', 'GdkPixbuf.py', 'GObject.py', 'Gio.py', 'GioUnix.py', 'GIMarshallingTests.py', 'Pango.py', 'keysyms.py', '__init__.py'] python.install_sources(python_sources, subdir : join_paths('gi', 'overrides') ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pygboxed.c0000664000000000000000000001673015074674453014741 0ustar00rootroot/* -*- Mode: C; c-basic-offset: 4 -*- * pygtk- Python bindings for the GTK toolkit. * Copyright (C) 1998-2003 James Henstridge * * pygboxed.c: wrapper for GBoxed * * 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 . */ #include #include #include #include "pygboxed.h" #include "pygi-type.h" #include "pygi-type.h" #include "pygi-util.h" GQuark pygboxed_type_key; PYGI_DEFINE_TYPE("gobject.GBoxed", PyGBoxed_Type, PyGBoxed); static void gboxed_dealloc(PyGBoxed *self) { 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* gboxed_richcompare(PyObject *self, PyObject *other, int op) { if (Py_TYPE(self) == Py_TYPE(other) && PyObject_IsInstance(self, (PyObject*)&PyGBoxed_Type)) return pyg_ptr_richcompare (pyg_boxed_get_ptr (self), pyg_boxed_get_ptr (other), op); else { Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } } static Py_hash_t gboxed_hash(PyGBoxed *self) { return (Py_hash_t)(gintptr)(pyg_boxed_get_ptr (self)); } static PyObject * gboxed_repr(PyGBoxed *boxed) { 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; } 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 gboxed_init(PyGBoxed *self, PyObject *args, PyObject *kwargs) { gchar buf[512]; if (!PyArg_ParseTuple(args, ":GBoxed.__init__")) return -1; pyg_boxed_set_ptr (self, NULL); self->gtype = 0; self->free_on_dealloc = FALSE; g_snprintf(buf, sizeof(buf), "%s can not be constructed", Py_TYPE(self)->tp_name); PyErr_SetString(PyExc_NotImplementedError, buf); return -1; } static void gboxed_free(PyObject *op) { PyObject_FREE(op); } static PyObject * gboxed_copy(PyGBoxed *self) { return pygi_gboxed_new (self->gtype, pyg_boxed_get_ptr (self), TRUE, TRUE); } static PyMethodDef pygboxed_methods[] = { { "copy", (PyCFunction) gboxed_copy, METH_NOARGS }, { NULL, NULL, 0 } }; /** * 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. * @type: the wrapper class. * * Registers a wrapper for a boxed type. The wrapper class will be a * subclass of gobject.GBoxed, and a reference to the wrapper class * will be stored in the provided module dictionary. */ void pygi_register_gboxed (PyObject *dict, const gchar *class_name, GType boxed_type, PyTypeObject *type) { PyObject *o; g_return_if_fail(dict != NULL); g_return_if_fail(class_name != NULL); g_return_if_fail(boxed_type != 0); if (!type->tp_dealloc) type->tp_dealloc = (destructor)gboxed_dealloc; Py_SET_TYPE(type, &PyType_Type); g_assert (Py_TYPE (&PyGBoxed_Type) != NULL); type->tp_base = &PyGBoxed_Type; if (PyType_Ready(type) < 0) { g_warning("could not get type `%s' ready", type->tp_name); return; } PyDict_SetItemString(type->tp_dict, "__gtype__", o=pyg_type_wrapper_new(boxed_type)); Py_DECREF(o); g_type_set_qdata(boxed_type, pygboxed_type_key, type); PyDict_SetItemString(dict, (char *)class_name, (PyObject *)type); } /** * 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. * @own_ref: whether the boxed wrapper should own the boxed value. * * Creates a wrapper for a boxed value. If @copy_boxed is set to * True, the wrapper will hold a copy of the value, instead of the * value itself. If @own_ref is True, then the value held by the * 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 or %NULL and sets an exception. */ PyObject * pygi_gboxed_new (GType boxed_type, gpointer boxed, gboolean copy_boxed, gboolean own_ref) { PyGILState_STATE state; PyGBoxed *self; PyTypeObject *tp; g_return_val_if_fail(boxed_type != 0, NULL); g_return_val_if_fail(!copy_boxed || (copy_boxed && own_ref), NULL); state = PyGILState_Ensure(); if (!boxed) { Py_INCREF(Py_None); PyGILState_Release(state); return Py_None; } tp = g_type_get_qdata(boxed_type, pygboxed_type_key); if (!tp) tp = (PyTypeObject *)pygi_type_import_by_g_type(boxed_type); 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) { PyGILState_Release(state); return NULL; } if (copy_boxed) boxed = g_boxed_copy(boxed_type, boxed); pyg_boxed_set_ptr (self, boxed); self->gtype = boxed_type; self->free_on_dealloc = own_ref; PyGILState_Release(state); return (PyObject *)self; } /** * 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_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)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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pygboxed.h0000664000000000000000000000250315074674453014737 0ustar00rootroot/* -*- 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 . */ #ifndef __PYGOBJECT_BOXED_H__ #define __PYGOBJECT_BOXED_H__ 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__ */ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pygenum.c0000664000000000000000000002621315074674453014601 0ustar00rootroot/* -*- 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 wrapper * * 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 . */ #include #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; 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 = (&PyLong_Type)->tp_new((PyTypeObject*)subclass, args, NULL); Py_DECREF(args); if (!item) return NULL; ((PyGEnum*)item)->gtype = gtype; return item; } static PyObject * pyg_enum_richcompare(PyGEnum *self, PyObject *other, int op) { static char warning[256]; if (!PyLong_Check (other)) { Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } if (PyObject_TypeCheck(other, &PyGEnum_Type) && ((PyGEnum*)other)->gtype != self->gtype) { g_snprintf(warning, sizeof(warning), "comparing different enum types: %s and %s", g_type_name(self->gtype), g_type_name(((PyGEnum*)other)->gtype)); if (PyErr_Warn(PyExc_Warning, warning)) return NULL; } return pyg_integer_richcompare((PyObject *)self, other, op); } static PyObject * pyg_enum_repr(PyGEnum *self) { 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; if (!PyUnicode_Check (module)) { Py_DECREF (module); return NULL; } enum_class = g_type_class_ref(self->gtype); g_assert(G_IS_ENUM_CLASS(enum_class)); l = PyLong_AS_LONG ((PyObject*)self); for (index = 0; index < enum_class->n_values; index++) if (l == enum_class->values[index].value) break; module_str = PyUnicode_AsUTF8 (module); namespace = g_strrstr (module_str, "."); if (namespace == NULL) { namespace = module_str; } else { namespace += 1; } value = enum_class->values[index].value_name; if (value) sprintf(tmp, "", value, namespace, Py_TYPE (self)->tp_name); else sprintf(tmp, "", 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 * pyg_enum_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "value", NULL }; long value; PyObject *pytc, *values, *ret, *intvalue; GType gtype; GEnumClass *eclass; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "l", kwlist, &value)) return NULL; pytc = PyObject_GetAttrString((PyObject *)type, "__gtype__"); if (!pytc) return NULL; if (!PyObject_TypeCheck(pytc, &PyGTypeWrapper_Type)) { Py_DECREF(pytc); PyErr_SetString(PyExc_TypeError, "__gtype__ attribute not a typecode"); return NULL; } gtype = pyg_type_from_object(pytc); Py_DECREF(pytc); eclass = G_ENUM_CLASS(g_type_class_ref(gtype)); /* A check that 0 < value < eclass->n_values was here but got * removed: enumeration values do not need to be consequitive, * e.g. GtkPathPriorityType values are not. */ values = PyObject_GetAttrString((PyObject *)type, "__enum_values__"); if (!values) { g_type_class_unref(eclass); return NULL; } /* Note that size of __enum_values__ dictionary can easily be less * than 'n_values'. This happens if some values of the enum are * numerically equal, e.g. gtk.ANCHOR_N == gtk.ANCHOR_NORTH. * Johan said that "In retrospect, using a dictionary to store the * values might not have been that good", but we need to keep * backward compatibility. */ 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); return NULL; } g_type_class_unref(eclass); intvalue = PyLong_FromLong((int)value); ret = PyDict_GetItem(values, intvalue); Py_DECREF(intvalue); Py_DECREF(values); if (ret) Py_INCREF(ret); else PyErr_Format(PyExc_ValueError, "invalid enum value: %ld", value); return ret; } PyObject* pyg_enum_from_gtype (GType gtype, int value) { PyObject *pyclass, *values, *retval, *intvalue; g_return_val_if_fail(gtype != G_TYPE_INVALID, NULL); /* Get a wrapper class by: * 1. check for one attached to the gtype * 2. lookup one in a typelib * 3. creating a new one */ pyclass = (PyObject*)g_type_get_qdata(gtype, pygenum_class_key); if (!pyclass) pyclass = pygi_type_import_by_g_type(gtype); if (!pyclass) pyclass = pyg_enum_add(NULL, g_type_name(gtype), NULL, gtype); if (!pyclass) return PyLong_FromLong(value); values = PyDict_GetItemString(((PyTypeObject *)pyclass)->tp_dict, "__enum_values__"); intvalue = PyLong_FromLong(value); retval = PyDict_GetItem(values, intvalue); if (retval) { Py_INCREF(retval); } else { PyErr_Clear(); retval = pyg_enum_val_new(pyclass, gtype, intvalue); } Py_DECREF(intvalue); return retval; } /* * pyg_enum_add * Dynamically create a class derived from PyGEnum based on the given GType. */ PyObject * pyg_enum_add (PyObject * module, const char * typename, const char * strip_prefix, GType gtype) { PyGILState_STATE state; PyObject *instance_dict, *stub, *values, *o; GEnumClass *eclass; guint i; g_return_val_if_fail(typename != NULL, NULL); if (!g_type_is_a (gtype, G_TYPE_ENUM)) { PyErr_Format (PyExc_TypeError, "Trying to register gtype '%s' as enum when in fact it is of type '%s'", g_type_name (gtype), g_type_name (G_TYPE_FUNDAMENTAL (gtype))); return NULL; } state = PyGILState_Ensure(); /* Create a new type derived from GEnum. This is the same as: * >>> stub = type(typename, (GEnum,), {}) */ instance_dict = PyDict_New(); stub = PyObject_CallFunction((PyObject *)&PyType_Type, "s(O)O", typename, (PyObject *)&PyGEnum_Type, instance_dict); Py_DECREF(instance_dict); if (!stub) { PyErr_SetString(PyExc_RuntimeError, "can't create const"); PyGILState_Release(state); return NULL; } ((PyTypeObject *)stub)->tp_flags &= ~Py_TPFLAGS_BASETYPE; if (module) PyDict_SetItemString(((PyTypeObject *)stub)->tp_dict, "__module__", PyUnicode_FromString (PyModule_GetName(module))); g_type_set_qdata(gtype, pygenum_class_key, stub); o = pyg_type_wrapper_new(gtype); PyDict_SetItemString(((PyTypeObject *)stub)->tp_dict, "__gtype__", o); Py_DECREF(o); if (module) { /* Add it to the module name space */ PyModule_AddObject(module, (char*)typename, stub); Py_INCREF(stub); } /* Register enum values */ eclass = G_ENUM_CLASS(g_type_class_ref(gtype)); values = PyDict_New(); for (i = 0; i < eclass->n_values; i++) { PyObject *item, *intval; intval = PyLong_FromLong(eclass->values[i].value); item = pyg_enum_val_new(stub, gtype, intval); PyDict_SetItem(values, intval, item); Py_DECREF(intval); if (module) { char *prefix; prefix = g_strdup(pyg_constant_strip_prefix(eclass->values[i].value_name, strip_prefix)); PyModule_AddObject(module, prefix, item); g_free(prefix); Py_INCREF(item); } } PyDict_SetItemString(((PyTypeObject *)stub)->tp_dict, "__enum_values__", values); Py_DECREF(values); g_type_class_unref(eclass); PyGILState_Release(state); return stub; } static PyObject * pyg_enum_reduce(PyObject *self, PyObject *args) { if (!PyArg_ParseTuple(args, ":GEnum.__reduce__")) return NULL; return Py_BuildValue("(O(i)O)", Py_TYPE(self), PyLong_AsLong (self), PyObject_GetAttrString(self, "__dict__")); } static PyObject * 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, intvalue); retval = pygi_utf8_to_py (enum_value->value_name); g_type_class_unref(enum_class); return retval; } static PyObject * 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, intvalue); retval = pygi_utf8_to_py (enum_value->value_nick); g_type_class_unref(enum_class); return retval; } static PyMethodDef pyg_enum_methods[] = { { "__reduce__", (PyCFunction)pyg_enum_reduce, METH_VARARGS }, { NULL, NULL, 0 } }; static PyGetSetDef pyg_enum_getsets[] = { { "value_name", (getter)pyg_enum_get_value_name, (setter)0 }, { "value_nick", (getter)pyg_enum_get_value_nick, (setter)0 }, { NULL, 0, 0 } }; /** * 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 = &PyLong_Type; PyGEnum_Type.tp_new = pyg_enum_new; PyGEnum_Type.tp_hash = PyLong_Type.tp_hash; 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; 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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pygenum.h0000664000000000000000000000325215074674453014604 0ustar00rootroot/* -*- 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 . */ #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__ */ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pygflags.c0000664000000000000000000003521115074674453014727 0ustar00rootroot/* -*- Mode: C; c-basic-offset: 4 -*- * pygtk- Python bindings for the GTK toolkit. * Copyright (C) 1998-2003 James Henstridge * Copyright (C) 2004 Johan Dahlin * * pygflags.c: GFlags wrapper * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * 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 . */ #include #include "pygi-type.h" #include "pygi-util.h" #include "pygi-type.h" #include "pygflags.h" #include "pygboxed.h" GQuark pygflags_class_key; PYGI_DEFINE_TYPE("gobject.GFlags", PyGFlags_Type, PyGFlags); static PyObject * 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 = PyLong_Type.tp_new((PyTypeObject*)subclass, args, NULL); Py_DECREF(args); if (!item) return NULL; ((PyGFlags*)item)->gtype = gtype; return item; } static PyObject * pyg_flags_richcompare(PyGFlags *self, PyObject *other, int op) { static char warning[256]; if (!PyLong_Check (other)) { Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } if (PyObject_TypeCheck(other, &PyGFlags_Type) && ((PyGFlags*)other)->gtype != self->gtype) { g_snprintf(warning, sizeof(warning), "comparing different flags types: %s and %s", g_type_name(self->gtype), g_type_name(((PyGFlags*)other)->gtype)); if (PyErr_Warn(PyExc_Warning, warning)) return NULL; } return pyg_integer_richcompare((PyObject *)self, other, op); } static char * generate_repr(GType gtype, guint value) { GFlagsClass *flags_class; char *retval = NULL, *tmp; guint i; flags_class = g_type_class_ref(gtype); g_assert(G_IS_FLAGS_CLASS(flags_class)); for (i = 0; i < flags_class->n_values; i++) { /* Some types (eg GstElementState in GStreamer 0.8) has flags with 0 values, * we're just ignore them for now otherwise they'll always show up */ if (flags_class->values[i].value == 0) continue; if ((value & flags_class->values[i].value) == flags_class->values[i].value) { if (retval) { tmp = g_strdup_printf("%s | %s", retval, flags_class->values[i].value_name); g_free(retval); retval = tmp; } else { retval = g_strdup_printf("%s", flags_class->values[i].value_name); } } } g_type_class_unref(flags_class); return retval; } static PyObject * pyg_flags_repr(PyGFlags *self) { 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; } 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("", tmp, namespace, Py_TYPE (self)->tp_name); else retval = g_strdup_printf("", PyLong_AsUnsignedLongMask ((PyObject*)self), namespace, Py_TYPE (self)->tp_name); g_free(tmp); Py_DECREF (module); pyretval = PyUnicode_FromString (retval); g_free(retval); return pyretval; } static PyObject * pyg_flags_new(PyTypeObject *type, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "value", NULL }; gulong value; PyObject *pytc, *values, *ret, *pyint; GType gtype; GFlagsClass *eclass; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "k", kwlist, &value)) return NULL; pytc = PyObject_GetAttrString((PyObject *)type, "__gtype__"); if (!pytc) return NULL; if (!PyObject_TypeCheck(pytc, &PyGTypeWrapper_Type)) { Py_DECREF(pytc); PyErr_SetString(PyExc_TypeError, "__gtype__ attribute not a typecode"); return NULL; } gtype = pyg_type_from_object(pytc); Py_DECREF(pytc); eclass = G_FLAGS_CLASS(g_type_class_ref(gtype)); values = PyObject_GetAttrString((PyObject *)type, "__flags_values__"); if (!values) { g_type_class_unref(eclass); return NULL; } if (!PyDict_Check(values)) { PyErr_SetString(PyExc_TypeError, "__flags_values__ badly formed"); Py_DECREF(values); g_type_class_unref(eclass); return NULL; } g_type_class_unref(eclass); pyint = PyLong_FromUnsignedLong (value); ret = PyDict_GetItem(values, pyint); if (!ret) { PyErr_Clear(); ret = pyg_flags_val_new((PyObject *)type, gtype, pyint); g_assert(ret != NULL); } else { Py_INCREF(ret); } Py_DECREF(pyint); Py_DECREF(values); return ret; } PyObject* pyg_flags_from_gtype (GType gtype, guint value) { PyObject *pyclass, *values, *retval, *pyint; if (PyErr_Occurred()) return PyLong_FromUnsignedLong (0); g_return_val_if_fail(gtype != G_TYPE_INVALID, NULL); /* Get a wrapper class by: * 1. check for one attached to the gtype * 2. lookup one in a typelib * 3. creating a new one */ pyclass = (PyObject*)g_type_get_qdata(gtype, pygflags_class_key); if (!pyclass) pyclass = pygi_type_import_by_g_type(gtype); if (!pyclass) pyclass = pyg_flags_add(NULL, g_type_name(gtype), NULL, gtype); if (!pyclass) return PyLong_FromUnsignedLong (value); values = PyDict_GetItemString(((PyTypeObject *)pyclass)->tp_dict, "__flags_values__"); pyint = PyLong_FromUnsignedLong (value); retval = PyDict_GetItem(values, pyint); if (!retval) { PyErr_Clear(); retval = pyg_flags_val_new(pyclass, gtype, pyint); g_assert(retval != NULL); } else { Py_INCREF(retval); } Py_DECREF(pyint); return retval; } /* * pyg_flags_add * Dynamically create a class derived from PyGFlags based on the given GType. */ PyObject * pyg_flags_add (PyObject * module, const char * typename, const char * strip_prefix, GType gtype) { PyGILState_STATE state; PyObject *instance_dict, *stub, *values, *o; GFlagsClass *eclass; guint i; g_return_val_if_fail(typename != NULL, NULL); if (!g_type_is_a(gtype, G_TYPE_FLAGS)) { g_warning("Trying to register gtype '%s' as flags when in fact it is of type '%s'", g_type_name(gtype), g_type_name(G_TYPE_FUNDAMENTAL(gtype))); return NULL; } state = PyGILState_Ensure(); /* Create a new type derived from GFlags. This is the same as: * >>> stub = type(typename, (GFlags,), {}) */ instance_dict = PyDict_New(); stub = PyObject_CallFunction((PyObject *)&PyType_Type, "s(O)O", typename, (PyObject *)&PyGFlags_Type, instance_dict); Py_DECREF(instance_dict); if (!stub) { PyErr_SetString(PyExc_RuntimeError, "can't create GFlags subtype"); PyGILState_Release(state); return NULL; } ((PyTypeObject *)stub)->tp_flags &= ~Py_TPFLAGS_BASETYPE; if (module) { PyDict_SetItemString(((PyTypeObject *)stub)->tp_dict, "__module__", PyUnicode_FromString (PyModule_GetName(module))); /* Add it to the module name space */ PyModule_AddObject(module, (char*)typename, stub); Py_INCREF(stub); } g_type_set_qdata(gtype, pygflags_class_key, stub); o = pyg_type_wrapper_new(gtype); PyDict_SetItemString(((PyTypeObject *)stub)->tp_dict, "__gtype__", o); Py_DECREF(o); /* Register flag values */ eclass = G_FLAGS_CLASS(g_type_class_ref(gtype)); values = PyDict_New(); for (i = 0; i < eclass->n_values; i++) { PyObject *item, *intval; 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); Py_DECREF(intval); if (module) { char *prefix; prefix = g_strdup(pyg_constant_strip_prefix(eclass->values[i].value_name, strip_prefix)); Py_INCREF(item); PyModule_AddObject(module, prefix, item); g_free(prefix); } Py_DECREF(item); } PyDict_SetItemString(((PyTypeObject *)stub)->tp_dict, "__flags_values__", values); Py_DECREF(values); g_type_class_unref(eclass); PyGILState_Release(state); return stub; } static PyObject * pyg_flags_and(PyGFlags *a, PyGFlags *b) { if (!PyGFlags_Check(a) || !PyGFlags_Check(b)) return PyLong_Type.tp_as_number->nb_and((PyObject*)a, (PyObject*)b); return pyg_flags_from_gtype(a->gtype, (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 PyLong_Type.tp_as_number->nb_or((PyObject*)a, (PyObject*)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 PyLong_Type.tp_as_number->nb_xor((PyObject*)a, (PyObject*)b); return pyg_flags_from_gtype(a->gtype, (guint)(PyLong_AsUnsignedLongMask ((PyObject*)a) ^ PyLong_AsUnsignedLongMask ((PyObject*)b))); } static PyObject * pyg_flags_warn (PyObject *self, PyObject *args) { if (PyErr_Warn(PyExc_Warning, "unsupported arithmetic operation for flags type")) return NULL; Py_INCREF(Py_None); return Py_None; } static PyObject * pyg_flags_get_first_value_name(PyGFlags *self, void *closure) { GFlagsClass *flags_class; GFlagsValue *flags_value; PyObject *retval; 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, (guint)PyLong_AsUnsignedLongMask ((PyObject*)self)); if (flags_value) retval = PyUnicode_FromString (flags_value->value_name); else { retval = Py_None; Py_INCREF(Py_None); } g_type_class_unref(flags_class); return retval; } static PyObject * pyg_flags_get_first_value_nick(PyGFlags *self, void *closure) { GFlagsClass *flags_class; GFlagsValue *flags_value; PyObject *retval; 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, (guint)PyLong_AsUnsignedLongMask ((PyObject*)self)); if (flags_value) retval = PyUnicode_FromString (flags_value->value_nick); else { retval = Py_None; Py_INCREF(Py_None); } g_type_class_unref(flags_class); return retval; } static PyObject * pyg_flags_get_value_names(PyGFlags *self, void *closure) { GFlagsClass *flags_class; PyObject *retval; 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++) { 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); return retval; } static PyObject * pyg_flags_get_value_nicks(PyGFlags *self, void *closure) { GFlagsClass *flags_class; PyObject *retval; 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 ((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); } g_type_class_unref(flags_class); return retval; } static PyGetSetDef pyg_flags_getsets[] = { { "first_value_name", (getter)pyg_flags_get_first_value_name, (setter)0 }, { "first_value_nick", (getter)pyg_flags_get_first_value_nick, (setter)0 }, { "value_names", (getter)pyg_flags_get_value_names, (setter)0 }, { "value_nicks", (getter)pyg_flags_get_value_nicks, (setter)0 }, { NULL, 0, 0 } }; static PyNumberMethods pyg_flags_as_number = { (binaryfunc)pyg_flags_warn, /* nb_add */ (binaryfunc)pyg_flags_warn, /* nb_subtract */ (binaryfunc)pyg_flags_warn, /* nb_multiply */ (binaryfunc)pyg_flags_warn, /* nb_divide */ (binaryfunc)pyg_flags_warn, /* nb_remainder */ (ternaryfunc)pyg_flags_warn, /* nb_power */ 0, /* nb_negative */ 0, /* nb_positive */ 0, /* nb_absolute */ 0, /* nb_nonzero */ 0, /* nb_invert */ 0, /* nb_lshift */ 0, /* nb_rshift */ (binaryfunc)pyg_flags_and, /* nb_and */ (binaryfunc)pyg_flags_xor, /* nb_xor */ (binaryfunc)pyg_flags_or, /* nb_or */ }; /** * 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 = &PyLong_Type; PyGFlags_Type.tp_new = pyg_flags_new; 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; 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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pygflags.h0000664000000000000000000000334415074674453014736 0ustar00rootroot/* -*- 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 . */ #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__ */ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pygi-argument.c0000664000000000000000000013133015074674453015702 0ustar00rootroot/* -*- Mode: C; c-basic-offset: 4 -*- * vim: tabstop=4 shiftwidth=4 expandtab * * Copyright (C) 2005-2009 Johan Dahlin * * pygi-argument.c: GIArgument - PyObject conversion functions. * * 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 . */ #include #include #include #include "pygobject-internal.h" #include #include #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" gboolean pygi_argument_to_gssize (GIArgument *arg_in, GITypeTag type_tag, gssize *gssize_out) { switch (type_tag) { case GI_TYPE_TAG_INT8: *gssize_out = arg_in->v_int8; return TRUE; case GI_TYPE_TAG_UINT8: *gssize_out = arg_in->v_uint8; return TRUE; case GI_TYPE_TAG_INT16: *gssize_out = arg_in->v_int16; return TRUE; case GI_TYPE_TAG_UINT16: *gssize_out = arg_in->v_uint16; return TRUE; case GI_TYPE_TAG_INT32: *gssize_out = arg_in->v_int32; return TRUE; case GI_TYPE_TAG_UINT32: *gssize_out = arg_in->v_uint32; return TRUE; case GI_TYPE_TAG_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: 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, "Unable to marshal %s to gssize", g_type_tag_to_string(type_tag)); return FALSE; } } 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, GITypeInfo *type_info) { GITypeTag type_tag = _pygi_get_storage_type (type_info); switch (type_tag) { case GI_TYPE_TAG_INT8: arg->v_int8 = (gint8)GPOINTER_TO_INT (arg->v_pointer); break; case GI_TYPE_TAG_INT16: arg->v_int16 = (gint16)GPOINTER_TO_INT (arg->v_pointer); break; case GI_TYPE_TAG_INT32: arg->v_int32 = (gint32)GPOINTER_TO_INT (arg->v_pointer); break; case GI_TYPE_TAG_UINT8: arg->v_uint8 = (guint8)GPOINTER_TO_UINT (arg->v_pointer); break; case GI_TYPE_TAG_UINT16: arg->v_uint16 = (guint16)GPOINTER_TO_UINT (arg->v_pointer); break; case GI_TYPE_TAG_UINT32: 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)); } } gpointer _pygi_arg_to_hash_pointer (const GIArgument *arg, 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); case GI_TYPE_TAG_UINT8: return GINT_TO_POINTER (arg->v_uint8); case GI_TYPE_TAG_INT16: return GINT_TO_POINTER (arg->v_int16); case GI_TYPE_TAG_UINT16: return GINT_TO_POINTER (arg->v_uint16); case GI_TYPE_TAG_INT32: 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)); return arg->v_pointer; } } /** * _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) { 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 array_len; } /** * _pygi_argument_to_array * @arg: The argument to convert * @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 * * Make sure an array type argument is wrapped in a GArray. * * Note: This method can *not* be folded into _pygi_argument_to_object() because * arrays are special in the sense that they might require access to @args in * order to get the length. * * Returns: A GArray wrapping @arg. If @out_free_array has been set to TRUE then * free the array with g_array_free() without freeing the data members. * Otherwise don't free the array. */ GArray * _pygi_argument_to_array (GIArgument *arg, PyGIArgArrayLengthPolicy array_length_policy, void *user_data1, void *user_data2, GITypeInfo *type_info, gboolean *out_free_array) { GITypeInfo *item_type_info; gboolean is_zero_terminated; gsize item_size; gssize length; GArray *g_array; g_return_val_if_fail (g_type_info_get_tag (type_info) == GI_TYPE_TAG_ARRAY, NULL); if (arg->v_pointer == NULL) { return NULL; } switch (g_type_info_get_array_type (type_info)) { case GI_ARRAY_TYPE_C: is_zero_terminated = g_type_info_is_zero_terminated (type_info); item_type_info = g_type_info_get_param_type (type_info, 0); item_size = _pygi_g_type_info_size (item_type_info); g_base_info_unref ( (GIBaseInfo *) item_type_info); if (is_zero_terminated) { 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; 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, (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); 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, (guint)item_size); g_free (g_array->data); g_array->data = arg->v_pointer; g_array->len = (guint)length; *out_free_array = TRUE; break; case GI_ARRAY_TYPE_ARRAY: case GI_ARRAY_TYPE_BYTE_ARRAY: /* Note: GByteArray is really just a GArray */ g_array = arg->v_pointer; *out_free_array = FALSE; break; case GI_ARRAY_TYPE_PTR_ARRAY: { GPtrArray *ptr_array = (GPtrArray*) arg->v_pointer; g_array = g_array_sized_new (FALSE, FALSE, sizeof(gpointer), ptr_array->len); g_array->data = (char*) ptr_array->pdata; g_array->len = ptr_array->len; *out_free_array = TRUE; break; } default: g_critical ("Unexpected array type %u", g_type_info_get_array_type (type_info)); g_array = NULL; break; } return g_array; } GIArgument _pygi_argument_from_object (PyObject *object, GITypeInfo *type_info, GITransfer transfer) { GIArgument arg; GITypeTag type_tag; gpointer cleanup_data = NULL; memset(&arg, 0, sizeof(GIArgument)); type_tag = g_type_info_get_tag (type_info); switch (type_tag) { case GI_TYPE_TAG_ARRAY: { Py_ssize_t py_length; guint length, i; gboolean is_zero_terminated; GITypeInfo *item_type_info; gsize item_size; GArray *array; GITransfer item_transfer; if (object == Py_None) { arg.v_pointer = NULL; break; } /* Note, strings are sequences, but we cannot accept them here */ if (!PySequence_Check (object) || PyUnicode_Check (object)) { PyErr_SetString (PyExc_TypeError, "expected sequence"); break; } 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); /* we handle arrays that are really strings specially, see below */ if (g_type_info_get_tag (item_type_info) == GI_TYPE_TAG_UINT8) item_size = 1; else item_size = sizeof (GIArgument); 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(); break; } if (g_type_info_get_tag (item_type_info) == GI_TYPE_TAG_UINT8 && PyBytes_Check (object)) { memcpy(array->data, PyBytes_AsString (object), length); array->len = length; goto array_success; } item_transfer = transfer == GI_TRANSFER_CONTAINER ? GI_TRANSFER_NOTHING : transfer; for (i = 0; i < length; i++) { PyObject *py_item; GIArgument item; py_item = PySequence_GetItem (object, i); if (py_item == NULL) { goto array_item_error; } item = _pygi_argument_from_object (py_item, item_type_info, item_transfer); Py_DECREF (py_item); if (PyErr_Occurred()) { goto array_item_error; } g_array_insert_val (array, i, item); continue; array_item_error: /* Free everything we have converted so far. */ _pygi_argument_release ( (GIArgument *) &array, type_info, GI_TRANSFER_NOTHING, GI_DIRECTION_IN); array = NULL; _PyGI_ERROR_PREFIX ("Item %u: ", i); break; } array_success: arg.v_pointer = array; g_base_info_unref ( (GIBaseInfo *) item_type_info); 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); switch (info_type) { case GI_INFO_TYPE_CALLBACK: PyErr_SetString (PyExc_TypeError, "Cannot translate Python object to callback type"); break; case GI_INFO_TYPE_BOXED: case GI_INFO_TYPE_STRUCT: case GI_INFO_TYPE_UNION: { 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); /* Note for G_TYPE_VALUE g_type: * This will currently leak the GValue that is allocated and * stashed in arg.v_pointer. Out argument marshaling for caller * allocated GValues already pass in memory for the GValue. * Further re-factoring is needed to fix this leak. * See: https://bugzilla.gnome.org/show_bug.cgi?id=693405 */ 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: { GType g_type; g_type = g_registered_type_info_get_g_type ( (GIRegisteredTypeInfo *) info); if (pyg_enum_get_value(g_type, object, &arg.v_int) < 0) break; break; } case GI_INFO_TYPE_FLAGS: { GType g_type; 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_arg_gobject_out_arg_from_py (object, &arg, transfer); break; default: g_assert_not_reached(); } g_base_info_unref (info); break; } case GI_TYPE_TAG_GLIST: case GI_TYPE_TAG_GSLIST: { Py_ssize_t length; GITypeInfo *item_type_info; GSList *list = NULL; GITransfer item_transfer; Py_ssize_t i; if (object == Py_None) { arg.v_pointer = NULL; break; } length = PySequence_Length (object); if (length < 0) { break; } item_type_info = g_type_info_get_param_type (type_info, 0); g_assert (item_type_info != NULL); item_transfer = transfer == GI_TRANSFER_CONTAINER ? GI_TRANSFER_NOTHING : transfer; for (i = length - 1; i >= 0; i--) { PyObject *py_item; GIArgument item; py_item = PySequence_GetItem (object, i); if (py_item == NULL) { goto list_item_error; } item = _pygi_argument_from_object (py_item, item_type_info, item_transfer); Py_DECREF (py_item); if (PyErr_Occurred()) { goto list_item_error; } if (type_tag == GI_TYPE_TAG_GLIST) { list = (GSList *) g_list_prepend ( (GList *) list, item.v_pointer); } else { list = g_slist_prepend (list, item.v_pointer); } continue; list_item_error: /* Free everything we have converted so far. */ _pygi_argument_release ( (GIArgument *) &list, type_info, GI_TRANSFER_NOTHING, GI_DIRECTION_IN); list = NULL; _PyGI_ERROR_PREFIX ("Item %zd: ", i); break; } arg.v_pointer = list; 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; GITypeTag key_type_tag; GHashFunc hash_func; GEqualFunc equal_func; GHashTable *hash_table; GITransfer item_transfer; Py_ssize_t i; if (object == Py_None) { arg.v_pointer = NULL; break; } length = PyMapping_Length (object); if (length < 0) { break; } keys = PyMapping_Keys (object); if (keys == NULL) { break; } values = PyMapping_Values (object); if (values == NULL) { 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); key_type_tag = g_type_info_get_tag (key_type_info); switch (key_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_table = g_hash_table_new (hash_func, equal_func); if (hash_table == NULL) { PyErr_NoMemory(); goto hash_table_release; } item_transfer = transfer == GI_TRANSFER_CONTAINER ? GI_TRANSFER_NOTHING : transfer; for (i = 0; i < length; i++) { PyObject *py_key; PyObject *py_value; GIArgument key; GIArgument value; py_key = PyList_GET_ITEM (keys, i); py_value = PyList_GET_ITEM (values, i); key = _pygi_argument_from_object (py_key, key_type_info, item_transfer); if (PyErr_Occurred()) { goto hash_table_item_error; } value = _pygi_argument_from_object (py_value, value_type_info, item_transfer); if (PyErr_Occurred()) { _pygi_argument_release (&key, type_info, GI_TRANSFER_NOTHING, GI_DIRECTION_IN); goto hash_table_item_error; } g_hash_table_insert (hash_table, key.v_pointer, _pygi_arg_to_hash_pointer (&value, value_type_info)); continue; hash_table_item_error: /* Free everything we have converted so far. */ _pygi_argument_release ( (GIArgument *) &hash_table, type_info, GI_TRANSFER_NOTHING, GI_DIRECTION_IN); hash_table = NULL; _PyGI_ERROR_PREFIX ("Item %zd: ", i); break; } arg.v_pointer = hash_table; hash_table_release: g_base_info_unref ( (GIBaseInfo *) key_type_info); g_base_info_unref ( (GIBaseInfo *) value_type_info); Py_DECREF (keys); Py_DECREF (values); break; } case GI_TYPE_TAG_ERROR: PyErr_SetString (PyExc_NotImplementedError, "error marshalling is not supported yet"); /* TODO */ break; default: /* Ignores cleanup data for now. */ pygi_marshal_from_py_basic_type (object, &arg, type_tag, transfer, &cleanup_data); break; } return arg; } /** * _pygi_argument_to_object: * @arg: The argument to convert to an object. * @type_info: Type info for @arg * @transfer: * * If the argument is of type array, it must be encoded in a GArray, by calling * _pygi_argument_to_array(). This logic can not be folded into this method * as determining array lengths may require access to method call arguments. * * Returns: A PyObject representing @arg */ PyObject * _pygi_argument_to_object (GIArgument *arg, GITypeInfo *type_info, GITransfer transfer) { GITypeTag type_tag; PyObject *object = NULL; type_tag = g_type_info_get_tag (type_info); switch (type_tag) { case GI_TYPE_TAG_VOID: { if (g_type_info_is_pointer (type_info)) { g_warn_if_fail (transfer == GI_TRANSFER_NOTHING); object = PyLong_FromVoidPtr (arg->v_pointer); } break; } case GI_TYPE_TAG_ARRAY: { /* Arrays are assumed to be packed in a GArray */ GArray *array; GITypeInfo *item_type_info; GITypeTag item_type_tag; GITransfer item_transfer; gsize i, item_size; if (arg->v_pointer == NULL) return PyList_New (0); item_type_info = g_type_info_get_param_type (type_info, 0); g_assert (item_type_info != NULL); item_type_tag = g_type_info_get_tag (item_type_info); item_transfer = transfer == GI_TRANSFER_CONTAINER ? GI_TRANSFER_NOTHING : transfer; array = arg->v_pointer; item_size = g_array_get_element_size (array); if (G_UNLIKELY (item_size > sizeof(GIArgument))) { g_critical ("Stack overflow protection. " "Can't copy array element into GIArgument."); return PyList_New (0); } if (item_type_tag == GI_TYPE_TAG_UINT8) { /* Return as a byte array */ object = PyBytes_FromStringAndSize (array->data, array->len); } else { object = PyList_New (array->len); if (object == NULL) { g_critical ("Failure to allocate array for %u items", array->len); g_base_info_unref ( (GIBaseInfo *) item_type_info); break; } for (i = 0; i < array->len; i++) { GIArgument item = { 0 }; PyObject *py_item; memcpy (&item, array->data + i * item_size, item_size); py_item = _pygi_argument_to_object (&item, item_type_info, item_transfer); if (py_item == NULL) { Py_CLEAR (object); _PyGI_ERROR_PREFIX ("Item %zu: ", i); break; } PyList_SET_ITEM (object, i, py_item); } } g_base_info_unref ( (GIBaseInfo *) item_type_info); 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); switch (info_type) { case GI_INFO_TYPE_CALLBACK: PyErr_SetString (PyExc_TypeError, "Cannot translate callback type to Python object"); break; case GI_INFO_TYPE_BOXED: case GI_INFO_TYPE_STRUCT: case GI_INFO_TYPE_UNION: { 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); } else { py_type = pygi_type_get_from_g_type (g_type); } 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; } case GI_INFO_TYPE_ENUM: case GI_INFO_TYPE_FLAGS: { GType type; type = g_registered_type_info_get_g_type ( (GIRegisteredTypeInfo *) info); 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_args = NULL; if (!py_type) return NULL; py_args = PyTuple_New (1); if (PyTuple_SetItem (py_args, 0, pygi_gint_to_py (arg->v_int)) != 0) { Py_DECREF (py_args); Py_DECREF (py_type); return NULL; } object = PyObject_CallFunction (py_type, "i", arg->v_int); Py_DECREF (py_args); Py_DECREF (py_type); } else if (info_type == GI_INFO_TYPE_ENUM) { object = pyg_enum_from_gtype (type, arg->v_int); } else { object = pyg_flags_from_gtype (type, arg->v_uint); } break; } case GI_INFO_TYPE_INTERFACE: case GI_INFO_TYPE_OBJECT: object = pygi_arg_object_to_py_called_from_c (arg, transfer); break; default: g_assert_not_reached(); } g_base_info_unref (info); break; } case GI_TYPE_TAG_GLIST: case GI_TYPE_TAG_GSLIST: { GSList *list; gsize length; GITypeInfo *item_type_info; GITransfer item_transfer; gsize i; list = arg->v_pointer; length = g_slist_length (list); object = PyList_New (length); if (object == NULL) { break; } item_type_info = g_type_info_get_param_type (type_info, 0); g_assert (item_type_info != NULL); item_transfer = transfer == GI_TRANSFER_CONTAINER ? GI_TRANSFER_NOTHING : transfer; for (i = 0; list != NULL; list = g_slist_next (list), i++) { GIArgument item; PyObject *py_item; item.v_pointer = list->data; py_item = _pygi_argument_to_object (&item, item_type_info, item_transfer); if (py_item == NULL) { Py_CLEAR (object); _PyGI_ERROR_PREFIX ("Item %zu: ", i); break; } PyList_SET_ITEM (object, i, py_item); } g_base_info_unref ( (GIBaseInfo *) item_type_info); break; } case GI_TYPE_TAG_GHASH: { GITypeInfo *key_type_info; GITypeInfo *value_type_info; GITransfer item_transfer; GHashTableIter hash_table_iter; GIArgument key; GIArgument value; if (arg->v_pointer == NULL) { object = Py_None; Py_INCREF (object); break; } object = PyDict_New(); if (object == NULL) { break; } key_type_info = g_type_info_get_param_type (type_info, 0); g_assert (key_type_info != NULL); g_assert (g_type_info_get_tag (key_type_info) != GI_TYPE_TAG_VOID); value_type_info = g_type_info_get_param_type (type_info, 1); g_assert (value_type_info != NULL); g_assert (g_type_info_get_tag (value_type_info) != GI_TYPE_TAG_VOID); item_transfer = transfer == GI_TRANSFER_CONTAINER ? GI_TRANSFER_NOTHING : transfer; g_hash_table_iter_init (&hash_table_iter, (GHashTable *) arg->v_pointer); while (g_hash_table_iter_next (&hash_table_iter, &key.v_pointer, &value.v_pointer)) { PyObject *py_key; PyObject *py_value; int retval; py_key = _pygi_argument_to_object (&key, key_type_info, item_transfer); if (py_key == NULL) { break; } _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); break; } retval = PyDict_SetItem (object, py_key, py_value); Py_DECREF (py_key); Py_DECREF (py_value); if (retval < 0) { Py_CLEAR (object); break; } } g_base_info_unref ( (GIBaseInfo *) key_type_info); g_base_info_unref ( (GIBaseInfo *) value_type_info); break; } case GI_TYPE_TAG_ERROR: { 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 pygi_error_check() is going to free it. */ error = g_error_copy (error); } if (pygi_error_check (&error)) { PyObject *err_type; PyObject *err_value; PyObject *err_trace; PyErr_Fetch (&err_type, &err_value, &err_trace); Py_XDECREF (err_type); Py_XDECREF (err_trace); object = err_value; } else { object = Py_None; Py_INCREF (object); break; } break; } default: { object = pygi_marshal_to_py_basic_type (arg, type_tag, transfer); } } return object; } void _pygi_argument_release (GIArgument *arg, GITypeInfo *type_info, GITransfer transfer, GIDirection direction) { GITypeTag type_tag; gboolean is_out = (direction == GI_DIRECTION_OUT || direction == GI_DIRECTION_INOUT); type_tag = g_type_info_get_tag (type_info); switch (type_tag) { case GI_TYPE_TAG_VOID: /* Don't do anything, it's transparent to the C side */ 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_GTYPE: case GI_TYPE_TAG_UNICHAR: break; case GI_TYPE_TAG_FILENAME: case GI_TYPE_TAG_UTF8: /* With allow-none support the string could be NULL */ if ((arg->v_string != NULL && (direction == GI_DIRECTION_IN && transfer == GI_TRANSFER_NOTHING)) || (direction == GI_DIRECTION_OUT && transfer == GI_TRANSFER_EVERYTHING)) { g_free (arg->v_string); } break; case GI_TYPE_TAG_ARRAY: { GArray *array; gsize i; if (arg->v_pointer == NULL) { return; } array = arg->v_pointer; if ( (direction == GI_DIRECTION_IN && transfer != GI_TRANSFER_EVERYTHING) || (direction == GI_DIRECTION_OUT && transfer == GI_TRANSFER_EVERYTHING)) { GITypeInfo *item_type_info; GITransfer item_transfer; item_type_info = g_type_info_get_param_type (type_info, 0); item_transfer = direction == GI_DIRECTION_IN ? GI_TRANSFER_NOTHING : GI_TRANSFER_EVERYTHING; /* Free the items */ for (i = 0; i < array->len; i++) { 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); } if ( (direction == GI_DIRECTION_IN && transfer == GI_TRANSFER_NOTHING) || (direction == GI_DIRECTION_OUT && transfer != GI_TRANSFER_NOTHING)) { g_array_free (array, TRUE); } 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); switch (info_type) { case GI_INFO_TYPE_CALLBACK: /* TODO */ break; case GI_INFO_TYPE_BOXED: case GI_INFO_TYPE_STRUCT: case GI_INFO_TYPE_UNION: { GType type; if (arg->v_pointer == NULL) { return; } type = g_registered_type_info_get_g_type ( (GIRegisteredTypeInfo *) info); if (g_type_is_a (type, G_TYPE_VALUE)) { GValue *value; value = arg->v_pointer; if ( (direction == GI_DIRECTION_IN && transfer != GI_TRANSFER_EVERYTHING) || (direction == GI_DIRECTION_OUT && transfer == GI_TRANSFER_EVERYTHING)) { g_value_unset (value); } if ( (direction == GI_DIRECTION_IN && transfer == GI_TRANSFER_NOTHING) || (direction == GI_DIRECTION_OUT && transfer != GI_TRANSFER_NOTHING)) { g_slice_free (GValue, value); } } else if (g_type_is_a (type, G_TYPE_CLOSURE)) { if (direction == GI_DIRECTION_IN && transfer == GI_TRANSFER_NOTHING) { g_closure_unref (arg->v_pointer); } } 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); } } else if (g_type_is_a (type, G_TYPE_BOXED)) { } else if (g_type_is_a (type, G_TYPE_POINTER) || type == G_TYPE_NONE) { g_warn_if_fail (!g_type_info_is_pointer (type_info) || transfer == GI_TRANSFER_NOTHING); } break; } case GI_INFO_TYPE_ENUM: case GI_INFO_TYPE_FLAGS: break; case GI_INFO_TYPE_INTERFACE: case GI_INFO_TYPE_OBJECT: if (arg->v_pointer == NULL) { return; } if (is_out && transfer == GI_TRANSFER_EVERYTHING) { g_object_unref (arg->v_pointer); } break; default: g_assert_not_reached(); } g_base_info_unref (info); break; } case GI_TYPE_TAG_GLIST: case GI_TYPE_TAG_GSLIST: { GSList *list; if (arg->v_pointer == NULL) { return; } list = arg->v_pointer; if ( (direction == GI_DIRECTION_IN && transfer != GI_TRANSFER_EVERYTHING) || (direction == GI_DIRECTION_OUT && transfer == GI_TRANSFER_EVERYTHING)) { GITypeInfo *item_type_info; GITransfer item_transfer; GSList *item; item_type_info = g_type_info_get_param_type (type_info, 0); g_assert (item_type_info != NULL); item_transfer = direction == GI_DIRECTION_IN ? GI_TRANSFER_NOTHING : GI_TRANSFER_EVERYTHING; /* Free the items */ for (item = list; item != NULL; item = g_slist_next (item)) { _pygi_argument_release ( (GIArgument *) &item->data, item_type_info, item_transfer, direction); } g_base_info_unref ( (GIBaseInfo *) item_type_info); } if ( (direction == GI_DIRECTION_IN && transfer == GI_TRANSFER_NOTHING) || (direction == GI_DIRECTION_OUT && transfer != GI_TRANSFER_NOTHING)) { if (type_tag == GI_TYPE_TAG_GLIST) { g_list_free ( (GList *) list); } else { /* type_tag == GI_TYPE_TAG_GSLIST */ g_slist_free (list); } } break; } case GI_TYPE_TAG_GHASH: { GHashTable *hash_table; if (arg->v_pointer == NULL) { return; } hash_table = arg->v_pointer; if (direction == GI_DIRECTION_IN && transfer != GI_TRANSFER_EVERYTHING) { /* We created the table without a destroy function, so keys and * values need to be released. */ GITypeInfo *key_type_info; GITypeInfo *value_type_info; GITransfer item_transfer; GHashTableIter hash_table_iter; gpointer key; gpointer value; 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); if (direction == GI_DIRECTION_IN) { item_transfer = GI_TRANSFER_NOTHING; } else { item_transfer = GI_TRANSFER_EVERYTHING; } g_hash_table_iter_init (&hash_table_iter, hash_table); while (g_hash_table_iter_next (&hash_table_iter, &key, &value)) { _pygi_argument_release ( (GIArgument *) &key, key_type_info, item_transfer, direction); _pygi_argument_release ( (GIArgument *) &value, value_type_info, item_transfer, direction); } g_base_info_unref ( (GIBaseInfo *) key_type_info); g_base_info_unref ( (GIBaseInfo *) value_type_info); } else if (direction == GI_DIRECTION_OUT && transfer == GI_TRANSFER_CONTAINER) { /* Be careful to avoid keys and values being freed if the * callee gave a destroy function. */ g_hash_table_steal_all (hash_table); } if ( (direction == GI_DIRECTION_IN && transfer == GI_TRANSFER_NOTHING) || (direction == GI_DIRECTION_OUT && transfer != GI_TRANSFER_NOTHING)) { g_hash_table_unref (hash_table); } break; } case GI_TYPE_TAG_ERROR: { GError *error; if (arg->v_pointer == NULL) { return; } error = * (GError **) arg->v_pointer; if (error != NULL) { g_error_free (error); } g_slice_free (GError *, arg->v_pointer); break; } default: break; } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pygi-argument.h0000664000000000000000000000522215074674453015707 0ustar00rootroot/* -*- Mode: C; c-basic-offset: 4 -*- * vim: tabstop=4 shiftwidth=4 expandtab * * Copyright (C) 2005-2009 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 . */ #ifndef __PYGI_ARGUMENT_H__ #define __PYGI_ARGUMENT_H__ #include #include G_BEGIN_DECLS /* Private */ typedef gssize (*PyGIArgArrayLengthPolicy) (gsize item_index, void *user_data1, void *user_data2); gssize _pygi_argument_array_length_marshal (gsize length_arg_index, void *user_data1, void *user_data2); 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, PyGIArgArrayLengthPolicy array_length_policy, void *user_data1, void *user_data2, GITypeInfo *type_info, gboolean *out_free_array); GIArgument _pygi_argument_from_object (PyObject *object, GITypeInfo *type_info, GITransfer transfer); PyObject* _pygi_argument_to_object (GIArgument *arg, GITypeInfo *type_info, GITransfer transfer); void _pygi_argument_release (GIArgument *arg, GITypeInfo *type_info, GITransfer transfer, GIDirection direction); gboolean pygi_argument_to_gssize (GIArgument *arg_in, GITypeTag type_tag, gssize *gssize_out); G_END_DECLS #endif /* __PYGI_ARGUMENT_H__ */ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pygi-array.c0000664000000000000000000010625615074674453015207 0ustar00rootroot/* -*- Mode: C; c-basic-offset: 4 -*- * vim: tabstop=4 shiftwidth=4 expandtab * * Copyright (C) 2011 John (J5) Palmieri * Copyright (C) 2014 Simon Feltman * * 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 . */ #include #include #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); 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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pygi-array.h0000664000000000000000000000346415074674453015211 0ustar00rootroot/* -*- Mode: C; c-basic-offset: 4 -*- * vim: tabstop=4 shiftwidth=4 expandtab * * Copyright (C) 2014 Simon Feltman * * 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 . */ #ifndef __PYGI_ARRAY_H__ #define __PYGI_ARRAY_H__ #include #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__*/ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pygi-async.c0000664000000000000000000004226215074674453015202 0ustar00rootroot/* -*- Mode: C; c-basic-offset: 4 -*- * vim: tabstop=4 shiftwidth=4 expandtab * * Copyright (C) 2015 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 . */ #include #include #include #include "pygobject-object.h" #include "pygboxed.h" #include "pygi-async.h" #include "pygi-util.h" #include "pygi-info.h" #include "pygi-invoke.h" static PyObject *asyncio_InvalidStateError; static PyObject *asyncio_get_running_loop; #if defined(PYPY_VERSION) static PyObject *contextvars_copy_context; #endif static PyObject *cancellable_info; /* This is never instantiated. */ PYGI_DEFINE_TYPE ("gi._gi.Async", PyGIAsync_Type, PyGIAsync) /** * Async.__repr__() implementation. * Takes the _Async.__repr_format format string and applies the finish function * info to it. */ static PyObject* async_repr(PyGIAsync *self) { PyObject *string; char *func_descr; func_descr = _pygi_g_base_info_get_fullname (self->finish_func->base.info); string = PyUnicode_FromFormat ("%s(finish_func=%s, done=%s)", Py_TYPE(self)->tp_name, func_descr, (self->result || self->exception) ? "True" : "False"); g_free (func_descr); return string; } /** * async_cancel: * * Cancel the asynchronous operation. */ static PyObject * async_cancel(PyGIAsync *self) { return PyObject_CallMethod (self->cancellable, "cancel", NULL); } static PyObject * async_done(PyGIAsync *self) { return PyBool_FromLong (self->result || self->exception); } static PyObject * async_result(PyGIAsync *self) { if (!self->result && !self->exception) { PyErr_SetString(asyncio_InvalidStateError, "Async task is still running!"); return NULL; } self->log_tb = FALSE; if (self->result) { Py_INCREF (self->result); return self->result; } else { PyErr_SetObject(PyExceptionInstance_Class(self->exception), self->exception); return NULL; } } static PyObject * async_exception(PyGIAsync *self) { PyObject *res; if (!self->result && !self->exception) { PyErr_SetString(asyncio_InvalidStateError, "Async task is still running!"); return NULL; } if (self->exception) res =self->exception; else res = Py_None; self->log_tb = FALSE; Py_INCREF (res); return res; } static PyObject* call_soon (PyGIAsync *self, PyGIAsyncCallback *cb) { PyObject *call_soon; PyObject *args, *kwargs = NULL; PyObject *ret; call_soon = PyObject_GetAttrString(self->loop, "call_soon"); if (!call_soon) return NULL; args = Py_BuildValue ("(OO)", cb->func, self); kwargs = PyDict_New (); PyDict_SetItemString (kwargs, "context", cb->context); ret = PyObject_Call (call_soon, args, kwargs); Py_CLEAR (args); Py_CLEAR (kwargs); Py_CLEAR (call_soon); return ret; } static PyObject* async_add_done_callback (PyGIAsync *self, PyObject *args, PyObject *kwargs) { PyGIAsyncCallback callback = { NULL }; static char * kwlist[] = {"", "context", NULL}; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|$O:add_done_callback", kwlist, &callback.func, &callback.context)) return NULL; Py_INCREF(callback.func); if (callback.context == NULL) #ifndef PYPY_VERSION callback.context = PyContext_CopyCurrent (); #else callback.context = PyObject_CallObject (contextvars_copy_context, NULL); #endif else Py_INCREF(callback.context); /* Note that we don't need to copy the current context in this case. */ if (self->result || self->exception) { PyObject *res = call_soon (self, &callback); Py_DECREF(callback.func); Py_DECREF(callback.context); if (res) { Py_DECREF(res); Py_RETURN_NONE; } else { return NULL; } } if (!self->callbacks) self->callbacks = g_array_new (TRUE, TRUE, sizeof (PyGIAsyncCallback)); g_array_append_val (self->callbacks, callback); Py_RETURN_NONE; } static PyObject* async_remove_done_callback (PyGIAsync *self, PyObject *fn) { guint i = 0; gssize removed = 0; while (self->callbacks && i < self->callbacks->len) { PyGIAsyncCallback *cb = &g_array_index (self->callbacks, PyGIAsyncCallback, i); if (PyObject_RichCompareBool (cb->func, fn, Py_EQ) == 1) { Py_DECREF(cb->func); Py_DECREF(cb->context); removed += 1; g_array_remove_index (self->callbacks, i); } else { i += 1; } } return PyLong_FromSsize_t(removed); } static int async_init(PyGIAsync *self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "finish_func", "cancellable", NULL }; PyObject *context = NULL; GMainContext *ctx = NULL; int ret = -1; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!|O!$:gi._gi.Async.__init__", kwlist, &PyGICallableInfo_Type, &self->finish_func, &PyGObject_Type, &self->cancellable)) goto out; Py_INCREF(self->finish_func); /* We need to pull in Gio.Cancellable at some point, but we delay it * until really needed to avoid having a dependency. */ if (G_UNLIKELY (!cancellable_info)) { PyObject *gio; gio = PyImport_ImportModule("gi.repository.Gio"); if (gio == NULL) goto out; cancellable_info = PyObject_GetAttrString(gio, "Cancellable"); Py_DECREF(gio); if (!cancellable_info) goto out; } if (self->cancellable) { int res; Py_INCREF (self->cancellable); res = PyObject_IsInstance (self->cancellable, cancellable_info); if (res == -1) goto out; if (res == 0) { PyErr_SetString (PyExc_TypeError, "cancellable argument needs to be of type Gio.Cancellable"); goto out; } } else { self->cancellable = PyObject_CallObject (cancellable_info, NULL); } self->loop = PyObject_CallObject (asyncio_get_running_loop, NULL); if (!self->loop) goto out; /* We use g_main_context_ref_thread_default() here, as that is what GTask * does. We then only allow creating an awaitable if python has a *running* * EventLoop iterating this context (i.e. has it as its `_context` attr). * * NOTE: This is a bit backward. Instead, it would make more sense to just * fetch the current EventLoop object for the ref'ed GMainContext. * Python will then do the rest and ensure it is not awaited from the wrong * EventLoop. */ ctx = g_main_context_ref_thread_default (); assert(ctx != NULL); /* Duck-type the running loop. It needs to have a _context attribute. */ context = PyObject_GetAttrString (self->loop, "_context"); if (context == NULL) goto out; if (!pyg_boxed_check (context, G_TYPE_MAIN_CONTEXT) || pyg_boxed_get_ptr (context) != ctx) { PyErr_SetString (PyExc_TypeError, "Running EventLoop is iterating a different GMainContext"); goto out; } /* Success! */ ret = 0; out: g_main_context_unref (ctx); Py_XDECREF (context); return ret; } static PyMethodDef async_methods[] = { {"cancel", (PyCFunction)async_cancel, METH_NOARGS}, {"done", (PyCFunction)async_done, METH_NOARGS}, {"result", (PyCFunction)async_result, METH_NOARGS}, {"exception", (PyCFunction)async_exception, METH_NOARGS}, {"add_done_callback", (PyCFunction)async_add_done_callback, METH_VARARGS | METH_KEYWORDS}, {"remove_done_callback", (PyCFunction)async_remove_done_callback, METH_O}, {NULL, NULL, 0}, }; static PyObject * async_await (PyGIAsync *self) { /* We return ourselves as iterator. This is legal in principle, but we * don't stop iterating after one item and just continue indefinately, * meaning that certain errors cannot be caught! */ if (!self->result && !self->exception) self->_asyncio_future_blocking = TRUE; Py_INCREF (self); return (PyObject *) self; } static PyObject * async_iternext (PyGIAsync *self) { /* Return ourselves if iteration needs to continue. */ if (!self->result && !self->exception) { Py_INCREF (self); return (PyObject *) self; } if (self->exception) { PyErr_SetObject(PyExceptionInstance_Class(self->exception), self->exception); return NULL; } else { PyObject *e; e = PyObject_CallFunctionObjArgs(PyExc_StopIteration, self->result, NULL); if (e == NULL) return NULL; PyErr_SetObject(PyExc_StopIteration, e); Py_DECREF(e); return NULL; } } static PyAsyncMethods async_async_methods = { .am_await = (unaryfunc) async_await, }; static void async_finalize(PyGIAsync *self) { PyObject *error_type, *error_value, *error_traceback; PyObject *context = NULL; PyObject *message = NULL; PyObject *call_exception_handler = NULL; PyObject *res = NULL; if (!self->log_tb) return; assert(self->exception != NULL); self->log_tb = 0; /* Save the current exception, if any. */ PyErr_Fetch(&error_type, &error_value, &error_traceback); context = PyDict_New(); if (context == NULL) { goto finally; } message = PyUnicode_FromFormat( "%s exception was never retrieved", Py_TYPE(self)->tp_name); if (message == NULL) goto finally; if (PyDict_SetItemString(context, "message", message) < 0 || PyDict_SetItemString(context, "exception", self->exception) < 0 || PyDict_SetItemString(context, "future", (PyObject*) self) < 0) goto finally; call_exception_handler = PyObject_GetAttrString(self->loop, "call_exception_handler"); if (!call_exception_handler) goto finally; res = PyObject_CallFunction(call_exception_handler, "(O)", context); if (res == NULL) PyErr_WriteUnraisable(context); finally: Py_CLEAR (res); Py_CLEAR (context); Py_CLEAR (message); Py_CLEAR (call_exception_handler); Py_CLEAR(self->loop); Py_CLEAR(self->finish_func); if (self->cancellable) Py_CLEAR(self->cancellable); if (self->result) Py_CLEAR(self->result); if (self->exception) Py_CLEAR(self->exception); /* Precation, cannot happen */ if (self->callbacks) g_array_free (self->callbacks, TRUE); /* Restore the saved exception. */ PyErr_Restore(error_type, error_value, error_traceback); } static void async_dealloc(PyGIAsync *self) { #ifndef PYPY_VERSION /* The finalizer might resurrect the object */ if (PyObject_CallFinalizerFromDealloc((PyObject *)self) < 0) return; #endif Py_TYPE(self)->tp_free((PyObject *)self); } void pygi_async_finish_cb (GObject *source_object, gpointer res, PyGIAsync *self) { PyGILState_STATE py_state; PyObject *source_pyobj, *res_pyobj, *args; PyObject *ret; guint i; /* Lock the GIL as we are coming into this code without the lock and we may be executing python code */ py_state = PyGILState_Ensure (); /* We might still be called at shutdown time. */ if (!Py_IsInitialized()) { PyGILState_Release (py_state); return; } res_pyobj = pygobject_new_full (res, FALSE, NULL); if (source_object) { source_pyobj = pygobject_new_full (source_object, FALSE, NULL); args = Py_BuildValue ("(OO)", source_pyobj, res_pyobj); } else { source_pyobj = NULL; args = Py_BuildValue ("(O)", res_pyobj); } ret = _wrap_g_callable_info_invoke ((PyGIBaseInfo *) self->finish_func, args, NULL); Py_XDECREF (res_pyobj); Py_XDECREF (source_pyobj); Py_XDECREF (args); if (PyErr_Occurred ()) { PyObject *exc = NULL, *value = NULL, *traceback = NULL; /* NOTE: cPython >=3.12 has PyErr_{Get,Set}RaisedException */ PyErr_Fetch (&exc, &value, &traceback); PyErr_NormalizeException(&exc, &value, &traceback); self->exception = value; self->log_tb = TRUE; Py_XDECREF (exc); Py_XDECREF (traceback); Py_XDECREF (ret); } else { self->result = ret; } for (i = 0; self->callbacks && i < self->callbacks->len; i++) { PyGIAsyncCallback *cb = &g_array_index (self->callbacks, PyGIAsyncCallback, i); /* We stop calling anything after the first exception, but still clear * the internal state as if we did. * This matches the pure python implementation of Future. */ if (!PyErr_Occurred ()) { ret = call_soon (self, cb); if (!ret) PyErr_PrintEx (FALSE); else Py_DECREF(ret); } Py_DECREF(cb->func); Py_DECREF(cb->context); } if (self->callbacks) g_array_free(self->callbacks, TRUE); self->callbacks = NULL; Py_DECREF(self); PyGILState_Release (py_state); } /** * pygi_async_new: * @finish_func: A #GIFunctionInfo to wrap that is used to finish. * @cancellable: A #PyObject containging a #GCancellable, or None * * Return a new async instance. * * Returns: An instance of gi.Async or %NULL on error. */ PyObject * pygi_async_new(PyObject *finish_func, PyObject *cancellable) { PyObject *res; PyObject *args; res = PyGIAsync_Type.tp_alloc (&PyGIAsync_Type, 0); if (res) { if (cancellable && cancellable != Py_None) args = Py_BuildValue ("(OO)", finish_func, cancellable); else args = Py_BuildValue ("(O)", finish_func); if (PyGIAsync_Type.tp_init (res, args, NULL) < 0) { Py_DECREF (args); Py_DECREF (res); /* Ignore exception from object initializer */ PyErr_Clear (); return NULL; } Py_DECREF(args); } return res; } static struct PyMemberDef async_members[] = { { "_asyncio_future_blocking", T_BOOL, offsetof(PyGIAsync, _asyncio_future_blocking), 0, NULL }, { "_loop", T_OBJECT, offsetof(PyGIAsync, loop), READONLY, NULL }, { "_finish_func", T_OBJECT, offsetof(PyGIAsync, finish_func), READONLY, NULL }, { "cancellable", T_OBJECT, offsetof(PyGIAsync, cancellable), READONLY, "The Gio.Cancellable associated with the task." }, { NULL, } }; /** * pygi_async_register_types: * @module: A Python modules to which Async gets added to. * * Initializes the Async class and adds it to the passed @module. * * Returns: -1 on error, 0 on success. */ int pygi_async_register_types(PyObject *module) { PyObject *asyncio = NULL; #ifdef PYPY_VERSION PyObject *contextvars = NULL; #endif #ifndef PYPY_VERSION PyGIAsync_Type.tp_finalize = (destructor)async_finalize; #else PyGIAsync_Type.tp_del = (destructor)async_finalize; #endif PyGIAsync_Type.tp_dealloc = (destructor)async_dealloc; PyGIAsync_Type.tp_repr = (reprfunc)async_repr; PyGIAsync_Type.tp_flags = Py_TPFLAGS_DEFAULT | Py_TPFLAGS_HAVE_FINALIZE; PyGIAsync_Type.tp_methods = async_methods; PyGIAsync_Type.tp_members = async_members; PyGIAsync_Type.tp_as_async = &async_async_methods; PyGIAsync_Type.tp_iternext = (iternextfunc) &async_iternext; PyGIAsync_Type.tp_init = (initproc)async_init; PyGIAsync_Type.tp_new = PyType_GenericNew; if (PyType_Ready (&PyGIAsync_Type) < 0) return -1; Py_INCREF (&PyGIAsync_Type); if (PyModule_AddObject (module, "Async", (PyObject *)&PyGIAsync_Type) < 0) { Py_DECREF (&PyGIAsync_Type); return -1; } asyncio = PyImport_ImportModule("asyncio"); if (asyncio == NULL) { goto fail; } asyncio_InvalidStateError = PyObject_GetAttrString(asyncio, "InvalidStateError"); if (asyncio_InvalidStateError == NULL) goto fail; asyncio_get_running_loop = PyObject_GetAttrString(asyncio, "_get_running_loop"); if (asyncio_get_running_loop == NULL) goto fail; #if defined(PYPY_VERSION) contextvars = PyImport_ImportModule("contextvars"); if (asyncio == NULL) { goto fail; } contextvars_copy_context = PyObject_GetAttrString(contextvars, "copy_context"); if (contextvars_copy_context == NULL) goto fail; #endif /* Only initialized when really needed! */ cancellable_info = NULL; Py_CLEAR(asyncio); return 0; fail: Py_CLEAR(asyncio); return -1; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pygi-async.h0000664000000000000000000000310415074674453015177 0ustar00rootroot/* -*- Mode: C; c-basic-offset: 4 -*- * vim: tabstop=4 shiftwidth=4 expandtab * * Copyright (C) 2015 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 . */ #ifndef __PYGI_ASYNC_H__ #define __PYGI_ASYNC_H__ #include "Python.h" #include "pygi-info.h" #include "pygi-cache.h" typedef struct { PyObject *func; PyObject *context; } PyGIAsyncCallback; typedef struct { PyObject_HEAD /* Everything for the instance, finish_func is kept in the class. */ PyGICallableInfo *finish_func; PyObject *loop; PyObject *cancellable; char _asyncio_future_blocking; PyObject *result; PyObject *exception; gboolean log_tb; GArray *callbacks; } PyGIAsync; int pygi_async_register_types (PyObject *d); void pygi_async_finish_cb (GObject *source_object, gpointer res, PyGIAsync *async); PyObject* pygi_async_new (PyObject *async_finish, PyObject *cancellable); #endif /* __PYGI_ASYNCRESULT_H__ */ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pygi-basictype.c0000664000000000000000000010373015074674453016046 0ustar00rootroot/* -*- Mode: C; c-basic-offset: 4 -*- * vim: tabstop=4 shiftwidth=4 expandtab * * Copyright (C) 2011 John (J5) Palmieri * Copyright (C) 2014 Simon Feltman * * 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 . */ #include #include "pygi-type.h" #include "pygi-basictype.h" #include "pygi-argument.h" #include "pygi-util.h" #if defined(G_OS_WIN32) #include static gboolean pygi_isfinite (gdouble value) { return _finite (value); } #else #include 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; } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pygi-basictype.h0000664000000000000000000001107115074674453016047 0ustar00rootroot/* -*- Mode: C; c-basic-offset: 4 -*- * vim: tabstop=4 shiftwidth=4 expandtab * * Copyright (C) 2014 Simon Feltman * * 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 . */ #ifndef __PYGI_ARG_BASICTYPE_H__ #define __PYGI_ARG_BASICTYPE_H__ #include #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__*/ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pygi-boxed.c0000664000000000000000000001554615074674453015173 0ustar00rootroot/* -*- Mode: C; c-basic-offset: 4 -*- * vim: tabstop=4 shiftwidth=4 expandtab * * Copyright (C) 2009 Simon van der Linden * * pygi-boxed.c: wrapper to handle registered structures. * * 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 . */ #include "pygi-boxed.h" #include "pygi-info.h" #include "pygboxed.h" #include "pygi-type.h" #include "pygi-basictype.h" #include "pygi-util.h" #include struct _PyGIBoxed { PyGBoxed base; gboolean slice_allocated; gsize size; }; static void boxed_clear (PyGIBoxed *self) { gpointer boxed = pyg_boxed_get_ptr (self); GType g_type = ((PyGBoxed *)self)->gtype; if ( ( (PyGBoxed *) self)->free_on_dealloc && boxed != NULL) { if (self->slice_allocated) { 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_boxed_free (g_type, boxed); } } pyg_boxed_set_ptr (self, NULL); } 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) { gpointer boxed = NULL; gsize size = 0; switch (g_base_info_get_type (info)) { case GI_INFO_TYPE_UNION: size = g_union_info_get_size ( (GIUnionInfo *) info); break; case GI_INFO_TYPE_BOXED: case GI_INFO_TYPE_STRUCT: size = g_struct_info_get_size ( (GIStructInfo *) info); break; default: PyErr_Format (PyExc_TypeError, "info should be Boxed or Union, not '%d'", g_base_info_get_type (info)); 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; boxed = g_slice_alloc0 (size); if (boxed == NULL) PyErr_NoMemory(); return boxed; } static PyObject * boxed_new (PyTypeObject *type, PyObject *args, PyObject *kwargs) { GIBaseInfo *info; gsize size = 0; gpointer boxed; PyGIBoxed *self = NULL; info = _pygi_object_get_gi_info ( (PyObject *) type, &PyGIBaseInfo_Type); if (info == NULL) { if (PyErr_ExceptionMatches (PyExc_AttributeError)) { PyErr_Format (PyExc_TypeError, "missing introspection information"); } return NULL; } boxed = pygi_boxed_alloc (info, &size); if (boxed == NULL) { goto out; } self = (PyGIBoxed *) pygi_boxed_new (type, boxed, TRUE, size); if (self == NULL) { g_slice_free1 (size, boxed); goto out; } self->size = size; self->slice_allocated = TRUE; out: g_base_info_unref (info); return (PyObject *) self; } static int 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; } PYGI_DEFINE_TYPE("gi.Boxed", PyGIBoxed_Type, PyGIBoxed); PyObject * pygi_boxed_new (PyTypeObject *type, gpointer boxed, gboolean free_on_dealloc, gsize allocated_slice) { PyGIBoxed *self; if (!boxed) { Py_RETURN_NONE; } if (!PyType_IsSubtype (type, &PyGIBoxed_Type)) { PyErr_SetString (PyExc_TypeError, "must be a subtype of gi.Boxed"); return NULL; } self = (PyGIBoxed *) type->tp_alloc (type, 0); if (self == NULL) { return NULL; } ( (PyGBoxed *) self)->gtype = pyg_type_from_object ( (PyObject *) type); ( (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; } else { self->size = 0; self->slice_allocated = FALSE; } return (PyObject *) self; } /** * 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) { 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 PyMethodDef boxed_methods[] = { { "_clear_boxed", (PyCFunction)boxed_clear_wrapper, METH_NOARGS }, { NULL, NULL, 0 } }; /** * Returns 0 on success, or -1 and sets an exception. */ int pygi_boxed_register_types (PyObject *m) { 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_flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE); PyGIBoxed_Type.tp_methods = boxed_methods; 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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pygi-boxed.h0000664000000000000000000000266215074674453015173 0ustar00rootroot/* -*- Mode: C; c-basic-offset: 4 -*- * vim: tabstop=4 shiftwidth=4 expandtab * * Copyright (C) 2009 Simon van der Linden * * 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 . */ #ifndef __PYGI_BOXED_H__ #define __PYGI_BOXED_H__ #include #include #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); void * pygi_boxed_alloc (GIBaseInfo *info, gsize *size); void pygi_boxed_copy_in_place (PyGIBoxed *self); int pygi_boxed_register_types (PyObject *m); G_END_DECLS #endif /* __PYGI_BOXED_H__ */ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pygi-cache.c0000664000000000000000000012724115074674453015131 0ustar00rootroot/* -*- Mode: C; c-basic-offset: 4 -*- * vim: tabstop=4 shiftwidth=4 expandtab * * Copyright (C) 2011 John (J5) Palmieri * Copyright (C) 2013 Simon Feltman * * 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 . */ #include #include #include "pygi-type.h" #include "pygi-info.h" #include "pygi-cache.h" #include "pygi-marshal-cleanup.h" #include "pygi-type.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; } /* 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; if (cache->type_info != NULL) g_base_info_unref ( (GIBaseInfo *)cache->type_info); if (cache->destroy_notify) cache->destroy_notify (cache); else g_slice_free (PyGIArgCache, cache); } /* PyGIInterfaceCache */ static void _interface_cache_free_func (PyGIInterfaceCache *cache) { if (cache != NULL) { Py_XDECREF (cache->py_type); if (cache->type_name != NULL) g_free (cache->type_name); if (cache->interface_info != NULL) g_base_info_unref ( (GIBaseInfo *)cache->interface_info); g_slice_free (PyGIInterfaceCache, 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 (!pygi_arg_base_setup ((PyGIArgCache *)iface_cache, type_info, arg_info, transfer, direction)) { return FALSE; } ( (PyGIArgCache *)iface_cache)->destroy_notify = (GDestroyNotify)_interface_cache_free_func; 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); if (g_type_is_a (iface_cache->g_type, G_TYPE_OBJECT)) { if (g_str_equal (g_type_name (iface_cache->g_type), "GCancellable")) iface_cache->arg_cache.async_context = PYGI_ASYNC_CONTEXT_CANCELLABLE; } if (iface_cache->py_type == NULL) { return FALSE; } return TRUE; } 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) { PyGIInterfaceCache *ic; 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; } return (PyGIArgCache *)ic; } /* PyGISequenceCache */ static void _sequence_cache_free_func (PyGISequenceCache *cache) { if (cache != NULL) { pygi_arg_cache_free (cache->item_cache); g_slice_free (PyGISequenceCache, cache); } } /* 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) { GITypeInfo *item_type_info; GITransfer item_transfer; 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 = pygi_arg_cache_new (item_type_info, NULL, item_transfer, direction, callable_cache, 0, 0); g_base_info_unref ( (GIBaseInfo *)item_type_info); if (sc->item_cache == NULL) { return FALSE; } return TRUE; } PyGIArgCache * pygi_arg_cache_alloc (void) { return g_slice_new0 (PyGIArgCache); } static PyGIArgCache * _arg_cache_new_for_interface (GIInterfaceInfo *iface_info, GITypeInfo *type_info, GIArgInfo *arg_info, GITransfer transfer, PyGIDirection direction, PyGICallableCache *callable_cache) { GIInfoType info_type; info_type = g_base_info_get_type ( (GIBaseInfo *)iface_info); 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 (); } return NULL; } 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) { PyGIArgCache *arg_cache = NULL; GITypeTag type_tag; type_tag = g_type_info_get_tag (type_info); 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; 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; case GI_TYPE_TAG_GLIST: arg_cache = pygi_arg_glist_new_from_info (type_info, arg_info, transfer, direction, callable_cache); break; case GI_TYPE_TAG_GSLIST: arg_cache = pygi_arg_gslist_new_from_info (type_info, arg_info, transfer, direction, callable_cache); break; case GI_TYPE_TAG_GHASH: arg_cache = pygi_arg_hash_table_new_from_info (type_info, arg_info, transfer, direction, callable_cache); 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, type_info, arg_info, transfer, direction, callable_cache); g_base_info_unref ( (GIBaseInfo *)interface_info); } break; case GI_TYPE_TAG_ERROR: arg_cache = pygi_arg_gerror_new_from_info (type_info, arg_info, transfer, direction); break; default: break; } if (arg_cache != NULL) { arg_cache->py_arg_index = py_arg_index; arg_cache->c_arg_index = c_arg_index; } return arg_cache; } /* PyGICallableCache */ static PyGIDirection _pygi_get_direction (PyGICallableCache *callable_cache, GIDirection gi_direction) { /* 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; } } /* Generate the cache for the callable's arguments */ static gboolean _callable_cache_generate_args_cache_real (PyGICallableCache *callable_cache, GICallableInfo *callable_info) { 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; /* Return arguments are always considered out */ return_direction = _pygi_get_direction (callable_cache, GI_DIRECTION_OUT); /* 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; return_cache->is_skipped = g_callable_info_skip_return (callable_info); callable_cache->return_cache = return_cache; g_base_info_unref (return_info); callable_cache->user_data_index = -1; 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; arg_info = g_callable_info_get_arg (callable_info, i); /* This only happens when dealing with callbacks */ if (g_arg_info_get_closure (arg_info) == i) { callable_cache->user_data_index = i; arg_cache = pygi_arg_cache_alloc (); _pygi_callable_cache_set_arg (callable_cache, arg_index, arg_cache); 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; } 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++; } if (direction & PYGI_DIRECTION_TO_PYTHON) { callable_cache->n_to_py_args++; } arg_cache->type_tag = g_type_info_get_tag (type_info); } else { GITransfer transfer; gssize py_arg_index = -1; transfer = g_arg_info_get_ownership_transfer (arg_info); if (direction & PYGI_DIRECTION_FROM_PYTHON) { py_arg_index = callable_cache->n_py_args; callable_cache->n_py_args++; } 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; } if (direction & PYGI_DIRECTION_TO_PYTHON) { callable_cache->n_to_py_args++; callable_cache->to_py_args = g_slist_append (callable_cache->to_py_args, arg_cache); } _pygi_callable_cache_set_arg (callable_cache, arg_index, arg_cache); } g_base_info_unref (type_info); } /* Ensure arguments always have a name when available */ arg_cache->arg_name = g_base_info_get_name ((GIBaseInfo *) arg_info); g_base_info_unref ( (GIBaseInfo *)arg_info); } 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; last_explicit_arg_index = -1; /* 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); 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) { /* 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)); } /* 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; } if (last_explicit_arg_index == -1) { last_explicit_arg_index = i; /* 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 (!return_cache->is_skipped && return_cache->type_tag != GI_TYPE_TAG_VOID) { callable_cache->has_return = TRUE; } tuple_names = PyList_New (0); if (callable_cache->has_return) { PyList_Append (tuple_names, Py_None); } 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; } /* 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 TRUE; } static void _callable_cache_deinit_real (PyGICallableCache *cache) { 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); g_clear_pointer (&cache->return_cache, pygi_arg_cache_free); } 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); 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); } n_args = (gint)cache->args_offset + g_callable_info_get_n_args (callable_info); 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); } if (!cache->generate_args_cache (cache, callable_info)) { _callable_cache_deinit_real (cache); return FALSE; } return TRUE; } 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); } } void pygi_callable_cache_free (PyGICallableCache *cache) { cache->deinit (cache); g_free (cache); } /* PyGIFunctionCache */ 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); } static void _function_cache_deinit_real (PyGICallableCache *callable_cache) { PyGIFunctionCache *function_cache = (PyGIFunctionCache *) callable_cache; g_function_invoker_destroy (&((PyGIFunctionCache *) callable_cache)->invoker); Py_CLEAR (function_cache->async_finish); _callable_cache_deinit_real (callable_cache); } 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; guint i; callable_cache->calling_context = PYGI_CALLING_CONTEXT_IS_FROM_PY; if (callable_cache->deinit == NULL) callable_cache->deinit = _function_cache_deinit_real; if (function_cache->invoke == NULL) function_cache->invoke = _function_cache_invoke_real; if (!_callable_cache_init (callable_cache, callable_info)) return FALSE; /* Check if this function is an async routine that is capable of returning * an async awaitable object. */ if (!callable_cache->has_return && callable_cache->n_to_py_args == 0) { PyGIArgCache *cancellable = NULL; PyGIArgCache *async_callback = NULL; for (i = 0; i < _pygi_callable_cache_args_len (callable_cache); i++) { PyGIArgCache *arg_cache = _pygi_callable_cache_get_arg (callable_cache, i); /* Ignore any out or in/out parameters. */ if (arg_cache->async_context == PYGI_ASYNC_CONTEXT_CALLBACK) { if (async_callback) { async_callback = NULL; break; } async_callback = arg_cache; } else if (arg_cache->async_context == PYGI_ASYNC_CONTEXT_CANCELLABLE) { if (cancellable) { cancellable = NULL; break; } cancellable = arg_cache; } } if (cancellable && async_callback) { GIBaseInfo *container = g_base_info_get_container ((GIBaseInfo*) callable_info); GIBaseInfo *async_finish = NULL; gint name_len; gchar *finish_name = NULL; /* This appears to be an async routine. As we have the * GCallableInfo at this point, so guess the finish name and look * up that information. */ name_len = strlen (callable_cache->name); if (g_str_has_suffix (callable_cache->name, "_async")) name_len -= 6; /* Original name without _async if it is there, _finish + NUL byte */ finish_name = g_malloc0 (name_len + 7 + 1); strncat (finish_name, callable_cache->name, name_len); strcat (finish_name, "_finish"); if (container && g_base_info_get_type (container) == GI_INFO_TYPE_OBJECT) { async_finish = g_object_info_find_method ((GIObjectInfo *) container, finish_name); } else if (container && g_base_info_get_type (container) == GI_INFO_TYPE_INTERFACE) { async_finish = g_interface_info_find_method ((GIInterfaceInfo *) container, finish_name); } else if (!container) { async_finish = g_irepository_find_by_name (NULL, callable_cache->namespace, finish_name); } else { g_debug ("Awaitable async functions only work on GObjects and as toplevel functions."); } if (async_finish && g_base_info_get_type (async_finish)) { function_cache->async_finish = _pygi_info_new ((GIBaseInfo *) async_finish); function_cache->async_cancellable = cancellable; function_cache->async_callback = async_callback; } if (async_finish) g_base_info_unref (async_finish); g_free (finish_name); } } /* 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; } } if (!pygi_error_check (&error)) { PyErr_Format (PyExc_RuntimeError, "unknown error creating invoker for %s", g_base_info_get_name ((GIBaseInfo *) callable_info)); } _callable_cache_deinit_real (callable_cache); return FALSE; } PyGIFunctionCache * pygi_function_cache_new (GICallableInfo *info) { PyGIFunctionCache *function_cache; function_cache = g_new0 (PyGIFunctionCache, 1); if (!_function_cache_init (function_cache, info)) { g_free (function_cache); return NULL; } return function_cache; } PyObject * pygi_function_cache_invoke (PyGIFunctionCache *function_cache, PyObject *py_args, PyObject *py_kwargs) { PyGIInvokeState state = { 0, }; return function_cache->invoke (function_cache, &state, py_args, py_kwargs); } /* PyGICCallbackCache */ PyGIFunctionCache * pygi_ccallback_cache_new (GICallableInfo *info, GCallback function_ptr) { PyGICCallbackCache *ccallback_cache; PyGIFunctionCache *function_cache; ccallback_cache = g_new0 (PyGICCallbackCache, 1); function_cache = (PyGIFunctionCache *) ccallback_cache; function_cache->invoker.native_address = function_ptr; if (!_function_cache_init (function_cache, info)) { g_free (ccallback_cache); return NULL; } return function_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); } /* PyGIConstructorCache */ static PyObject * _constructor_cache_invoke_real (PyGIFunctionCache *function_cache, PyGIInvokeState *state, PyObject *py_args, PyObject *py_kwargs) { 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); return FALSE; } 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 (ret == NULL || cache->return_cache->is_skipped) return ret; if (ret != Py_None) { if (!PyTuple_Check (ret)) return ret; if (PyTuple_GET_ITEM (ret, 0) != Py_None) return ret; } PyErr_SetString (PyExc_TypeError, "constructor returned NULL"); Py_DECREF (ret); return NULL; } PyGIFunctionCache * pygi_constructor_cache_new (GICallableInfo *info) { PyGIConstructorCache *constructor_cache; PyGIFunctionCache *function_cache; constructor_cache = g_new0 (PyGIConstructorCache, 1); function_cache = (PyGIFunctionCache *) constructor_cache; function_cache->invoke = _constructor_cache_invoke_real; if (!_function_cache_init (function_cache, info)) { g_free (constructor_cache); return NULL; } return function_cache; } /* PyGIFunctionWithInstanceCache */ static gboolean _function_with_instance_cache_generate_args_cache_real (PyGICallableCache *callable_cache, GICallableInfo *callable_info) { GIInterfaceInfo *interface_info; PyGIArgCache *instance_cache; GITransfer transfer; interface_info = g_base_info_get_container ((GIBaseInfo *) callable_info); transfer = g_callable_info_get_instance_ownership_transfer (callable_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; /* 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; _pygi_callable_cache_set_arg (callable_cache, 0, instance_cache); callable_cache->n_py_args++; return _callable_cache_generate_args_cache_real (callable_cache, callable_info); } static gboolean _function_with_instance_cache_init (PyGIFunctionWithInstanceCache *fwi_cache, GICallableInfo *info) { PyGICallableCache *callable_cache = (PyGICallableCache *) fwi_cache; callable_cache->args_offset += 1; callable_cache->generate_args_cache = _function_with_instance_cache_generate_args_cache_real; return _function_cache_init ((PyGIFunctionCache *) fwi_cache, info); } /* PyGIMethodCache */ PyGIFunctionCache * pygi_method_cache_new (GICallableInfo *info) { PyGIMethodCache *method_cache; PyGIFunctionWithInstanceCache *fwi_cache; method_cache = g_new0 (PyGIMethodCache, 1); fwi_cache = (PyGIFunctionWithInstanceCache *) method_cache; if (!_function_with_instance_cache_init (fwi_cache, info)) { g_free (method_cache); return NULL; } return (PyGIFunctionCache *) method_cache; } /* PyGIVFuncCache */ 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; } implementor_gtype = pyg_type_from_object (py_gtype); if (implementor_gtype == G_TYPE_INVALID) return FALSE; /* vfunc addresses are pulled into the state at call time and cannot be * cached because the call site can specify a different portion of the * class hierarchy. e.g. Object.do_func vs. SubObject.do_func might * retrieve a different vfunc address but GI gives us the same vfunc info. */ state->function_ptr = g_vfunc_info_get_address ((GIVFuncInfo *) vfunc_cache->info, implementor_gtype, &error); if (pygi_error_check (&error)) { return FALSE; } 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); return ret; } static void _vfunc_cache_deinit_real (PyGICallableCache *callable_cache) { g_base_info_unref (((PyGIVFuncCache *) callable_cache)->info); _function_cache_deinit_real (callable_cache); } PyGIFunctionCache * pygi_vfunc_cache_new (GICallableInfo *info) { PyGIVFuncCache *vfunc_cache; PyGIFunctionCache *function_cache; PyGIFunctionWithInstanceCache *fwi_cache; vfunc_cache = g_new0 (PyGIVFuncCache, 1); function_cache = (PyGIFunctionCache *) vfunc_cache; fwi_cache = (PyGIFunctionWithInstanceCache *) vfunc_cache; ((PyGICallableCache *) vfunc_cache)->deinit = _vfunc_cache_deinit_real; /* 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; function_cache->invoke = _vfunc_cache_invoke_real; if (!_function_with_instance_cache_init (fwi_cache, info)) { g_free (vfunc_cache); return NULL; } /* Required by _vfunc_cache_invoke_real() */ vfunc_cache->info = g_base_info_ref ((GIBaseInfo *) info); return function_cache; } /* PyGIClosureCache */ PyGIClosureCache * pygi_closure_cache_new (GICallableInfo *info) { gssize i; PyGIClosureCache *closure_cache; PyGICallableCache *callable_cache; closure_cache = g_new0 (PyGIClosureCache, 1); callable_cache = (PyGICallableCache *) closure_cache; callable_cache->calling_context = PYGI_CALLING_CONTEXT_IS_FROM_C; if (!_callable_cache_init (callable_cache, info)) { g_free (closure_cache); return NULL; } /* 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; garray_cache = (PyGIArgGArray *) arg_cache; if (garray_cache->len_arg_index == -1) continue; 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; } /* 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; arg_cache = g_ptr_array_index (callable_cache->args_cache, i); if (arg_cache->direction == PYGI_DIRECTION_TO_PYTHON && arg_cache->type_tag == GI_TYPE_TAG_VOID && arg_cache->is_pointer) { callable_cache->user_data_index = i; break; } } } return closure_cache; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pygi-cache.h0000664000000000000000000002645315074674453015141 0ustar00rootroot/* -*- Mode: C; c-basic-offset: 4 -*- * vim: tabstop=4 shiftwidth=4 expandtab * * Copyright (C) 2011 John (J5) Palmieri * Copyright (C) 2013 Simon Feltman * * 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 . */ #ifndef __PYGI_CACHE_H__ #define __PYGI_CACHE_H__ #include #include #include #include "pygi-invoke-state-struct.h" G_BEGIN_DECLS 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, gpointer *cleanup_data); typedef PyObject *(*PyGIMarshalToPyFunc) (PyGIInvokeState *state, PyGICallableCache *callable_cache, PyGIArgCache *arg_cache, 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 * actual GI type. If they have children the marshaller will * also handle marshalling the children. * - PYGI_META_ARG_TYPE_CHILD - Children without python argument are * ignored by the marshallers and handled directly by their parents * marshaller. * - 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 */ typedef enum { PYGI_META_ARG_TYPE_PARENT, PYGI_META_ARG_TYPE_CHILD, PYGI_META_ARG_TYPE_CHILD_WITH_PYARG, PYGI_META_ARG_TYPE_CLOSURE, } PyGIMetaArgType; /* * Argument direction types denotes how we marshal, * e.g. to Python or from Python or both. */ typedef enum { 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. */ typedef enum { PYGI_CALLING_CONTEXT_IS_FROM_C, PYGI_CALLING_CONTEXT_IS_FROM_PY } PyGICallingContext; typedef enum { PYGI_ASYNC_CONTEXT_NONE = 0, PYGI_ASYNC_CONTEXT_CALLBACK, PYGI_ASYNC_CONTEXT_CANCELLABLE, } PyGIAsyncContext; struct _PyGIArgCache { const gchar *arg_name; PyGIMetaArgType meta_type; PyGIAsyncContext async_context; gboolean is_pointer; gboolean is_caller_allocates; gboolean is_skipped; gboolean allow_none; gboolean has_default; PyGIDirection direction; GITransfer transfer; GITypeTag type_tag; GITypeInfo *type_info; PyGIMarshalFromPyFunc from_py_marshaller; PyGIMarshalToPyFunc to_py_marshaller; PyGIMarshalCleanupFunc from_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; } PyGIArgGArray; typedef struct _PyGIInterfaceCache { PyGIArgCache arg_cache; gboolean is_foreign; GType g_type; PyObject *py_type; GIInterfaceInfo *interface_info; gchar *type_name; } PyGIInterfaceCache; struct _PyGICallableCache { const gchar *name; const gchar *container_name; const gchar *namespace; PyGICallingContext calling_context; PyGIArgCache *return_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; /* 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; /* 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; /* Information about async functions. */ PyObject *async_finish; PyGIArgCache *async_callback; PyGIArgCache *async_cancellable; /* 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; }; 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 #endif /* __PYGI_CACHE_H__ */ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pygi-ccallback.c0000664000000000000000000000635115074674453015763 0ustar00rootroot/* -*- Mode: C; c-basic-offset: 4 -*- * vim: tabstop=4 shiftwidth=4 expandtab * * Copyright (C) 2011 John (J5) Palmieri , Red Hat, Inc. * * pygi-boxed-closure.c: wrapper to handle GClosure box types with C callbacks. * * 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 . */ #include "pygi-util.h" #include "pygi-ccallback.h" #include static PyObject * _ccallback_call(PyGICCallback *self, PyObject *args, PyObject *kwargs) { PyObject *result; if (self->cache == NULL) { self->cache = (PyGICCallbackCache *)pygi_ccallback_cache_new (self->info, self->callback); if (self->cache == NULL) return NULL; } result = pygi_ccallback_cache_invoke (self->cache, args, kwargs, self->user_data); return result; } PYGI_DEFINE_TYPE("gi.CCallback", PyGICCallback_Type, PyGICCallback); PyObject * _pygi_ccallback_new (GCallback callback, gpointer user_data, GIScopeType scope, GIFunctionInfo *info, GDestroyNotify destroy_notify) { PyGICCallback *self; if (!callback) { Py_RETURN_NONE; } self = (PyGICCallback *) PyGICCallback_Type.tp_alloc (&PyGICCallback_Type, 0); if (self == NULL) { return NULL; } self->callback = (GCallback) callback; self->user_data = user_data; self->scope = scope; self->destroy_notify_func = destroy_notify; self->info = g_base_info_ref( (GIBaseInfo *) info); return (PyObject *) self; } 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); } /** * Returns 0 on success, or -1 and sets an exception. */ int pygi_ccallback_register_types (PyObject *m) { 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) < 0) return -1; Py_INCREF ((PyObject *) &PyGICCallback_Type); if (PyModule_AddObject (m, "CCallback", (PyObject *) &PyGICCallback_Type) < 0) { Py_DECREF ((PyObject *) &PyGICCallback_Type); return -1; } return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pygi-ccallback.h0000664000000000000000000000310015074674453015755 0ustar00rootroot/* -*- Mode: C; c-basic-offset: 4 -*- * vim: tabstop=4 shiftwidth=4 expandtab * * Copyright (C) 2011 John (J5) Palmieri , 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, see . */ #ifndef __PYGI_CCLOSURE_H__ #define __PYGI_CCLOSURE_H__ #include #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, gpointer user_data, GIScopeType scope, GIFunctionInfo *info, GDestroyNotify destroy_notify); int pygi_ccallback_register_types (PyObject *m); G_END_DECLS #endif /* __PYGI_CCLOSURE_H__ */ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pygi-closure.c0000664000000000000000000010641515074674453015542 0ustar00rootroot/* -*- Mode: C; c-basic-offset: 4 -*- * vim: tabstop=4 shiftwidth=4 expandtab * * pygi-closure.c: PyGI C Closure functions * * 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 . */ #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" #include "pygi-async.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 library function call. */ static GSList* async_free_list; static void _pygi_closure_assign_pyobj_to_retval (gpointer retval, GIArgument *arg, PyGIArgCache *arg_cache) { if (retval == NULL) return; switch (arg_cache->type_tag) { case GI_TYPE_TAG_BOOLEAN: *((ffi_sarg *) retval) = arg->v_boolean; break; case GI_TYPE_TAG_INT8: *((ffi_sarg *) retval) = arg->v_int8; break; case GI_TYPE_TAG_UINT8: *((ffi_arg *) retval) = arg->v_uint8; break; case GI_TYPE_TAG_INT16: *((ffi_sarg *) retval) = arg->v_int16; break; case GI_TYPE_TAG_UINT16: *((ffi_arg *) retval) = arg->v_uint16; break; case GI_TYPE_TAG_INT32: *((ffi_sarg *) retval) = arg->v_int32; break; case GI_TYPE_TAG_UINT32: *((ffi_arg *) retval) = arg->v_uint32; break; case GI_TYPE_TAG_INT64: *((ffi_sarg *) retval) = arg->v_int64; break; case GI_TYPE_TAG_UINT64: *((ffi_arg *) retval) = arg->v_uint64; break; case GI_TYPE_TAG_FLOAT: *((gfloat *) retval) = arg->v_float; break; case GI_TYPE_TAG_DOUBLE: *((gdouble *) retval) = arg->v_double; break; case GI_TYPE_TAG_GTYPE: *((ffi_arg *) retval) = arg->v_size; break; case GI_TYPE_TAG_UNICHAR: *((ffi_arg *) retval) = arg->v_uint32; break; case GI_TYPE_TAG_INTERFACE: { GIBaseInfo *interface_info; interface_info = ((PyGIInterfaceCache *) arg_cache)->interface_info; switch (g_base_info_get_type (interface_info)) { case GI_INFO_TYPE_ENUM: *(ffi_sarg *) retval = arg->v_int; break; case GI_INFO_TYPE_FLAGS: *(ffi_arg *) retval = arg->v_uint; break; default: *(ffi_arg *) retval = (ffi_arg) arg->v_pointer; break; } break; } default: *(ffi_arg *) retval = (ffi_arg) arg->v_pointer; break; } } static void _pygi_closure_assign_pyobj_to_out_argument (gpointer out_arg, GIArgument *arg, PyGIArgCache *arg_cache) { if (out_arg == NULL) return; switch (arg_cache->type_tag) { case GI_TYPE_TAG_BOOLEAN: *((gboolean *) out_arg) = arg->v_boolean; break; case GI_TYPE_TAG_INT8: *((gint8 *) out_arg) = arg->v_int8; break; case GI_TYPE_TAG_UINT8: *((guint8 *) out_arg) = arg->v_uint8; break; case GI_TYPE_TAG_INT16: *((gint16 *) out_arg) = arg->v_int16; break; case GI_TYPE_TAG_UINT16: *((guint16 *) out_arg) = arg->v_uint16; break; case GI_TYPE_TAG_INT32: *((gint32 *) out_arg) = arg->v_int32; break; case GI_TYPE_TAG_UINT32: *((guint32 *) out_arg) = arg->v_uint32; break; case GI_TYPE_TAG_INT64: *((gint64 *) out_arg) = arg->v_int64; break; case GI_TYPE_TAG_UINT64: *((guint64 *) out_arg) = arg->v_uint64; break; case GI_TYPE_TAG_FLOAT: *((gfloat *) out_arg) = arg->v_float; break; case GI_TYPE_TAG_DOUBLE: *((gdouble *) out_arg) = arg->v_double; break; case GI_TYPE_TAG_GTYPE: *((GType *) out_arg) = arg->v_size; break; case GI_TYPE_TAG_UNICHAR: *((guint32 *) out_arg) = arg->v_uint32; break; case GI_TYPE_TAG_INTERFACE: { GIBaseInfo *interface_info; interface_info = ((PyGIInterfaceCache *) arg_cache)->interface_info; switch (g_base_info_get_type (interface_info)) { case GI_INFO_TYPE_ENUM: *(gint *) out_arg = arg->v_int; break; case GI_INFO_TYPE_FLAGS: *(guint *) out_arg = arg->v_uint; break; case GI_INFO_TYPE_STRUCT: 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; } *((gpointer *) out_arg) = arg->v_pointer; break; default: *((gpointer *) out_arg) = arg->v_pointer; break; } break; } default: *((gpointer *) out_arg) = arg->v_pointer; break; } } static void _pygi_closure_convert_ffi_arguments (PyGIInvokeArgState *state, PyGICallableCache *cache, void **args) { 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 { 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); 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; } 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; } } 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 _invoke_state_init_from_cache (PyGIInvokeState *state, PyGIClosureCache *closure_cache, void **args) { 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; for (i = 0; (gsize)i < _pygi_callable_cache_args_len (cache); i++) { PyGIArgCache *arg_cache; arg_cache = g_ptr_array_index (cache->args_cache, i); if (arg_cache->direction & PYGI_DIRECTION_TO_PYTHON) { PyObject *value; 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 { /* 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 (arg_cache->meta_type != PYGI_META_ARG_TYPE_PARENT) { continue; } else { 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 (state->py_in_args, n_in_args, value); n_in_args++; } } if (_PyTuple_Resize (&state->py_in_args, n_in_args) == -1) return FALSE; return TRUE; } static gboolean _pygi_closure_set_out_arguments (PyGIInvokeState *state, PyGICallableCache *cache, PyObject *py_retval, void *resp) { 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)) { 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++; } 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)) { 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 _pygi_invoke_closure_clear_py_data(PyGICClosure *invoke_closure) { PyGILState_STATE state = PyGILState_Ensure(); Py_CLEAR (invoke_closure->function); Py_CLEAR (invoke_closure->user_data); PyGILState_Release (state); } void _pygi_closure_handle (ffi_cif *cif, void *result, void **args, void *data) { PyGILState_STATE py_state; PyGICClosure *closure = data; PyObject *retval; 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 */ py_state = PyGILState_Ensure (); if (closure->cache == NULL) goto end; state.user_data = closure->user_data; _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, state.py_in_args); if (retval == NULL) { _pygi_closure_clear_retvals (&state, closure->cache, result); goto end; } 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: 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. Scope notified will be freed when the notify is called. Scope async closures free only their python data now and the closure later during the next creation of a closure. This minimizes potential ref leaks at least in regards to the python objects. (you can't free the closure you are currently using!) */ switch (closure->scope) { case GI_SCOPE_TYPE_CALL: case GI_SCOPE_TYPE_NOTIFIED: break; case GI_SCOPE_TYPE_ASYNC: /* Append this PyGICClosure to a list of closure that we will free after we're done with this function invokation */ _pygi_invoke_closure_clear_py_data(closure); async_free_list = g_slist_prepend (async_free_list, closure); break; default: /* 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)); } _invoke_state_clear (&state); PyGILState_Release (py_state); } void _pygi_invoke_closure_free (PyGICClosure* invoke_closure) { #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); } PyGICClosure* _pygi_make_native_closure (GICallableInfo* info, PyGIClosureCache *cache, GIScopeType scope, PyObject *py_function, PyObject *py_user_data) { PyGICClosure *closure; ffi_closure *fficlosure; /* Begin by cleaning up old async functions */ g_slist_free_full (async_free_list, (GDestroyNotify) _pygi_invoke_closure_free); async_free_list = NULL; /* Build the closure itself */ closure = g_slice_new0 (PyGICClosure); closure->info = (GICallableInfo *) g_base_info_ref ( (GIBaseInfo *) info); closure->function = py_function; closure->user_data = py_user_data; closure->cache = cache; Py_INCREF (py_function); 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 to free itself later */ closure->scope = scope; 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 (py_arg == _PyGIDefaultArgPlaceholder) { /* We need to have an async to "marshal" instead in this case. */ if (!state->py_async) return FALSE; if (callback_cache->user_data_index <= 0) return FALSE; user_data_cache = _pygi_callable_cache_get_arg (callable_cache, (guint)callback_cache->user_data_index); Py_INCREF (state->py_async); arg->v_pointer = pygi_async_finish_cb; state->args[user_data_cache->c_arg_index].arg_value.v_pointer = state->py_async; return TRUE; } 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 (arg_cache->scope == GI_SCOPE_TYPE_ASYNC) arg_cache->arg_cache.async_context = PYGI_ASYNC_CONTEXT_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; } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pygi-closure.h0000664000000000000000000000420015074674453015534 0ustar00rootroot/* -*- 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 . */ #ifndef __PYGI_CLOSURE_H__ #define __PYGI_CLOSURE_H__ #include #include #include #include "pygi-cache.h" G_BEGIN_DECLS /* Private */ typedef struct _PyGICClosure { GICallableInfo *info; PyObject *function; ffi_closure *closure; ffi_cif cif; 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 (PyGICClosure* invoke_closure); PyGICClosure* _pygi_make_native_closure (GICallableInfo* info, PyGIClosureCache *cache, GIScopeType scope, PyObject *function, 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 #endif /* __PYGI_CLOSURE_H__ */ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pygi-enum-marshal.c0000664000000000000000000003264015074674453016455 0ustar00rootroot/* -*- Mode: C; c-basic-offset: 4 -*- * vim: tabstop=4 shiftwidth=4 expandtab * * Copyright (C) 2011 John (J5) Palmieri * Copyright (C) 2014 Simon Feltman * * 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 . */ #include #include #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; } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pygi-enum-marshal.h0000664000000000000000000000334615074674453016463 0ustar00rootroot/* -*- Mode: C; c-basic-offset: 4 -*- * vim: tabstop=4 shiftwidth=4 expandtab * * Copyright (C) 2014 Simon Feltman * * 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 . */ #ifndef __PYGI_ENUM_MARSHAL_H__ #define __PYGI_ENUM_MARSHAL_H__ #include #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__*/ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pygi-error.c0000664000000000000000000002475015074674453015220 0ustar00rootroot/* -*- 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 * Copyright (C) 2014 Simon Feltman * * 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 . */ #include #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 (py_arg == Py_None) { arg->v_pointer = NULL; *cleanup_data = NULL; return TRUE; } else 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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pygi-error.h0000664000000000000000000000335515074674453015223 0ustar00rootroot/* -*- 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 * * 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 . */ #ifndef __PYGI_ERROR_H__ #define __PYGI_ERROR_H__ #include #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__*/ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pygi-foreign-api.h0000664000000000000000000000602315074674453016265 0ustar00rootroot/* -*- Mode: C; c-basic-offset: 4 -*- * vim: tabstop=4 shiftwidth=4 expandtab * * Copyright (C) 2005-2009 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 . */ #ifndef __PYGI_FOREIGN_API_H__ #define __PYGI_FOREIGN_API_H__ #include #include 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__ */ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pygi-foreign-cairo.c0000664000000000000000000004652715074674453016621 0ustar00rootroot/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */ /* * Copyright (c) 2010 Collabora Ltd. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. */ #include #include #include #include /* 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 static int _gi_cairo_exec (PyObject *module); /* * cairo_t marshaling */ static PyObject * cairo_context_to_arg (PyObject *value, GIInterfaceInfo *interface_info, GITransfer transfer, GIArgument *arg) { cairo_t *cr; 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, GITransfer transfer, gpointer data) { cairo_t *context = (cairo_t*) data; 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_) { cairo_destroy ( (cairo_t*) struct_); 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, GIInterfaceInfo *interface_info, GITransfer transfer, GIArgument *arg) { cairo_surface_t *surface; if (!PyObject_TypeCheck (value, &PycairoSurface_Type)) { PyErr_SetString (PyExc_TypeError, "Expected cairo.Surface"); return NULL; } surface = ( (PycairoSurface*) value)->surface; if (!surface) { PyErr_SetString (PyExc_ValueError, "Surface instance wrapping a NULL surface"); 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, GITransfer transfer, gpointer data) { cairo_surface_t *surface = (cairo_surface_t*) data; if (transfer == GI_TRANSFER_NOTHING) cairo_surface_reference (surface); return PycairoSurface_FromSurface (surface, NULL); } static PyObject * cairo_surface_release (GIBaseInfo *base_info, gpointer struct_) { cairo_surface_destroy ( (cairo_surface_t*) struct_); 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, GIInterfaceInfo *interface_info, GITransfer transfer, GIArgument *arg) { cairo_path_t *path; if (!PyObject_TypeCheck (value, &PycairoPath_Type)) { PyErr_SetString (PyExc_TypeError, "Expected cairo.Path"); return NULL; } path = ( (PycairoPath*) value)->path; if (!path) { PyErr_SetString (PyExc_ValueError, "Path instance wrapping a NULL path"); 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, 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); } static PyObject * cairo_path_release (GIBaseInfo *base_info, gpointer struct_) { cairo_path_destroy ( (cairo_path_t*) struct_); 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, GITransfer transfer, GIArgument *arg) { cairo_font_options_t *font_options; if (!PyObject_TypeCheck (value, &PycairoFontOptions_Type)) { PyErr_SetString (PyExc_TypeError, "Expected cairo.FontOptions"); return NULL; } font_options = ( (PycairoFontOptions*) value)->font_options; if (!font_options) { PyErr_SetString (PyExc_ValueError, "FontOptions instance wrapping a NULL font_options"); 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, GITransfer transfer, gpointer data) { cairo_font_options_t *font_options = (cairo_font_options_t*) data; if (transfer == GI_TRANSFER_NOTHING) font_options = cairo_font_options_copy (font_options); return PycairoFontOptions_FromFontOptions (font_options); } static PyObject * cairo_font_options_release (GIBaseInfo *base_info, gpointer struct_) { cairo_font_options_destroy ( (cairo_font_options_t*) struct_); Py_RETURN_NONE; } /* * 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) { /* 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 #define PYGI_MODINIT_FUNC PyMODINIT_FUNC #endif static PyMethodDef _gi_cairo_functions[] = { {0,} }; static PyModuleDef_Slot _gi_cairo_slots[] = { {Py_mod_exec, _gi_cairo_exec}, {0, NULL} }; static struct PyModuleDef __gi_cairomodule = { PyModuleDef_HEAD_INIT, "_gi_cairo", NULL, 0, _gi_cairo_functions, _gi_cairo_slots, NULL, NULL, NULL }; PYGI_MODINIT_FUNC PyInit__gi_cairo (void); PYGI_MODINIT_FUNC PyInit__gi_cairo (void) { return PyModuleDef_Init(&__gi_cairomodule); } static int _gi_cairo_exec (PyObject *module) { PyObject *gobject_mod; import_cairo(); if (Pycairo_CAPI == NULL) return -1; gobject_mod = pygobject_init (3, 13, 2); if (gobject_mod == NULL) return -1; 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", cairo_context_to_arg, cairo_context_from_arg, cairo_context_release); pygi_register_foreign_struct ("cairo", "Surface", cairo_surface_to_arg, cairo_surface_from_arg, cairo_surface_release); pygi_register_foreign_struct ("cairo", "Path", cairo_path_to_arg, cairo_path_from_arg, cairo_path_release); pygi_register_foreign_struct ("cairo", "FontOptions", cairo_font_options_to_arg, cairo_font_options_from_arg, cairo_font_options_release); 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 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pygi-foreign.c0000664000000000000000000001562015074674453015514 0ustar00rootroot/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */ /* * Copyright (c) 2010 litl, LLC * Copyright (c) 2010 Collabora Ltd. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. */ #include #include "pygobject-internal.h" #include "pygi-foreign.h" #include typedef struct { const char *namespace; const char *name; PyGIArgOverrideToGIArgumentFunc to_func; PyGIArgOverrideFromGIArgumentFunc from_func; PyGIArgOverrideReleaseFunc release_func; } PyGIForeignStruct; static GPtrArray *foreign_structs = NULL; static void init_foreign_structs (void) { foreign_structs = g_ptr_array_new (); } static PyGIForeignStruct * do_lookup (const gchar *namespace, const gchar *name) { guint i; for (i = 0; i < foreign_structs->len; i++) { PyGIForeignStruct *foreign_struct = \ g_ptr_array_index (foreign_structs, i); if ( (strcmp (namespace, foreign_struct->namespace) == 0) && (strcmp (name, foreign_struct->name) == 0)) { return foreign_struct; } } 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_by_name (const char *namespace, const char *name) { PyGIForeignStruct *result; result = do_lookup (namespace, name); if (result == NULL) { PyObject *module = pygi_struct_foreign_load_module (namespace); if (module == NULL) PyErr_Clear (); else { Py_DECREF (module); result = do_lookup (namespace, name); } } if (result == NULL) { PyErr_Format (PyExc_TypeError, "Couldn't find foreign struct converter for '%s.%s'", namespace, name); } 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, GITransfer transfer, GIArgument *arg) { PyObject *result; GIBaseInfo *base_info = (GIBaseInfo *) interface_info; PyGIForeignStruct *foreign_struct = pygi_struct_foreign_lookup (base_info); if (foreign_struct == NULL) { PyErr_Format(PyExc_KeyError, "could not find foreign type %s", g_base_info_get_name (base_info)); return FALSE; } result = foreign_struct->to_func (value, interface_info, transfer, arg); return result; } PyObject * pygi_struct_foreign_convert_from_g_argument (GIInterfaceInfo *interface_info, GITransfer transfer, GIArgument *arg) { GIBaseInfo *base_info = (GIBaseInfo *) interface_info; PyGIForeignStruct *foreign_struct = pygi_struct_foreign_lookup (base_info); if (foreign_struct == NULL) return NULL; return foreign_struct->from_func (interface_info, transfer, arg); } PyObject * pygi_struct_foreign_release (GIBaseInfo *base_info, gpointer struct_) { PyGIForeignStruct *foreign_struct = pygi_struct_foreign_lookup (base_info); if (foreign_struct == NULL) return NULL; if (!foreign_struct->release_func) Py_RETURN_NONE; return foreign_struct->release_func (base_info, struct_); } void 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_; new_struct->name = name; new_struct->to_func = to_func; new_struct->from_func = from_func; new_struct->release_func = release_func; 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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pygi-foreign.h0000664000000000000000000000520015074674453015512 0ustar00rootroot/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */ /* * Copyright (c) 2010 litl, LLC * Copyright (c) 2010 Collabora Ltd. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. */ #ifndef __PYGI_FOREIGN_H__ #define __PYGI_FOREIGN_H__ #include #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 (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__ */ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pygi-fundamental.c0000664000000000000000000002075615074674453016367 0ustar00rootroot/* -*- Mode: C; c-basic-offset: 4 -*- * vim: tabstop=4 shiftwidth=4 expandtab * * Copyright (C) 2009 Simon van der Linden * Copyright (C) 2010 Tomeu Vizoso * Copyright (C) 2012 Bastian Winkler * * pygi-fundamental.c: wrapper to handle instances of fundamental 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 #include "pygobject-internal.h" #include "pygi-info.h" #include "pygi-util.h" #include "pygi-fundamental.h" #include "pygobject-object.h" // for pygobject_lookup_class static PyGIFundamental * _pygi_fundamental_new_internal (PyTypeObject *type, gpointer pointer); static void fundamental_dealloc (PyGIFundamental *self) { pygi_fundamental_unref (self); self->instance = NULL; PyObject_GC_UnTrack ((PyObject *) self); if (self->weaklist) PyObject_ClearWeakRefs ((PyObject *) self); Py_TYPE (self)->tp_free ((PyObject *) self); } static PyObject * fundamental_new (PyTypeObject *type, PyObject *args, PyObject *kwargs) { GIBaseInfo *info; gpointer pointer; PyGIFundamental *self = NULL; GType g_type; info = _pygi_object_get_gi_info ((PyObject *) type, &PyGIObjectInfo_Type); if (info == NULL) { if (PyErr_ExceptionMatches (PyExc_AttributeError)) { PyErr_Format (PyExc_TypeError, "missing introspection information"); } return NULL; } g_type = pyg_type_from_object ((PyObject *) type); if (G_TYPE_IS_ABSTRACT (g_type)) { PyErr_Format (PyExc_TypeError, "cannot instantiate abstract type %s", g_type_name (g_type)); return NULL; } pointer = g_type_create_instance (g_type); if (pointer == NULL) { PyErr_NoMemory(); goto out; } self = _pygi_fundamental_new_internal (type, pointer); if (self == NULL) { g_free (pointer); PyErr_Format (PyExc_TypeError, "cannot instantiate Fundamental Python wrapper type %s", g_type_name (g_type)); goto out; } out: g_base_info_unref (info); return (PyObject *) self; } static int fundamental_init(PyObject *self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { NULL }; if (!PyArg_ParseTupleAndKeywords (args, kwargs, ":Fundamental.__init__", kwlist)) { return -1; } return 0; } static PyObject* fundamental_richcompare (PyObject *self, PyObject *other, int op) { if (Py_TYPE (self) == Py_TYPE (other)) { return pyg_ptr_richcompare (((PyGIFundamental*) self)->instance, ((PyGIFundamental*) other)->instance, op); } else { Py_INCREF (Py_NotImplemented); return Py_NotImplemented; } } static Py_hash_t fundamental_hash (PyGIFundamental *self) { return (Py_hash_t)(gintptr)(self->instance); } static PyObject * fundamental_repr (PyGIFundamental *self) { gchar buf[128]; g_snprintf (buf, sizeof(buf), "<%s at 0x%" G_GUINTPTR_FORMAT ">", g_type_name (self->gtype), (guintptr) self->instance); return PyUnicode_FromString (buf); } PYGI_DEFINE_TYPE("gi.Fundamental", PyGIFundamental_Type, PyGIFundamental); PyObject * pygi_fundamental_new (gpointer instance) { GType gtype; PyTypeObject *type; PyGIFundamental *self; if (!instance) { Py_RETURN_NONE; } gtype = G_TYPE_FROM_INSTANCE (instance); type = pygobject_lookup_class (gtype); self = _pygi_fundamental_new_internal (type, instance); pygi_fundamental_ref (self); return (PyObject *) self; } static PyGIFundamental * _pygi_fundamental_new_internal (PyTypeObject *type, gpointer instance) { PyGIFundamental *self; GIObjectInfo *info; if (!PyType_IsSubtype (type, &PyGIFundamental_Type)) { PyErr_SetString (PyExc_TypeError, "must be a subtype of gi.Fundamental"); return NULL; } info = _pygi_object_get_gi_info ( (PyObject *) type, &PyGIObjectInfo_Type); if (info == NULL) { if (PyErr_ExceptionMatches (PyExc_AttributeError)) { PyErr_Format (PyExc_TypeError, "missing introspection information"); } return NULL; } self = (PyGIFundamental *) type->tp_alloc (type, 0); if (self == NULL) { return NULL; } self->gtype = pyg_type_from_object ((PyObject *) type); self->instance = instance; self->ref_func = g_object_info_get_ref_function_pointer (info); self->unref_func = g_object_info_get_unref_function_pointer (info); /* A special case for GParamSpec. It has a floating reference when created. * We make sure we have a proper reference, so we can ref/unref normally. */ if (G_TYPE_IS_PARAM (self->gtype)) { g_param_spec_ref_sink (self->instance); } g_base_info_unref (info); return self; } void pygi_fundamental_ref (PyGIFundamental *self) { if (self->ref_func && self->instance) self->ref_func (self->instance); } void pygi_fundamental_unref (PyGIFundamental *self) { if (self->unref_func && self->instance) self->unref_func (self->instance); } GTypeInstance* pygi_fundamental_get (PyObject *self) { if (PyObject_TypeCheck (self, &PyGIFundamental_Type)) { return ((PyGIFundamental *) self)->instance; } else { PyErr_SetString (PyExc_TypeError, "Expected GObject Fundamental type"); return NULL; } } int pygi_fundamental_register_types (PyObject *m) { Py_SET_TYPE(&PyGIFundamental_Type, &PyType_Type); g_assert (Py_TYPE (&PyGIFundamental_Type) != NULL); PyGIFundamental_Type.tp_alloc = PyType_GenericAlloc; PyGIFundamental_Type.tp_new = (newfunc) fundamental_new; PyGIFundamental_Type.tp_init = (initproc) fundamental_init; PyGIFundamental_Type.tp_dealloc = (destructor) fundamental_dealloc; PyGIFundamental_Type.tp_flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE); PyGIFundamental_Type.tp_richcompare = fundamental_richcompare; PyGIFundamental_Type.tp_repr = (reprfunc) fundamental_repr; PyGIFundamental_Type.tp_hash = (hashfunc) fundamental_hash; PyGIFundamental_Type.tp_weaklistoffset = offsetof(PyGIFundamental, weaklist); if (PyType_Ready (&PyGIFundamental_Type)) return -1; if (PyModule_AddObject (m, "Fundamental", (PyObject *) &PyGIFundamental_Type)) return -1; return 0; } GTypeInstance* pygi_fundamental_from_value (const GValue *value) { GIRepository *repository = g_irepository_get_default (); GIBaseInfo *info = g_irepository_find_by_gtype (repository, G_VALUE_TYPE (value)); GTypeInstance *instance = NULL; if (info == NULL) return NULL; if (GI_IS_OBJECT_INFO (info)) { GIObjectInfoGetValueFunction get_value_func = g_object_info_get_get_value_function_pointer ((GIObjectInfo *) info); if (get_value_func) { instance = get_value_func (value); } } g_base_info_unref (info); return instance; } gboolean pygi_fundamental_set_value (GValue *value, GTypeInstance *instance) { GIRepository *repository; GIBaseInfo *info; gboolean result = FALSE; if (instance == NULL) return result; repository = g_irepository_get_default (); info = g_irepository_find_by_gtype (repository, G_TYPE_FROM_INSTANCE (instance)); if (info == NULL) return result; if (GI_IS_OBJECT_INFO (info)) { GIObjectInfoSetValueFunction set_value_func = g_object_info_get_set_value_function_pointer ((GIObjectInfo *) info); if (set_value_func) { set_value_func (value, instance); result = TRUE; } } g_base_info_unref (info); return result; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pygi-fundamental.h0000664000000000000000000000405115074674453016362 0ustar00rootroot/* -*- Mode: C; c-basic-offset: 4 -*- * vim: tabstop=4 shiftwidth=4 expandtab * * Copyright (C) 2009 Simon van der Linden * Copyright (C) 2010 Tomeu Vizoso * Copyright (C) 2012 Bastian Winkler * * 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_FUNDAMENTAL_H__ #define __PYGI_FUNDAMENTAL_H__ #include #include #include "pygobject-internal.h" #include "pygpointer.h" #include "pygi-type.h" G_BEGIN_DECLS extern PyTypeObject PyGIFundamental_Type; typedef struct { PyObject_HEAD PyObject* weaklist; gpointer instance; GType gtype; GIObjectInfoRefFunction ref_func; GIObjectInfoUnrefFunction unref_func; } PyGIFundamental; PyObject* pygi_fundamental_new (gpointer instance); void pygi_fundamental_ref (PyGIFundamental *self); void pygi_fundamental_unref (PyGIFundamental *self); GTypeInstance* pygi_fundamental_get (PyObject *self); int pygi_fundamental_register_types (PyObject *m); #define pygi_check_fundamental(info_type,info) \ ((info_type) == GI_INFO_TYPE_OBJECT && \ g_object_info_get_fundamental ((GIObjectInfo *)(info))) GTypeInstance* pygi_fundamental_from_value (const GValue *value); gboolean pygi_fundamental_set_value (GValue *value, GTypeInstance *instance); #endif /* __PYGI_FUNDAMENTAL_H__ */ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pygi-hashtable.c0000664000000000000000000003323715074674453016022 0ustar00rootroot/* -*- Mode: C; c-basic-offset: 4 -*- * vim: tabstop=4 shiftwidth=4 expandtab * * Copyright (C) 2011 John (J5) Palmieri * Copyright (C) 2014 Simon Feltman * * 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 . */ #include #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; } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pygi-hashtable.h0000664000000000000000000000260215074674453016017 0ustar00rootroot/* -*- Mode: C; c-basic-offset: 4 -*- * vim: tabstop=4 shiftwidth=4 expandtab * * Copyright (C) 2013 Simon Feltman * * 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 . */ #ifndef __PYGI_HASHTABLE_H__ #define __PYGI_HASHTABLE_H__ #include "pygi-cache.h" #include 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__*/ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pygi-info.c0000664000000000000000000023563615074674453015031 0ustar00rootroot/* -*- Mode: C; c-basic-offset: 4 -*- * vim: tabstop=4 shiftwidth=4 expandtab * * Copyright (C) 2005-2009 Johan Dahlin * Copyright (C) 2013 Simon Feltman * * pygi-info.c: GI.*Info 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 . */ #include "pygi-info.h" #include "pygi-cache.h" #include "pygi-invoke.h" #include "pygi-argument.h" #include "pygi-util.h" #include "pygi-basictype.h" #include "pygi-type.h" #include "pygi-fundamental.h" /* _generate_doc_string * * C wrapper to call Python implemented "gi.docstring.generate_doc_string" */ static PyObject * _generate_doc_string(PyGIBaseInfo *self) { static PyObject *_py_generate_doc_string = NULL; if (_py_generate_doc_string == NULL) { PyObject *mod = PyImport_ImportModule ("gi.docstring"); if (!mod) return NULL; _py_generate_doc_string = PyObject_GetAttrString (mod, "generate_doc_string"); if (_py_generate_doc_string == NULL) { Py_DECREF (mod); return NULL; } Py_DECREF (mod); } 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) { if (self->inst_weakreflist != NULL) PyObject_ClearWeakRefs ( (PyObject *) self); g_base_info_unref (self->info); if (self->cache != NULL) pygi_callable_cache_free ( (PyGICallableCache *) self->cache); Py_TYPE (self)->tp_free ((PyObject *)self); } static PyObject * _base_info_repr (PyGIBaseInfo *self) { return PyUnicode_FromFormat ("%s(%s)", Py_TYPE( (PyObject *) self)->tp_name, _safe_base_info_get_name (self->info)); } static PyObject * _wrap_g_base_info_equal (PyGIBaseInfo *self, PyObject *other) { GIBaseInfo *other_info; 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: return _wrap_g_base_info_equal (self, other); case Py_NE: 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; } Py_INCREF(res); return res; } 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 < 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", "assert", "break", "class", "continue", "def", "del", "elif", "else", "except", "finally", "for", "from", "global", "if", "import", "in", "is", "lambda", "nonlocal", "not", "or", "pass", "raise", "return", "try", "while", "with", "yield", "print", NULL}; #else #error Need keyword list for this major Python version #endif const gchar **i; for (i = keywords; *i != NULL; ++i) { if (strcmp (name, *i) == 0) { return TRUE; } } return FALSE; } 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 = _safe_base_info_get_name (self->info); /* escape keywords */ if (_pygi_is_python_keyword (name)) { gchar *escaped = g_strconcat (name, "_", NULL); PyObject *obj = pygi_utf8_to_py (escaped); g_free (escaped); return obj; } return pygi_utf8_to_py (name); } static PyObject * _wrap_g_base_info_get_name_unescaped (PyGIBaseInfo *self) { return _get_info_string (self, _safe_base_info_get_name); } static PyObject * _wrap_g_base_info_get_namespace (PyGIBaseInfo *self) { 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); if (info == NULL) { Py_RETURN_NONE; } return _pygi_info_new (info); } 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 } }; /* _base_info_getattro: * * The usage of __getattr__ is needed because the get/set method table * does not work for __doc__. */ static PyObject * _base_info_getattro(PyGIBaseInfo *self, PyObject *name) { PyObject *result; static PyObject *docstr; if (docstr == NULL) { docstr= PyUnicode_InternFromString ("__doc__"); if (docstr == NULL) return NULL; } Py_INCREF (name); PyUnicode_InternInPlace (&name); if (name == docstr) { result = _generate_doc_string (self); } else { result = PyObject_GenericGetAttr ((PyObject *)self, name); } Py_DECREF (name); return result; } static PyObject * _base_info_attr_name(PyGIBaseInfo *self, void *closure) { return _wrap_g_base_info_get_name (self); } static PyObject * _base_info_attr_module(PyGIBaseInfo *self, void *closure) { return PyUnicode_FromFormat ("gi.repository.%s", g_base_info_get_namespace (self->info)); } static PyGetSetDef _base_info_getsets[] = { { "__name__", (getter)_base_info_attr_name, (setter)0, "Name", NULL}, { "__module__", (getter)_base_info_attr_module, (setter)0, "Module name", NULL}, { NULL, 0, 0 } }; PyObject * _pygi_info_new (GIBaseInfo *info) { GIInfoType info_type; PyTypeObject *type = NULL; PyGIBaseInfo *self; info_type = g_base_info_get_type (info); switch (info_type) { case GI_INFO_TYPE_INVALID: PyErr_SetString (PyExc_RuntimeError, "Invalid info type"); return NULL; case GI_INFO_TYPE_FUNCTION: type = &PyGIFunctionInfo_Type; break; case GI_INFO_TYPE_CALLBACK: type = &PyGICallbackInfo_Type; break; case GI_INFO_TYPE_STRUCT: case GI_INFO_TYPE_BOXED: type = &PyGIStructInfo_Type; break; case GI_INFO_TYPE_ENUM: case GI_INFO_TYPE_FLAGS: type = &PyGIEnumInfo_Type; break; case GI_INFO_TYPE_OBJECT: type = &PyGIObjectInfo_Type; break; case GI_INFO_TYPE_INTERFACE: type = &PyGIInterfaceInfo_Type; break; case GI_INFO_TYPE_CONSTANT: type = &PyGIConstantInfo_Type; break; case GI_INFO_TYPE_UNION: type = &PyGIUnionInfo_Type; break; case GI_INFO_TYPE_VALUE: type = &PyGIValueInfo_Type; break; case GI_INFO_TYPE_SIGNAL: type = &PyGISignalInfo_Type; break; case GI_INFO_TYPE_VFUNC: type = &PyGIVFuncInfo_Type; break; case GI_INFO_TYPE_PROPERTY: type = &PyGIPropertyInfo_Type; break; case GI_INFO_TYPE_FIELD: type = &PyGIFieldInfo_Type; break; case GI_INFO_TYPE_ARG: type = &PyGIArgInfo_Type; break; case GI_INFO_TYPE_TYPE: type = &PyGITypeInfo_Type; break; case GI_INFO_TYPE_UNRESOLVED: type = &PyGIUnresolvedInfo_Type; break; default: g_assert_not_reached(); break; } self = (PyGIBaseInfo *) type->tp_alloc (type, 0); if (self == NULL) { return NULL; } self->info = g_base_info_ref (info); self->inst_weakreflist = NULL; self->cache = NULL; return (PyObject *) self; } GIBaseInfo * _pygi_object_get_gi_info (PyObject *object, PyTypeObject *type) { PyObject *py_info; GIBaseInfo *info = NULL; py_info = PyObject_GetAttrString (object, "__info__"); if (py_info == NULL) { return NULL; } 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); goto out; } info = ( (PyGIBaseInfo *) py_info)->info; g_base_info_ref (info); out: Py_DECREF (py_info); return info; } /* CallableInfo */ PYGI_DEFINE_TYPE ("gi.CallableInfo", PyGICallableInfo_Type, PyGICallableInfo); /* _callable_info_call: * * Shared wrapper for invoke which can be bound (instance method or class constructor) * or unbound (function or static method). */ static PyObject * _callable_info_call (PyGICallableInfo *self, PyObject *args, PyObject *kwargs) { /* Insert the bound arg at the beginning of the invoke method args. */ if (self->py_bound_arg) { int i; PyObject *result; Py_ssize_t argcount = PyTuple_Size (args); PyObject *newargs = PyTuple_New (argcount + 1); if (newargs == NULL) return NULL; Py_INCREF (self->py_bound_arg); PyTuple_SET_ITEM (newargs, 0, self->py_bound_arg); for (i = 0; i < argcount; i++) { PyObject *v = PyTuple_GET_ITEM (args, i); Py_XINCREF (v); PyTuple_SET_ITEM (newargs, i+1, v); } /* Invoke with the original GI info struct this wrapper was based upon. * This is necessary to maintain the same cache for all bound versions. */ result = _wrap_g_callable_info_invoke ((PyGIBaseInfo *)self->py_unbound_info, newargs, kwargs); Py_DECREF (newargs); return result; } else { /* We should never have an unbound info when calling when calling invoke * at this point because the descriptor implementation on sub-classes * should return "self" not a copy when there is no bound arg. */ g_assert (self->py_unbound_info == NULL); return _wrap_g_callable_info_invoke ((PyGIBaseInfo *)self, args, 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: * * Specialization of _callable_info_call for GIFunctionInfo which * handles constructor error conditions. */ static PyObject * _function_info_call (PyGICallableInfo *self, PyObject *args, PyObject *kwargs) { if (self->py_bound_arg) { GIFunctionInfoFlags flags; /* Ensure constructors are only called as class methods on the class * implementing the constructor and not on sub-classes. */ flags = g_function_info_get_flags ( (GIFunctionInfo*) self->base.info); if (flags & GI_FUNCTION_IS_CONSTRUCTOR) { PyObject *py_str_name; const gchar *str_name; GIBaseInfo *container_info = g_base_info_get_container (self->base.info); g_assert (container_info != NULL); py_str_name = PyObject_GetAttrString (self->py_bound_arg, "__name__"); if (py_str_name == NULL) return NULL; if (PyUnicode_Check (py_str_name) ) { PyObject *tmp = PyUnicode_AsUTF8String (py_str_name); Py_DECREF (py_str_name); py_str_name = tmp; } str_name = PyBytes_AsString (py_str_name); 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", _safe_base_info_get_name (container_info), str_name); Py_DECREF (py_str_name); return NULL; } Py_DECREF (py_str_name); } } return _callable_info_call (self, args, kwargs); } /* _new_bound_callable_info * * Utility function for sub-classes to create a bound version of themself. */ static PyGICallableInfo * _new_bound_callable_info (PyGICallableInfo *self, PyObject *bound_arg) { PyGICallableInfo *new_self; /* Return self if this is already bound or there is nothing passed to bind. */ if (self->py_bound_arg != NULL || bound_arg == NULL || bound_arg == Py_None) { Py_INCREF ((PyObject *)self); return self; } new_self = (PyGICallableInfo *)_pygi_info_new (self->base.info); if (new_self == NULL) return NULL; Py_INCREF ((PyObject *)self); new_self->py_unbound_info = (struct PyGICallableInfo *)self; Py_INCREF (bound_arg); new_self->py_bound_arg = bound_arg; return new_self; } /* _function_info_descr_get * * Descriptor protocol implementation for functions, methods, and constructors. */ static PyObject * _function_info_descr_get (PyGICallableInfo *self, PyObject *obj, PyObject *type) { GIFunctionInfoFlags flags; PyObject *bound_arg = NULL; flags = g_function_info_get_flags ( (GIFunctionInfo*) self->base.info); if (flags & GI_FUNCTION_IS_CONSTRUCTOR) { if (type == NULL) bound_arg = (PyObject *)(Py_TYPE(obj)); else bound_arg = type; } else if (flags & GI_FUNCTION_IS_METHOD) { bound_arg = obj; } return (PyObject *)_new_bound_callable_info (self, bound_arg); } /* _vfunc_info_descr_get * * Descriptor protocol implementation for virtual functions. */ static PyObject * _vfunc_info_descr_get (PyGICallableInfo *self, PyObject *obj, PyObject *type) { PyObject *result; PyObject *bound_arg = NULL; bound_arg = PyObject_GetAttrString (type, "__gtype__"); if (bound_arg == NULL) return NULL; /* _new_bound_callable_info adds its own ref so free the one from GetAttrString */ result = (PyObject *)_new_bound_callable_info (self, bound_arg); Py_DECREF (bound_arg); return result; } static void _callable_info_dealloc (PyGICallableInfo *self) { Py_CLEAR (self->py_unbound_info); Py_CLEAR (self->py_bound_arg); 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 */ PYGI_DEFINE_TYPE ("gi.CallbackInfo", PyGICallbackInfo_Type, PyGICallableInfo); static PyMethodDef _PyGICallbackInfo_methods[] = { { NULL, NULL, 0 } }; /* ErrorDomainInfo */ PYGI_DEFINE_TYPE ("gi.ErrorDomainInfo", PyGIErrorDomainInfo_Type, PyGIBaseInfo); static PyMethodDef _PyGIErrorDomainInfo_methods[] = { { NULL, NULL, 0 } }; /* SignalInfo */ 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 */ 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 */ PYGI_DEFINE_TYPE ("gi.ArgInfo", PyGIArgInfo_Type, PyGIBaseInfo); static PyObject * _wrap_g_arg_info_get_direction (PyGIBaseInfo *self) { 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 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 pygi_gboolean_to_py ( g_arg_info_is_return_value ((GIArgInfo*)self->info) ); } static PyObject * _wrap_g_arg_info_is_optional (PyGIBaseInfo *self) { 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 pygi_gboolean_to_py ( g_arg_info_may_be_null ((GIArgInfo*)self->info) ); } static PyObject * _wrap_g_arg_info_get_ownership_transfer (PyGIBaseInfo *self) { return pygi_guint_to_py ( g_arg_info_get_ownership_transfer ((GIArgInfo *)self->info) ); } static PyObject * _wrap_g_arg_info_get_scope (PyGIBaseInfo *self) { return pygi_guint_to_py ( g_arg_info_get_scope ((GIArgInfo *)self->info) ); } 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[] = { { "get_direction", (PyCFunction) _wrap_g_arg_info_get_direction, METH_NOARGS }, { "is_caller_allocates", (PyCFunction) _wrap_g_arg_info_is_caller_allocates, METH_NOARGS }, { "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_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 */ 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 */ PYGI_DEFINE_TYPE ("gi.FunctionInfo", PyGIFunctionInfo_Type, PyGICallableInfo); static PyObject * _wrap_g_function_info_is_constructor (PyGIBaseInfo *self) { GIFunctionInfoFlags flags; gboolean is_constructor; flags = g_function_info_get_flags ( (GIFunctionInfo*) self->info); is_constructor = flags & GI_FUNCTION_IS_CONSTRUCTOR; return pygi_gboolean_to_py (is_constructor); } static PyObject * _wrap_g_function_info_is_method (PyGIBaseInfo *self) { GIFunctionInfoFlags flags; gboolean is_method; flags = g_function_info_get_flags ( (GIFunctionInfo*) self->info); is_method = flags & GI_FUNCTION_IS_METHOD; return pygi_gboolean_to_py (is_method); } gsize _pygi_g_type_tag_size (GITypeTag type_tag) { gsize size = 0; switch (type_tag) { case GI_TYPE_TAG_BOOLEAN: size = sizeof (gboolean); break; case GI_TYPE_TAG_INT8: case GI_TYPE_TAG_UINT8: size = sizeof (gint8); break; case GI_TYPE_TAG_INT16: case GI_TYPE_TAG_UINT16: size = sizeof (gint16); break; case GI_TYPE_TAG_INT32: case GI_TYPE_TAG_UINT32: size = sizeof (gint32); break; case GI_TYPE_TAG_INT64: case GI_TYPE_TAG_UINT64: size = sizeof (gint64); break; case GI_TYPE_TAG_FLOAT: size = sizeof (gfloat); break; case GI_TYPE_TAG_DOUBLE: size = sizeof (gdouble); break; case GI_TYPE_TAG_GTYPE: size = sizeof (GType); break; case GI_TYPE_TAG_UNICHAR: size = sizeof (gunichar); break; case GI_TYPE_TAG_VOID: case GI_TYPE_TAG_UTF8: case GI_TYPE_TAG_FILENAME: 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: PyErr_Format (PyExc_TypeError, "Unable to know the size (assuming %s is not a pointer)", g_type_tag_to_string (type_tag)); break; default: break; } return size; } gsize _pygi_g_type_info_size (GITypeInfo *type_info) { gsize size = 0; GITypeTag type_tag; type_tag = g_type_info_get_tag (type_info); switch (type_tag) { 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_GTYPE: case GI_TYPE_TAG_UNICHAR: size = _pygi_g_type_tag_size (type_tag); g_assert (size > 0); 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); switch (info_type) { case GI_INFO_TYPE_STRUCT: if (g_type_info_is_pointer (type_info)) { size = sizeof (gpointer); } else { size = g_struct_info_get_size ( (GIStructInfo *) info); } break; case GI_INFO_TYPE_UNION: if (g_type_info_is_pointer (type_info)) { size = sizeof (gpointer); } else { size = g_union_info_get_size ( (GIUnionInfo *) info); } break; case GI_INFO_TYPE_ENUM: case GI_INFO_TYPE_FLAGS: if (g_type_info_is_pointer (type_info)) { size = sizeof (gpointer); } else { GITypeTag enum_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: case GI_INFO_TYPE_OBJECT: case GI_INFO_TYPE_INTERFACE: case GI_INFO_TYPE_CALLBACK: size = sizeof (gpointer); break; case GI_INFO_TYPE_VFUNC: case GI_INFO_TYPE_INVALID: case GI_INFO_TYPE_FUNCTION: case GI_INFO_TYPE_CONSTANT: case GI_INFO_TYPE_VALUE: case GI_INFO_TYPE_SIGNAL: case GI_INFO_TYPE_PROPERTY: case GI_INFO_TYPE_FIELD: case GI_INFO_TYPE_ARG: case GI_INFO_TYPE_TYPE: case GI_INFO_TYPE_UNRESOLVED: default: g_assert_not_reached(); break; } g_base_info_unref (info); break; } case GI_TYPE_TAG_ARRAY: case GI_TYPE_TAG_VOID: case GI_TYPE_TAG_UTF8: case GI_TYPE_TAG_FILENAME: case GI_TYPE_TAG_GLIST: case GI_TYPE_TAG_GSLIST: case GI_TYPE_TAG_GHASH: 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 */ 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) { GType type; type = g_registered_type_info_get_g_type ( (GIRegisteredTypeInfo *) self->info); return pyg_type_wrapper_new (type); } 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 */ PYGI_DEFINE_TYPE ("StructInfo", PyGIStructInfo_Type, PyGIBaseInfo); static PyObject * _wrap_g_struct_info_get_fields (PyGIBaseInfo *self) { return _make_infos_tuple (self, g_struct_info_get_n_fields, g_struct_info_get_field); } static PyObject * _wrap_g_struct_info_get_methods (PyGIBaseInfo *self) { return _make_infos_tuple (self, g_struct_info_get_n_methods, g_struct_info_get_method); } static PyObject * _wrap_g_struct_info_get_size (PyGIBaseInfo *self) { return pygi_gsize_to_py (g_struct_info_get_size (self->info)); } static PyObject * _wrap_g_struct_info_get_alignment (PyGIBaseInfo *self) { return pygi_gsize_to_py (g_struct_info_get_alignment (self->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)); } 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_find_method (PyGIBaseInfo *self, PyObject *py_name) { return _get_child_info_by_name (self, py_name, g_struct_info_find_method); } static PyObject * _wrap_g_struct_info_find_field (PyGIBaseInfo *self, PyObject *py_name) { 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 } }; gboolean pygi_g_struct_info_is_simple (GIStructInfo *struct_info) { gboolean is_simple; gint n_field_infos; gint i; is_simple = TRUE; n_field_infos = g_struct_info_get_n_fields (struct_info); for (i = 0; i < n_field_infos && is_simple; i++) { GIFieldInfo *field_info; GITypeInfo *field_type_info; GITypeTag field_type_tag; field_info = g_struct_info_get_field (struct_info, i); field_type_info = g_field_info_get_type (field_info); field_type_tag = g_type_info_get_tag (field_type_info); switch (field_type_tag) { 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: if (g_type_info_is_pointer (field_type_info)) { is_simple = FALSE; } break; case GI_TYPE_TAG_VOID: case GI_TYPE_TAG_GTYPE: case GI_TYPE_TAG_ERROR: case GI_TYPE_TAG_UTF8: case GI_TYPE_TAG_FILENAME: case GI_TYPE_TAG_ARRAY: case GI_TYPE_TAG_GLIST: case GI_TYPE_TAG_GSLIST: case GI_TYPE_TAG_GHASH: is_simple = FALSE; break; case GI_TYPE_TAG_INTERFACE: { GIBaseInfo *info; GIInfoType info_type; info = g_type_info_get_interface (field_type_info); info_type = g_base_info_get_type (info); switch (info_type) { case GI_INFO_TYPE_STRUCT: if (g_type_info_is_pointer (field_type_info)) { is_simple = FALSE; } else { is_simple = pygi_g_struct_info_is_simple ( (GIStructInfo *) info); } break; case GI_INFO_TYPE_UNION: /* TODO */ is_simple = FALSE; break; case GI_INFO_TYPE_ENUM: case GI_INFO_TYPE_FLAGS: if (g_type_info_is_pointer (field_type_info)) { is_simple = FALSE; } break; case GI_INFO_TYPE_BOXED: case GI_INFO_TYPE_OBJECT: case GI_INFO_TYPE_CALLBACK: case GI_INFO_TYPE_INTERFACE: is_simple = FALSE; break; case GI_INFO_TYPE_VFUNC: case GI_INFO_TYPE_INVALID: case GI_INFO_TYPE_FUNCTION: case GI_INFO_TYPE_CONSTANT: case GI_INFO_TYPE_VALUE: case GI_INFO_TYPE_SIGNAL: case GI_INFO_TYPE_PROPERTY: case GI_INFO_TYPE_FIELD: case GI_INFO_TYPE_ARG: case GI_INFO_TYPE_TYPE: case GI_INFO_TYPE_UNRESOLVED: default: g_assert_not_reached(); break; } g_base_info_unref (info); break; } default: g_assert_not_reached(); break; } g_base_info_unref ( (GIBaseInfo *) field_type_info); g_base_info_unref ( (GIBaseInfo *) field_info); } return is_simple; } /* EnumInfo */ PYGI_DEFINE_TYPE ("gi.EnumInfo", PyGIEnumInfo_Type, PyGIBaseInfo); static PyObject * _wrap_g_enum_info_get_values (PyGIBaseInfo *self) { return _make_infos_tuple (self, g_enum_info_get_n_values, g_enum_info_get_value); } static PyObject * _wrap_g_enum_info_is_flags (PyGIBaseInfo *self) { GIInfoType info_type = g_base_info_get_type ((GIBaseInfo *) self->info); if (info_type == GI_INFO_TYPE_ENUM) { Py_RETURN_FALSE; } else if (info_type == GI_INFO_TYPE_FLAGS) { Py_RETURN_TRUE; } else { g_assert_not_reached(); } } 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 */ PYGI_DEFINE_TYPE ("ObjectInfo", PyGIObjectInfo_Type, PyGIBaseInfo); static PyObject * _wrap_g_object_info_get_parent (PyGIBaseInfo *self) { return _get_child_info (self, g_object_info_get_parent); } static PyObject * _wrap_g_object_info_get_methods (PyGIBaseInfo *self) { return _make_infos_tuple (self, g_object_info_get_n_methods, g_object_info_get_method); } static PyObject * _wrap_g_object_info_find_method (PyGIBaseInfo *self, PyObject *py_name) { return _get_child_info_by_name (self, py_name, g_object_info_find_method); } static PyObject * _wrap_g_object_info_get_fields (PyGIBaseInfo *self) { return _make_infos_tuple (self, g_object_info_get_n_fields, g_object_info_get_field); } 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); } 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); } 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 _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 _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 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) { return _get_child_info (self, g_object_info_get_class_struct); } 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); } static PyObject * _wrap_g_object_info_get_unref_function (PyGIBaseInfo *self) { return _get_info_string (self, g_object_info_get_unref_function); } 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 */ PYGI_DEFINE_TYPE ("InterfaceInfo", PyGIInterfaceInfo_Type, PyGIBaseInfo); static PyObject * _wrap_g_interface_info_get_methods (PyGIBaseInfo *self) { return _make_infos_tuple (self, g_interface_info_get_n_methods, g_interface_info_get_method); } 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); } 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); } 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); } 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); } 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); } 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); } 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_signals (PyGIBaseInfo *self) { return _make_infos_tuple (self, g_interface_info_get_n_signals, g_interface_info_get_signal); } static PyObject * _wrap_g_interface_info_find_signal (PyGIBaseInfo *self, PyObject *py_name) { 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 }, { "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 */ PYGI_DEFINE_TYPE ("gi.ConstantInfo", PyGIConstantInfo_Type, PyGIBaseInfo); static PyObject * _wrap_g_constant_info_get_value (PyGIBaseInfo *self) { GITypeInfo *type_info; GIArgument value = {0}; PyObject *py_value; gboolean free_array = FALSE; if (g_constant_info_get_value ( (GIConstantInfo *) self->info, &value) < 0) { PyErr_SetString (PyExc_RuntimeError, "unable to get value"); return NULL; } type_info = g_constant_info_get_type ( (GIConstantInfo *) self->info); if (g_type_info_get_tag (type_info) == GI_TYPE_TAG_ARRAY) { value.v_pointer = _pygi_argument_to_array (&value, NULL, NULL, NULL, type_info, &free_array); } py_value = _pygi_argument_to_object (&value, type_info, GI_TRANSFER_NOTHING); if (free_array) { g_array_free (value.v_pointer, FALSE); } g_constant_info_free_value (self->info, &value); g_base_info_unref ( (GIBaseInfo *) type_info); return py_value; } static PyMethodDef _PyGIConstantInfo_methods[] = { { "get_value", (PyCFunction) _wrap_g_constant_info_get_value, METH_NOARGS }, { NULL, NULL, 0 } }; /* GIValueInfo */ PYGI_DEFINE_TYPE ("gi.ValueInfo", PyGIValueInfo_Type, PyGIBaseInfo); static PyObject * _wrap_g_value_info_get_value (PyGIBaseInfo *self) { gint64 value; value = g_value_info_get_value ( (GIValueInfo *) self->info); return pygi_gint64_to_py (value); } static PyMethodDef _PyGIValueInfo_methods[] = { { "get_value", (PyCFunction) _wrap_g_value_info_get_value, METH_NOARGS }, { NULL, NULL, 0 } }; /* GIFieldInfo */ 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, PyObject *args) { PyObject *instance; GIBaseInfo *container_info; GIInfoType container_info_type; gpointer pointer; GITypeInfo *field_type_info; GIArgument value; PyObject *py_value = NULL; gboolean free_array = FALSE; memset(&value, 0, sizeof(GIArgument)); if (!PyArg_ParseTuple (args, "O:FieldInfo.get_value", &instance)) { return NULL; } container_info = g_base_info_get_container (self->info); g_assert (container_info != NULL); /* Check the instance. */ if (!_pygi_g_registered_type_info_check_object ( (GIRegisteredTypeInfo *) container_info, instance)) { _PyGI_ERROR_PREFIX ("argument 1: "); return NULL; } /* Get the pointer to the container. */ container_info_type = g_base_info_get_type (container_info); switch (container_info_type) { case GI_INFO_TYPE_UNION: case GI_INFO_TYPE_STRUCT: pointer = pyg_boxed_get (instance, void); break; case GI_INFO_TYPE_OBJECT: if (pygi_check_fundamental (container_info_type, container_info)) pointer = pygi_fundamental_get (instance); else pointer = pygobject_get (instance); break; default: /* Other types don't have fields. */ g_assert_not_reached(); } if (pointer == NULL) { PyErr_Format(PyExc_RuntimeError, "object at %p of type %s is not initialized", instance, Py_TYPE(instance)->tp_name); return NULL; } /* Get the field's value. */ field_type_info = g_field_info_get_type ( (GIFieldInfo *) self->info); /* A few types are not handled by g_field_info_get_field, so do it here. */ if (!g_type_info_is_pointer (field_type_info) && g_type_info_get_tag (field_type_info) == GI_TYPE_TAG_INTERFACE) { GIBaseInfo *info; GIInfoType info_type; if (! (g_field_info_get_flags ( (GIFieldInfo *) self->info) & GI_FIELD_IS_READABLE)) { PyErr_SetString (PyExc_RuntimeError, "field is not readable"); goto out; } info = g_type_info_get_interface (field_type_info); info_type = g_base_info_get_type (info); g_base_info_unref (info); switch (info_type) { case GI_INFO_TYPE_UNION: PyErr_SetString (PyExc_NotImplementedError, "getting an union is not supported yet"); goto out; case GI_INFO_TYPE_STRUCT: { gsize offset; offset = g_field_info_get_offset ( (GIFieldInfo *) self->info); value.v_pointer = (char*) pointer + offset; goto argument_to_object; } default: /* Fallback. */ break; } } if (!g_field_info_get_field ( (GIFieldInfo *) self->info, pointer, &value)) { PyErr_SetString (PyExc_RuntimeError, "unable to get the value"); goto out; } if (g_type_info_get_tag (field_type_info) == GI_TYPE_TAG_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: py_value = _pygi_argument_to_object (&value, field_type_info, GI_TRANSFER_NOTHING); if (free_array) { g_array_free (value.v_pointer, FALSE); } out: g_base_info_unref ( (GIBaseInfo *) field_type_info); return py_value; } static PyObject * _wrap_g_field_info_set_value (PyGIBaseInfo *self, PyObject *args) { PyObject *instance; PyObject *py_value; GIBaseInfo *container_info; GIInfoType container_info_type; gpointer pointer; GITypeInfo *field_type_info; GIArgument value; PyObject *retval = NULL; if (!PyArg_ParseTuple (args, "OO:FieldInfo.set_value", &instance, &py_value)) { return NULL; } container_info = g_base_info_get_container (self->info); g_assert (container_info != NULL); /* Check the instance. */ if (!_pygi_g_registered_type_info_check_object ( (GIRegisteredTypeInfo *) container_info, instance)) { _PyGI_ERROR_PREFIX ("argument 1: "); return NULL; } /* Get the pointer to the container. */ container_info_type = g_base_info_get_type (container_info); switch (container_info_type) { case GI_INFO_TYPE_UNION: case GI_INFO_TYPE_STRUCT: pointer = pyg_boxed_get (instance, void); break; case GI_INFO_TYPE_OBJECT: if (pygi_check_fundamental (container_info_type, container_info)) pointer = pygi_fundamental_get (instance); else pointer = pygobject_get (instance); break; default: /* Other types don't have fields. */ g_assert_not_reached(); } if (pointer == NULL) { PyErr_Format(PyExc_RuntimeError, "object at %p of type %s is not initialized", instance, Py_TYPE(instance)->tp_name); return NULL; } field_type_info = g_field_info_get_type ( (GIFieldInfo *) self->info); /* 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) && g_type_info_get_tag (field_type_info) == GI_TYPE_TAG_INTERFACE) { GIBaseInfo *info; GIInfoType info_type; if (! (g_field_info_get_flags ( (GIFieldInfo *) self->info) & GI_FIELD_IS_WRITABLE)) { PyErr_SetString (PyExc_RuntimeError, "field is not writable"); goto out; } info = g_type_info_get_interface (field_type_info); info_type = g_base_info_get_type (info); switch (info_type) { case GI_INFO_TYPE_UNION: PyErr_SetString (PyExc_NotImplementedError, "setting an union is not supported yet"); goto out; case GI_INFO_TYPE_STRUCT: { gboolean is_simple; gsize offset; gssize size; is_simple = pygi_g_struct_info_is_simple ( (GIStructInfo *) info); if (!is_simple) { PyErr_SetString (PyExc_TypeError, "cannot set a structure which has no well-defined ownership transfer rules"); g_base_info_unref (info); goto out; } value = _pygi_argument_from_object (py_value, field_type_info, GI_TRANSFER_NOTHING); if (PyErr_Occurred()) { g_base_info_unref (info); goto out; } offset = g_field_info_get_offset ( (GIFieldInfo *) self->info); size = g_struct_info_get_size ( (GIStructInfo *) info); g_assert (size > 0); memmove ((char*) pointer + offset, value.v_pointer, size); g_base_info_unref (info); retval = Py_None; goto out; } default: /* Fallback. */ break; } g_base_info_unref (info); } else if (g_type_info_is_pointer (field_type_info) && (g_type_info_get_tag (field_type_info) == GI_TYPE_TAG_VOID || g_type_info_get_tag (field_type_info) == GI_TYPE_TAG_UTF8)) { int offset; value = _pygi_argument_from_object (py_value, field_type_info, GI_TRANSFER_NOTHING); if (PyErr_Occurred()) { goto out; } offset = g_field_info_get_offset ((GIFieldInfo *) self->info); G_STRUCT_MEMBER (gpointer, pointer, offset) = (gpointer)value.v_pointer; retval = Py_None; goto out; } value = _pygi_argument_from_object (py_value, field_type_info, GI_TRANSFER_EVERYTHING); if (PyErr_Occurred()) { goto out; } if (!g_field_info_set_field ( (GIFieldInfo *) self->info, pointer, &value)) { _pygi_argument_release (&value, field_type_info, GI_TRANSFER_NOTHING, GI_DIRECTION_IN); PyErr_SetString (PyExc_RuntimeError, "unable to set value for field"); goto out; } retval = Py_None; out: g_base_info_unref ( (GIBaseInfo *) field_type_info); Py_XINCREF (retval); 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 */ PYGI_DEFINE_TYPE ("gi.UnresolvedInfo", PyGIUnresolvedInfo_Type, PyGIBaseInfo); static PyMethodDef _PyGIUnresolvedInfo_methods[] = { { NULL, NULL, 0 } }; /* GIVFuncInfo */ PYGI_DEFINE_TYPE ("gi.VFuncInfo", PyGIVFuncInfo_Type, PyGICallableInfo); static PyObject * _wrap_g_vfunc_info_get_flags (PyGIBaseInfo *self) { return pygi_guint_to_py (g_vfunc_info_get_flags ((GIVFuncInfo *) self->info)); } static PyObject * _wrap_g_vfunc_info_get_offset (PyGIBaseInfo *self) { return pygi_gint_to_py (g_vfunc_info_get_offset ((GIVFuncInfo *) self->info)); } 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 */ PYGI_DEFINE_TYPE ("gi.UnionInfo", PyGIUnionInfo_Type, PyGIBaseInfo); static PyObject * _wrap_g_union_info_get_fields (PyGIBaseInfo *self) { 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) { return _make_infos_tuple (self, g_union_info_get_n_methods, g_union_info_get_method); } static PyObject * _wrap_g_union_info_get_size (PyGIBaseInfo *self) { return pygi_gsize_to_py (g_union_info_get_size (self->info)); } 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 } }; /* Private */ gchar * _pygi_g_base_info_get_fullname (GIBaseInfo *info) { GIBaseInfo *container_info; gchar *fullname; container_info = g_base_info_get_container (info); if (container_info != NULL) { fullname = g_strdup_printf ("%s.%s.%s", g_base_info_get_namespace (container_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), _safe_base_info_get_name (info)); } if (fullname == NULL) { PyErr_NoMemory(); } return fullname; } /** * 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_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) < 0) \ return -1; \ Py_INCREF ((PyObject *)&type); \ if (PyModule_AddObject(m, #cname, (PyObject *)&type) < 0) { \ Py_DECREF ((PyObject *)&type); \ return -1; \ }; Py_SET_TYPE(&PyGIBaseInfo_Type, &PyType_Type); PyGIBaseInfo_Type.tp_dealloc = (destructor) _base_info_dealloc; PyGIBaseInfo_Type.tp_repr = (reprfunc) _base_info_repr; PyGIBaseInfo_Type.tp_flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE); PyGIBaseInfo_Type.tp_weaklistoffset = offsetof(PyGIBaseInfo, inst_weakreflist); PyGIBaseInfo_Type.tp_methods = _PyGIBaseInfo_methods; PyGIBaseInfo_Type.tp_richcompare = (richcmpfunc)_base_info_richcompare; PyGIBaseInfo_Type.tp_getset = _base_info_getsets; PyGIBaseInfo_Type.tp_getattro = (getattrofunc) _base_info_getattro; 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; } 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); _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, PyGICallableInfo_Type); _PyGI_REGISTER_TYPE (m, PyGIRegisteredTypeInfo_Type, RegisteredTypeInfo, PyGIBaseInfo_Type); _PyGI_REGISTER_TYPE (m, PyGIStructInfo_Type, StructInfo, PyGIRegisteredTypeInfo_Type); _PyGI_REGISTER_TYPE (m, PyGIEnumInfo_Type, EnumInfo, PyGIRegisteredTypeInfo_Type); _PyGI_REGISTER_TYPE (m, PyGIObjectInfo_Type, ObjectInfo, PyGIRegisteredTypeInfo_Type); _PyGI_REGISTER_TYPE (m, PyGIInterfaceInfo_Type, InterfaceInfo, PyGIRegisteredTypeInfo_Type); _PyGI_REGISTER_TYPE (m, PyGIConstantInfo_Type, ConstantInfo, PyGIBaseInfo_Type); _PyGI_REGISTER_TYPE (m, PyGIValueInfo_Type, ValueInfo, PyGIBaseInfo_Type); _PyGI_REGISTER_TYPE (m, PyGIFieldInfo_Type, FieldInfo, PyGIBaseInfo_Type); _PyGI_REGISTER_TYPE (m, PyGIUnionInfo_Type, UnionInfo, PyGIRegisteredTypeInfo_Type); _PyGI_REGISTER_TYPE (m, PyGIErrorDomainInfo_Type, ErrorDomainInfo, PyGIBaseInfo_Type); _PyGI_REGISTER_TYPE (m, PyGIPropertyInfo_Type, PropertyInfo, PyGIBaseInfo_Type); _PyGI_REGISTER_TYPE (m, PyGIArgInfo_Type, ArgInfo, PyGIBaseInfo_Type); _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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pygi-info.h0000664000000000000000000000567315074674453015032 0ustar00rootroot/* -*- Mode: C; c-basic-offset: 4 -*- * vim: tabstop=4 shiftwidth=4 expandtab * * Copyright (C) 2005-2009 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 . */ #ifndef __PYGI_INFO_H__ #define __PYGI_INFO_H__ #include #include #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); /* Private */ extern PyTypeObject PyGIBaseInfo_Type; extern PyTypeObject PyGICallableInfo_Type; extern PyTypeObject PyGICallbackInfo_Type; extern PyTypeObject PyGIFunctionInfo_Type; extern PyTypeObject PyGIRegisteredTypeInfo_Type; extern PyTypeObject PyGIStructInfo_Type; extern PyTypeObject PyGIEnumInfo_Type; extern PyTypeObject PyGIObjectInfo_Type; extern PyTypeObject PyGIInterfaceInfo_Type; extern PyTypeObject PyGIConstantInfo_Type; extern PyTypeObject PyGIValueInfo_Type; extern PyTypeObject PyGIFieldInfo_Type; extern PyTypeObject PyGIUnresolvedInfo_Type; extern PyTypeObject PyGIVFuncInfo_Type; extern PyTypeObject PyGIUnionInfo_Type; extern PyTypeObject PyGIBoxedInfo_Type; extern PyTypeObject PyGIFundamental_Type; extern PyTypeObject PyGIErrorDomainInfo_Type; extern PyTypeObject PyGISignalInfo_Type; extern PyTypeObject PyGIPropertyInfo_Type; extern PyTypeObject PyGIArgInfo_Type; extern PyTypeObject PyGITypeInfo_Type; #define PyGIBaseInfo_GET_GI_INFO(object) g_base_info_ref(((PyGIBaseInfo *)object)->info) PyObject* _pygi_info_new (GIBaseInfo *info); GIBaseInfo* _pygi_object_get_gi_info (PyObject *object, PyTypeObject *type); 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); int pygi_info_register_types (PyObject *m); gboolean _pygi_is_python_keyword (const gchar *name); G_END_DECLS #endif /* __PYGI_INFO_H__ */ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pygi-invoke-state-struct.h0000664000000000000000000000360215074674453020020 0ustar00rootroot#ifndef __PYGI_INVOKE_STATE_STRUCT_H__ #define __PYGI_INVOKE_STATE_STRUCT_H__ #include #include 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; /* 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 **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; /* An awaitable to return for an async function that was called with * default arguments. */ PyObject *py_async; gpointer user_data; /* Function pointer to call with ffi. */ gpointer function_ptr; } PyGIInvokeState; G_END_DECLS #endif ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pygi-invoke.c0000664000000000000000000007651615074674453015371 0ustar00rootroot/* -*- Mode: C; c-basic-offset: 4 -*- * vim: tabstop=4 shiftwidth=4 expandtab * * Copyright (C) 2005-2009 Johan Dahlin * Copyright (C) 2011 John (J5) Palimier * * pygi-invoke.c: main invocation function * * 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 . */ #include "pygi-invoke.h" #include "pygi-marshal-cleanup.h" #include "pygi-error.h" #include "pygi-resulttuple.h" #include "pygi-async.h" #include "pygi-foreign.h" #include "pygi-boxed.h" extern PyObject *_PyGIDefaultArgPlaceholder; static gboolean _check_for_unexpected_kwargs (PyGICallableCache *cache, GHashTable *arg_name_hash, PyObject *py_kwargs) { PyObject *dict_key, *dict_value; Py_ssize_t dict_iter_pos = 0; while (PyDict_Next (py_kwargs, &dict_iter_pos, &dict_key, &dict_value)) { PyObject *key; { key = PyUnicode_AsUTF8String (dict_key); if (key == NULL) { return FALSE; } } /* 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'", full_name, PyBytes_AsString (key)); Py_DECREF (key); g_free (full_name); return FALSE; } Py_DECREF (key); } return TRUE; } /** * _py_args_combine_and_check_length: * @cache: PyGICallableCache * @py_args: the tuple of positional arguments. * @py_kwargs: the dict of keyword arguments to be merged with py_args. * * Returns: New value reference to the combined py_args and py_kwargs. */ static PyObject * _py_args_combine_and_check_length (PyGICallableCache *cache, PyObject *py_args, PyObject *py_kwargs) { PyObject *combined_py_args = NULL; Py_ssize_t n_py_args, n_py_kwargs, i; gssize n_expected_args = cache->n_py_args; GSList *l; n_py_args = PyTuple_GET_SIZE (py_args); if (py_kwargs == NULL) n_py_kwargs = 0; else n_py_kwargs = PyDict_Size (py_kwargs); /* Fast path, we already have the exact number of args and not kwargs. */ 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 (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 %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 (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; } /* will hold arguments from both py_args and py_kwargs * when they are combined into a single tuple */ combined_py_args = PyTuple_New (n_expected_args); for (i = 0, l = cache->arg_name_list; i < n_expected_args && l; i++, l = l->next) { 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); } /* 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) { 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'", full_name, arg_name); Py_DECREF (combined_py_args); g_free (full_name); return NULL; } } return combined_py_args; } /* 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. */ #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]; /** * _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) { gpointer mem; 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 { mem = g_slice_alloc0 (PyGI_INVOKE_ARG_STATE_SIZE (state->n_args)); } if (mem == NULL && state->n_args != 0) { PyErr_NoMemory(); return FALSE; } if (mem != NULL) { state->args = mem; state->ffi_args = (gpointer)((gchar *)mem + state->n_args * sizeof (PyGIInvokeArgState)); } 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; } 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++; } /* 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); 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 void _invoke_state_clear (PyGIInvokeState *state, PyGIFunctionCache *function_cache) { _pygi_invoke_arg_state_free (state); Py_XDECREF (state->py_in_args); Py_XDECREF (state->py_async); } static gboolean _caller_alloc (PyGIArgCache *arg_cache, GIArgument *arg) { if (arg_cache->type_tag == GI_TYPE_TAG_INTERFACE) { PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache; arg->v_pointer = NULL; if (g_type_is_a (iface_cache->g_type, G_TYPE_BOXED)) { arg->v_pointer = pygi_boxed_alloc (iface_cache->interface_info, NULL); } else if (iface_cache->g_type == G_TYPE_VALUE) { 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, arg); } else { gssize size = g_struct_info_get_size( (GIStructInfo *)iface_cache->interface_info); arg->v_pointer = g_malloc0 (size); } } else if (arg_cache->type_tag == GI_TYPE_TAG_ARRAY) { PyGIArgGArray *array_cache = (PyGIArgGArray *)arg_cache; arg->v_pointer = g_array_new (TRUE, TRUE, (guint)array_cache->item_size); } else { return FALSE; } if (arg->v_pointer == NULL) return FALSE; return TRUE; } /* 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) { 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)", full_name, cache->n_py_args, state->n_py_in_args); g_free (full_name); return FALSE; } if (function_cache->async_finish && function_cache->async_callback && function_cache->async_callback->py_arg_index < state->n_py_in_args && PyTuple_GET_ITEM (state->py_in_args, function_cache->async_callback->py_arg_index) == _PyGIDefaultArgPlaceholder) { /* We are dealing with an async call that returns an awaitable */ PyObject *cancellable = NULL; /* Try to resolve any passed GCancellable. */ if (function_cache->async_cancellable && function_cache->async_cancellable->py_arg_index < state->n_py_in_args) cancellable = PyTuple_GET_ITEM (state->py_in_args, function_cache->async_cancellable->py_arg_index); if (cancellable == _PyGIDefaultArgPlaceholder) cancellable = NULL; state->py_async = pygi_async_new (function_cache->async_finish, cancellable); } 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; gboolean marshal = TRUE; switch (arg_cache->direction) { case PYGI_DIRECTION_FROM_PYTHON: /* 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->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)", 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); return FALSE; } py_arg = PyTuple_GET_ITEM (state->py_in_args, arg_cache->py_arg_index); break; case PYGI_DIRECTION_BIDIRECTIONAL: 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)", 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); return FALSE; } py_arg = 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) { /* 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, full_name); g_free (full_name); pygi_marshal_cleanup_args_from_py_parameter_fail (state, cache, i); return FALSE; } } else { /* Non-caller allocated out args will use arg_pointers as an * extra level of indirection */ state->ffi_args[i] = &state->args[i].arg_pointer; } break; default: g_assert_not_reached(); break; } if (py_arg == _PyGIDefaultArgPlaceholder) { /* If this is the cancellable, then we may override it later if we * detect an async call. */ marshal = FALSE; if (state->py_async && arg_cache->async_context == PYGI_ASYNC_CONTEXT_CANCELLABLE) { marshal = TRUE; py_arg = ((PyGIAsync*) state->py_async)->cancellable; } else if (state->py_async && arg_cache->async_context == PYGI_ASYNC_CONTEXT_CALLBACK) { marshal = TRUE; } else { *c_arg = arg_cache->default_value; } } if (marshal && 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", i); pygi_marshal_cleanup_args_from_py_parameter_fail (state, cache, i); return FALSE; } success = arg_cache->from_py_marshaller (state, 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); return FALSE; } } } return TRUE; } 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 n_out_args = cache->n_to_py_args - cache->n_to_py_child_args; if (cache->return_cache) { if (!cache->return_cache->is_skipped) { gpointer cleanup_data = NULL; py_return = cache->return_cache->to_py_marshaller ( state, cache, cache->return_cache, &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; } } else { if (cache->return_cache->transfer == GI_TRANSFER_EVERYTHING) { 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); } } } /* Return the async future if we have one. */ if (state->py_async) { /* We must have no return value */ g_assert (n_out_args == 0); g_assert (cache->return_cache->is_skipped || cache->return_cache->type_tag == GI_TYPE_TAG_VOID); Py_DECREF(py_return); Py_INCREF(state->py_async); return state->py_async; } 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, * otherwise Python will expect an exception. */ g_assert (py_return == NULL); Py_INCREF(Py_None); py_return = Py_None; } py_out = py_return; } 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].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, 0); return NULL; } } else { /* return a tuple */ gssize py_arg_index = 0; GSList *cache_item = cache->to_py_args; 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 < 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].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 (cache->has_return) py_arg_index--; pygi_marshal_cleanup_args_to_py_parameter_fail (state, cache, py_arg_index); Py_DECREF (py_out); return NULL; } PyTuple_SET_ITEM (py_out, py_arg_index, py_obj); cache_item = cache_item->next; } } return py_out; } PyObject * pygi_invoke_c_callable (PyGIFunctionCache *function_cache, PyGIInvokeState *state, PyObject *py_args, PyObject *py_kwargs) { PyGICallableCache *cache = (PyGICallableCache *) function_cache; GIFFIReturnValue ffi_return_value = {0}; PyObject *ret = NULL; if (!_invoke_state_init_from_cache (state, function_cache, py_args, py_kwargs)) goto err; if (!_invoke_marshal_in_args (state, function_cache)) goto err; Py_BEGIN_ALLOW_THREADS; ffi_call (&function_cache->invoker.cif, state->function_ptr, (void *) &ffi_return_value, (void **) state->ffi_args); 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); err: _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) { 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); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pygi-invoke.h0000664000000000000000000000330115074674453015354 0ustar00rootroot/* -*- Mode: C; c-basic-offset: 4 -*- * vim: tabstop=4 shiftwidth=4 expandtab * * Copyright (C) 2005-2009 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 . */ #ifndef __PYGI_INVOKE_H__ #define __PYGI_INVOKE_H__ #include #include #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, 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__ */ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pygi-list.c0000664000000000000000000004005615074674453015037 0ustar00rootroot/* -*- Mode: C; c-basic-offset: 4 -*- * vim: tabstop=4 shiftwidth=4 expandtab * * Copyright (C) 2011 John (J5) Palmieri * Copyright (C) 2014 Simon Feltman * * 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 . */ #include #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; } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pygi-list.h0000664000000000000000000000271415074674453015043 0ustar00rootroot/* -*- Mode: C; c-basic-offset: 4 -*- * vim: tabstop=4 shiftwidth=4 expandtab * * Copyright (C) 2014 Simon Feltman * * 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 . */ #ifndef __PYGI_LIST_H__ #define __PYGI_LIST_H__ #include #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__*/ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pygi-marshal-cleanup.c0000664000000000000000000002205715074674453017141 0ustar00rootroot/* -*- Mode: C; c-basic-offset: 4 -*- * vim: tabstop=4 shiftwidth=4 expandtab * * Copyright (C) 2011 John (J5) Palmieri , 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, see . */ #include "pygi-marshal-cleanup.h" #include "pygi-foreign.h" #include static inline void _cleanup_caller_allocates (PyGIInvokeState *state, PyGIArgCache *cache, PyObject *py_obj, gpointer data, gboolean was_processed) { PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)cache; /* 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->is_foreign) { if (was_processed) return; /* will be cleaned up at deallocation */ pygi_struct_foreign_release ((GIBaseInfo *)iface_cache->interface_info, data); } else { if (was_processed) return; /* will be cleaned up at deallocation */ g_free (data); } } /** * Cleanup during invoke can happen in multiple * stages, each of which can be the result of a * successful compleation of that stage or an error * occured which requires partial cleanup. * * For the most part, either the C interface being * invoked or the python object which wraps the * parameters, handle their lifecycles but in some * cases, where we have intermediate objects, * or when we fail processing a parameter, we need * to handle the clean up manually. * * There are two argument processing stages. * They are the in stage, where we process python * parameters into their C counterparts, and the out * stage, where we process out C parameters back * into python objects. The in stage also sets up * temporary out structures for caller allocated * parameters which need to be cleaned up either on * in stage failure or at the completion of the out * stage (either success or failure) * * The in stage must call one of these cleanup functions: * - pygi_marshal_cleanup_args_from_py_marshal_success * (continue to out stage) * - pygi_marshal_cleanup_args_from_py_parameter_fail * (final, exit from invoke) * * The out stage must call one of these cleanup functions which are all final: * - pygi_marshal_cleanup_args_to_py_marshal_success * - pygi_marshal_cleanup_args_return_fail * - pygi_marshal_cleanup_args_to_py_parameter_fail * **/ void pygi_marshal_cleanup_args_from_py_marshal_success (PyGIInvokeState *state, PyGICallableCache *cache) { 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); 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 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) { 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); } /* Now clean up args */ cache_item = cache->to_py_args; while (cache_item) { PyGIArgCache *arg_cache = (PyGIArgCache *) cache_item->data; 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 pygi_marshal_cleanup_args_from_py_parameter_fail (PyGIInvokeState *state, PyGICallableCache *cache, gssize failed_arg_index) { 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 < _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 cleanup_data = state->args[i].arg_cleanup_data; PyObject *py_arg = 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, py_arg, cleanup_data, i < (guint)failed_arg_index); } else if (arg_cache->is_caller_allocates && cleanup_data != NULL) { _cleanup_caller_allocates (state, arg_cache, py_arg, cleanup_data, FALSE); } state->args[i].arg_cleanup_data = NULL; } if (have_error) PyErr_Restore (error_type, error_value, error_traceback); } void pygi_marshal_cleanup_args_return_fail (PyGIInvokeState *state, PyGICallableCache *cache) { state->failed = TRUE; } void pygi_marshal_cleanup_args_to_py_parameter_fail (PyGIInvokeState *state, PyGICallableCache *cache, gssize failed_to_py_arg_index) { state->failed = TRUE; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pygi-marshal-cleanup.h0000664000000000000000000000377515074674453017154 0ustar00rootroot/* -*- Mode: C; c-basic-offset: 4 -*- * vim: tabstop=4 shiftwidth=4 expandtab * * Copyright (C) 2011 John (J5) Palmieri , 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, see . */ #ifndef __PYGI_MARSHAL_CLEANUP_H__ #define __PYGI_MARSHAL_CLEANUP_H__ #include "pygi-struct.h" #include "pygi-invoke-state-struct.h" #include "pygi-cache.h" G_BEGIN_DECLS void pygi_marshal_cleanup_args_from_py_marshal_success (PyGIInvokeState *state, PyGICallableCache *cache); void pygi_marshal_cleanup_args_from_py_parameter_fail (PyGIInvokeState *state, PyGICallableCache *cache, gssize failed_arg_index); void pygi_marshal_cleanup_args_to_py_marshal_success (PyGIInvokeState *state, PyGICallableCache *cache); void pygi_marshal_cleanup_args_return_fail (PyGIInvokeState *state, PyGICallableCache *cache); void pygi_marshal_cleanup_args_to_py_parameter_fail (PyGIInvokeState *state, PyGICallableCache *cache, gssize failed_to_py_arg_index); G_END_DECLS #endif /* __PYGI_MARSHAL_CLEANUP_H__ */ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pygi-object.c0000664000000000000000000003645115074674453015336 0ustar00rootroot/* -*- Mode: C; c-basic-offset: 4 -*- * vim: tabstop=4 shiftwidth=4 expandtab * * Copyright (C) 2011 John (J5) Palmieri * Copyright (C) 2014 Simon Feltman * * 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 . */ #include #include #include "pygi-object.h" #include "pygi-fundamental.h" #include "pygobject-object.h" /* * GObject from Python */ typedef gboolean (*PyGIObjectMarshalFromPyFunc) (PyObject *py_arg, GIArgument *arg, GITransfer transfer); /* _pygi_marshal_from_py_object: * py_arg: (in): * arg: (out): */ static gboolean _pygi_marshal_from_py_object (PyObject *py_arg, /*in*/ GIArgument *arg, /*out*/ GITransfer transfer) { GObject *gobj; if (py_arg == Py_None) { arg->v_pointer = NULL; return TRUE; } if (PyObject_TypeCheck(py_arg, &PyGIFundamental_Type)) { arg->v_pointer = pygi_fundamental_get (py_arg); if (transfer == GI_TRANSFER_EVERYTHING) { pygi_fundamental_ref ((PyGIFundamental *) py_arg); } 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_object (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_object); } 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 */ static PyObject * pygi_arg_object_to_py (GIArgument *arg, GITransfer transfer) { PyObject *pyobj; if (arg->v_pointer == NULL) { pyobj = Py_None; Py_INCREF (pyobj); } else if (G_IS_OBJECT(arg->v_pointer)) { pyobj = pygobject_new_full (arg->v_pointer, /*steal=*/ transfer == GI_TRANSFER_EVERYTHING, /*type=*/ NULL); } else { pyobj = pygi_fundamental_new (arg->v_pointer); if (pyobj && transfer == GI_TRANSFER_EVERYTHING) pygi_fundamental_unref ((PyGIFundamental *) pyobj); } return pyobj; } PyObject * pygi_arg_object_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_object_to_py (arg, GI_TRANSFER_EVERYTHING); g_object_force_floating (arg->v_pointer); } else { object = pygi_arg_object_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_object_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_object_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 (was_processed && state->failed && data != NULL && arg_cache->transfer == GI_TRANSFER_EVERYTHING) { if (G_IS_OBJECT (data)) { g_object_unref (G_OBJECT(data)); } else { PyGIInterfaceCache *iface_cache = (PyGIInterfaceCache *)arg_cache; GIObjectInfoUnrefFunction unref_func; unref_func = g_object_info_get_unref_function_pointer ( (GIObjectInfo *)iface_cache->interface_info); if (unref_func) unref_func (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; } } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pygi-object.h0000664000000000000000000000341215074674453015332 0ustar00rootroot/* -*- Mode: C; c-basic-offset: 4 -*- * vim: tabstop=4 shiftwidth=4 expandtab * * Copyright (C) 2014 Simon Feltman * * 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 . */ #ifndef __PYGI_OBJECT_H__ #define __PYGI_OBJECT_H__ #include #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_object_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__*/ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pygi-property.c0000664000000000000000000003247615074674453015757 0ustar00rootroot/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */ /* * Copyright (c) 2010 Collabora Ltd. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. */ #include "pygi-property.h" #include "pygi-value.h" #include "pygi-argument.h" #include "pygi-fundamental.h" #include "pygi-type.h" #include "pygi-fundamental.h" #include static GIPropertyInfo * lookup_property_from_object_info (GIObjectInfo *info, const gchar *attr_name) { gssize n_infos; gint i; n_infos = g_object_info_get_n_properties (info); for (i = 0; i < n_infos; i++) { GIPropertyInfo *property_info; property_info = g_object_info_get_property (info, i); g_assert (info != NULL); if (strcmp (attr_name, g_base_info_get_name (property_info)) == 0) { return property_info; } g_base_info_unref (property_info); } return NULL; } static GIPropertyInfo * lookup_property_from_interface_info (GIInterfaceInfo *info, const gchar *attr_name) { gssize n_infos; gint i; n_infos = g_interface_info_get_n_properties (info); for (i = 0; i < n_infos; i++) { GIPropertyInfo *property_info; property_info = g_interface_info_get_property (info, i); g_assert (info != NULL); if (strcmp (attr_name, g_base_info_get_name (property_info)) == 0) { return property_info; } g_base_info_unref (property_info); } return NULL; } static GIPropertyInfo * _pygi_lookup_property_from_g_type (GType g_type, const gchar *attr_name) { GIPropertyInfo *ret = NULL; GIRepository *repository; GIBaseInfo *info; repository = g_irepository_get_default(); info = g_irepository_find_by_gtype (repository, g_type); if (info == NULL) return NULL; if (GI_IS_OBJECT_INFO (info)) ret = lookup_property_from_object_info ((GIObjectInfo *) info, attr_name); else if (GI_IS_INTERFACE_INFO (info)) ret = lookup_property_from_interface_info ((GIInterfaceInfo *) info, attr_name); g_base_info_unref (info); return ret; } PyObject * pygi_call_do_get_property (PyObject *instance, GParamSpec *pspec) { PyObject *py_pspec; PyObject *retval; py_pspec = pygi_fundamental_new (pspec); retval = PyObject_CallMethod (instance, "do_get_property", "O", py_pspec); Py_DECREF (py_pspec); return retval; } PyObject * pygi_get_property_value (PyGObject *instance, GParamSpec *pspec) { GIPropertyInfo *property_info = NULL; GValue value = { 0, }; PyObject *py_value = NULL; GType fundamental; gboolean handled; if (!(pspec->flags & G_PARAM_READABLE)) { PyErr_Format(PyExc_TypeError, "property %s is not readable", g_param_spec_get_name (pspec)); return NULL; } /* 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; /* 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; } /* 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; } py_value = _pygi_argument_to_object (&arg, type_info, transfer); if (free_array) { g_array_free (arg.v_pointer, FALSE); } g_base_info_unref (type_info); g_base_info_unref (property_info); if (PyErr_Occurred()) { return NULL; } } /* Fallback to GValue marshalling. */ if (py_value == NULL) { py_value = pyg_param_gvalue_as_pyobject (&value, TRUE, pspec); } out: 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 (PyGObject *instance, GParamSpec *pspec, PyObject *py_value) { GIPropertyInfo *property_info = NULL; GITypeInfo *type_info = NULL; GITypeTag type_tag; GITransfer transfer; GValue value = { 0, }; GIArgument arg = { 0, }; gint ret_value = -1; /* 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 == NULL) goto out; if (! (pspec->flags & G_PARAM_WRITABLE)) goto out; type_info = g_property_info_get_type (property_info); transfer = g_property_info_get_ownership_transfer (property_info); arg = _pygi_argument_from_object (py_value, type_info, transfer); if (PyErr_Occurred()) goto out; g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec)); /* FIXME: Lots of types still unhandled */ type_tag = g_type_info_get_tag (type_info); switch (type_tag) { 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); g_base_info_unref (info); switch (info_type) { 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: if (arg.v_pointer == NULL || G_IS_OBJECT (arg.v_pointer)) { g_value_set_object (&value, arg.v_pointer); } else if (!pygi_fundamental_set_value (&value, arg.v_pointer)) { PyErr_Format (PyExc_NotImplementedError, "Setting properties of type '%s' is not implemented", g_type_name (type)); goto out; } break; case GI_INFO_TYPE_BOXED: case GI_INFO_TYPE_STRUCT: case GI_INFO_TYPE_UNION: if (g_type_is_a (type, G_TYPE_BOXED)) { g_value_set_boxed (&value, arg.v_pointer); } else if (g_type_is_a (type, G_TYPE_VARIANT)) { g_value_set_variant (&value, arg.v_pointer); } else { PyErr_Format (PyExc_NotImplementedError, "Setting properties of type '%s' is not implemented", g_type_name (type)); goto out; } break; default: PyErr_Format (PyExc_NotImplementedError, "Setting properties of type '%s' is not implemented", g_type_name (type)); goto out; } break; } case GI_TYPE_TAG_BOOLEAN: g_value_set_boolean (&value, arg.v_boolean); break; case GI_TYPE_TAG_INT8: g_value_set_schar (&value, arg.v_int8); break; case GI_TYPE_TAG_INT16: case GI_TYPE_TAG_INT32: if (G_VALUE_HOLDS_LONG (&value)) g_value_set_long (&value, arg.v_long); else g_value_set_int (&value, arg.v_int); break; case GI_TYPE_TAG_INT64: if (G_VALUE_HOLDS_LONG (&value)) g_value_set_long (&value, arg.v_long); else g_value_set_int64 (&value, arg.v_int64); break; case GI_TYPE_TAG_UINT8: g_value_set_uchar (&value, arg.v_uint8); break; case GI_TYPE_TAG_UINT16: case GI_TYPE_TAG_UINT32: if (G_VALUE_HOLDS_ULONG (&value)) g_value_set_ulong (&value, arg.v_ulong); else g_value_set_uint (&value, arg.v_uint); break; case GI_TYPE_TAG_UINT64: if (G_VALUE_HOLDS_ULONG (&value)) g_value_set_ulong (&value, arg.v_ulong); else g_value_set_uint64 (&value, arg.v_uint64); break; case GI_TYPE_TAG_FLOAT: g_value_set_float (&value, arg.v_float); break; case GI_TYPE_TAG_DOUBLE: g_value_set_double (&value, arg.v_double); break; case GI_TYPE_TAG_GTYPE: g_value_set_gtype (&value, arg.v_size); break; case GI_TYPE_TAG_UTF8: case GI_TYPE_TAG_FILENAME: g_value_set_string (&value, arg.v_string); break; case GI_TYPE_TAG_GHASH: g_value_set_boxed (&value, arg.v_pointer); break; case GI_TYPE_TAG_GLIST: if (G_VALUE_HOLDS_BOXED(&value)) g_value_set_boxed (&value, arg.v_pointer); else g_value_set_pointer (&value, arg.v_pointer); break; case GI_TYPE_TAG_ARRAY: { /* This is assumes GI_TYPE_TAG_ARRAY is always a GStrv * https://bugzilla.gnome.org/show_bug.cgi?id=688232 */ GArray *arg_items = (GArray*) arg.v_pointer; gchar** strings; guint i; if (arg_items == NULL) goto out; strings = g_new0 (char*, arg_items->len + 1); for (i = 0; i < arg_items->len; ++i) { strings[i] = g_array_index (arg_items, GIArgument, i).v_string; } strings[arg_items->len] = NULL; g_value_take_boxed (&value, strings); g_array_free (arg_items, TRUE); break; } default: PyErr_Format (PyExc_NotImplementedError, "Setting properties of type %s is not implemented", g_type_tag_to_string (g_type_info_get_tag (type_info))); goto out; } g_object_set_property (instance->obj, pspec->name, &value); g_value_unset (&value); ret_value = 0; out: if (property_info != NULL) g_base_info_unref (property_info); if (type_info != NULL) g_base_info_unref (type_info); return ret_value; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pygi-property.h0000664000000000000000000000350715074674453015755 0ustar00rootroot/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */ /* * Copyright (c) 2010 Collabora Ltd. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. */ #ifndef __PYGI_PROPERTY_H__ #define __PYGI_PROPERTY_H__ #include #include #include "pygobject-internal.h" PyObject * pygi_get_property_value (PyGObject *instance, GParamSpec *pspec); 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__ */ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pygi-repository.c0000664000000000000000000003071615074674453016305 0ustar00rootroot/* -*- Mode: C; c-basic-offset: 4 -*- * vim: tabstop=4 shiftwidth=4 expandtab * * Copyright (C) 2005-2009 Johan Dahlin * * pygi-repository.c: GIRepository wrapper. * * 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 . */ #include "pygi-repository.h" #include "pygi-info.h" #include "pygi-basictype.h" #include "pygi-util.h" PyObject *PyGIRepositoryError; PYGI_DEFINE_TYPE("gi.Repository", PyGIRepository_Type, PyGIRepository); static PyObject * _wrap_g_irepository_enumerate_versions (PyGIRepository *self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "namespace", NULL }; const char *namespace_; GList *versions, *item; PyObject *ret = NULL; if (!PyArg_ParseTupleAndKeywords (args, kwargs, "s:Repository.enumerate_versions", kwlist, &namespace_)) { return NULL; } versions = g_irepository_enumerate_versions (self->repository, namespace_); ret = PyList_New(0); for (item = versions; item; item = item->next) { char *version = item->data; PyObject *py_version = pygi_utf8_to_py (version); PyList_Append(ret, py_version); Py_DECREF(py_version); g_free (version); } g_list_free(versions); return ret; } static PyObject * _wrap_g_irepository_get_default (PyObject *self) { static PyGIRepository *repository = NULL; if (!repository) { repository = (PyGIRepository *) PyObject_New (PyGIRepository, &PyGIRepository_Type); if (repository == NULL) { return NULL; } repository->repository = g_irepository_get_default(); } Py_INCREF ( (PyObject *) repository); return (PyObject *) repository; } static PyObject * _wrap_g_irepository_require (PyGIRepository *self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "namespace", "version", "lazy", NULL }; const char *namespace_; const char *version = NULL; PyObject *lazy = NULL; GIRepositoryLoadFlags flags = 0; GError *error; if (!PyArg_ParseTupleAndKeywords (args, kwargs, "s|zO:Repository.require", kwlist, &namespace_, &version, &lazy)) { return NULL; } if (lazy != NULL && PyObject_IsTrue (lazy)) { flags |= G_IREPOSITORY_LOAD_FLAG_LAZY; } error = NULL; g_irepository_require (self->repository, namespace_, version, flags, &error); if (error != NULL) { PyErr_SetString (PyGIRepositoryError, error->message); g_error_free (error); return NULL; } Py_RETURN_NONE; } 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) { static char *kwlist[] = { "namespace", "name", NULL }; const char *namespace_; const char *name; GIBaseInfo *info; PyObject *py_info; size_t len; char *trimmed_name = NULL; if (!PyArg_ParseTupleAndKeywords (args, kwargs, "ss:Repository.find_by_name", kwlist, &namespace_, &name)) { return NULL; } /* If the given name ends with an underscore, it might be due to usage * as an accessible replacement for something in GI with the same name * as a Python keyword. Test for this and trim it out if necessary. */ len = strlen (name); if (len > 0 && name[len-1] == '_') { trimmed_name = g_strndup (name, len-1); if (_pygi_is_python_keyword (trimmed_name)) { name = trimmed_name; } } info = g_irepository_find_by_name (self->repository, namespace_, name); g_free (trimmed_name); if (info == NULL) { Py_RETURN_NONE; } py_info = _pygi_info_new (info); g_base_info_unref (info); return py_info; } static PyObject * _wrap_g_irepository_get_infos (PyGIRepository *self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "namespace", NULL }; const char *namespace_; gssize n_infos; PyObject *infos; gint i; if (!PyArg_ParseTupleAndKeywords (args, kwargs, "s:Repository.get_infos", kwlist, &namespace_)) { return NULL; } n_infos = g_irepository_get_n_infos (self->repository, namespace_); if (n_infos < 0) { PyErr_Format (PyExc_RuntimeError, "Namespace '%s' not loaded", namespace_); return NULL; } infos = PyTuple_New (n_infos); for (i = 0; i < n_infos; i++) { GIBaseInfo *info; PyObject *py_info; info = g_irepository_get_info (self->repository, namespace_, i); g_assert (info != NULL); py_info = _pygi_info_new (info); g_base_info_unref (info); if (py_info == NULL) { Py_CLEAR (infos); break; } PyTuple_SET_ITEM (infos, i, py_info); } return infos; } static PyObject * _wrap_g_irepository_get_typelib_path (PyGIRepository *self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "namespace", NULL }; const char *namespace_; const gchar *typelib_path; if (!PyArg_ParseTupleAndKeywords (args, kwargs, "s:Repository.get_typelib_path", kwlist, &namespace_)) { return NULL; } typelib_path = g_irepository_get_typelib_path (self->repository, namespace_); if (typelib_path == NULL) { PyErr_Format (PyExc_RuntimeError, "Namespace '%s' not loaded", namespace_); return NULL; } return pygi_filename_to_py (typelib_path); } static PyObject * _wrap_g_irepository_get_version (PyGIRepository *self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "namespace", NULL }; const char *namespace_; const gchar *version; if (!PyArg_ParseTupleAndKeywords (args, kwargs, "s:Repository.get_version", kwlist, &namespace_)) { return NULL; } version = g_irepository_get_version (self->repository, namespace_); if (version == NULL) { PyErr_Format (PyExc_RuntimeError, "Namespace '%s' not loaded", namespace_); return NULL; } return pygi_utf8_to_py (version); } static PyObject * _wrap_g_irepository_get_loaded_namespaces (PyGIRepository *self) { char **namespaces; PyObject *py_namespaces; gssize i; namespaces = g_irepository_get_loaded_namespaces (self->repository); py_namespaces = PyList_New (0); 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_free (namespaces[i]); } g_free (namespaces); 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 }, { "require", (PyCFunction) _wrap_g_irepository_require, METH_VARARGS | METH_KEYWORDS }, { "get_infos", (PyCFunction) _wrap_g_irepository_get_infos, METH_VARARGS | METH_KEYWORDS }, { "find_by_name", (PyCFunction) _wrap_g_irepository_find_by_name, METH_VARARGS | METH_KEYWORDS }, { "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 } }; /** * Returns 0 on success, or -1 and sets an exception. */ int pygi_repository_register_types (PyObject *m) { 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) < 0) return -1; 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 (PyGIRepositoryError == NULL) return -1; Py_INCREF (PyGIRepositoryError); if (PyModule_AddObject (m, "RepositoryError", PyGIRepositoryError) < 0) { Py_DECREF (PyGIRepositoryError); return -1; } return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pygi-repository.h0000664000000000000000000000230215074674453016300 0ustar00rootroot/* -*- Mode: C; c-basic-offset: 4 -*- * vim: tabstop=4 shiftwidth=4 expandtab * * Copyright (C) 2005-2009 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 . */ #ifndef __PYGI_REPOSITORY_H__ #define __PYGI_REPOSITORY_H__ #include #include G_BEGIN_DECLS typedef struct { PyObject_HEAD GIRepository *repository; } PyGIRepository; /* Private */ extern PyTypeObject PyGIRepository_Type; extern PyObject *PyGIRepositoryError; int pygi_repository_register_types (PyObject *m); G_END_DECLS #endif /* __PYGI_REPOSITORY_H__ */ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pygi-resulttuple.c0000664000000000000000000002631115074674453016452 0ustar00rootroot/* -*- Mode: C; c-basic-offset: 4 -*- * vim: tabstop=4 shiftwidth=4 expandtab * * Copyright (C) 2015 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 . */ #include #include #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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pygi-resulttuple.h0000664000000000000000000000221515074674453016454 0ustar00rootroot/* -*- Mode: C; c-basic-offset: 4 -*- * vim: tabstop=4 shiftwidth=4 expandtab * * Copyright (C) 2015 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 . */ #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); PyObject* pygi_resulttuple_new (PyTypeObject *subclass, Py_ssize_t len); #endif /* __PYGI_RESULTTUPLE_H__ */ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pygi-signal-closure.c0000664000000000000000000002445415074674453017017 0ustar00rootroot/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */ /* * Copyright (c) 2011 Laszlo Pandy * * 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 . */ #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, const gchar *signal_name) { GIRepository *repository; GIBaseInfo *info; GISignalInfo *signal_info = NULL; repository = g_irepository_get_default(); info = g_irepository_find_by_gtype (repository, g_type); if (info == NULL) return NULL; if (GI_IS_OBJECT_INFO (info)) signal_info = g_object_info_find_signal ((GIObjectInfo *) info, signal_name); else if (GI_IS_INTERFACE_INFO (info)) signal_info = g_interface_info_find_signal ((GIInterfaceInfo *) info, signal_name); g_base_info_unref (info); return signal_info; } static void pygi_signal_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; g_base_info_unref (((PyGISignalClosure *) pc)->signal_info); ((PyGISignalClosure *) pc)->signal_info = NULL; } static void pygi_signal_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 = NULL; guint i; 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; g_assert_cmpint(sig_info_highest_arg, ==, n_param_values); /* 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 if (i == 0) { PyObject *item = pyg_value_as_pyobject(¶m_values[i], FALSE); if (!item) { goto out; } PyTuple_SetItem(params, i, item); } else if (i < (guint)sig_info_highest_arg) { GIArgInfo arg_info; GITypeInfo type_info; 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); arg = _pygi_argument_from_g_value(¶m_values[i], &type_info); 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, _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); } 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); } } /* 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) { 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); /* 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 (PyGObject *instance, GType g_type, const gchar *signal_name, PyObject *callback, PyObject *extra_args, PyObject *swap_data) { GClosure *closure = NULL; PyGISignalClosure *pygi_closure = NULL; GISignalInfo *signal_info = NULL; g_return_val_if_fail(callback != NULL, NULL); signal_info = _pygi_lookup_signal_from_g_type (g_type, signal_name); if (signal_info == NULL) return NULL; closure = g_closure_new_simple(sizeof(PyGISignalClosure), NULL); g_closure_add_invalidate_notifier(closure, NULL, pygi_signal_closure_invalidate); g_closure_set_marshal(closure, pygi_signal_closure_marshal); pygi_closure = (PyGISignalClosure *)closure; pygi_closure->signal_info = signal_info; Py_INCREF(callback); pygi_closure->pyg_closure.callback = callback; if (extra_args != NULL && 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; } pygi_closure->pyg_closure.extra_args = extra_args; } if (swap_data) { Py_INCREF(swap_data); pygi_closure->pyg_closure.swap_data = swap_data; closure->derivative_flag = TRUE; } return closure; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pygi-signal-closure.h0000664000000000000000000000345515074674453017022 0ustar00rootroot/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */ /* * Copyright (c) 2011 Laszlo Pandy * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. */ #ifndef __PYGI_SIGNAL_CLOSURE_H__ #define __PYGI_SIGNAL_CLOSURE_H__ #include #include #include "pygobject-internal.h" G_BEGIN_DECLS /* Private */ typedef struct _PyGISignalClosure { PyGClosure pyg_closure; GISignalInfo *signal_info; } PyGISignalClosure; 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 #endif /* __PYGI_SIGNAL_CLOSURE_H__ */ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pygi-source.c0000664000000000000000000001474015074674453015365 0ustar00rootroot/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */ /* * Copyright (C) 1998-2003 James Henstridge * Copyright (C) 2005 Oracle * Copyright (c) 2012 Canonical Ltd. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. */ #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 { GSource source; PyObject *obj; } PyGRealSource; static gboolean source_prepare(GSource *source, gint *timeout) { PyGRealSource *pysource = (PyGRealSource *)source; PyObject *t; gboolean ret = FALSE; gboolean got_err = TRUE; PyGILState_STATE state; state = PyGILState_Ensure(); t = PyObject_CallMethod(pysource->obj, "prepare", NULL); if (t == NULL) { goto bail; } else if (!PyObject_IsTrue(t)) { got_err = FALSE; goto bail; } else if (!PyTuple_Check(t)) { PyErr_SetString(PyExc_TypeError, "source prepare function must return a tuple or False"); goto bail; } else if (PyTuple_Size(t) != 2) { PyErr_SetString(PyExc_TypeError, "source prepare function return tuple must be exactly " "2 elements long"); goto bail; } if (!pygi_gboolean_from_py (PyTuple_GET_ITEM(t, 0), &ret)) { ret = FALSE; goto bail; } if (!pygi_gint_from_py (PyTuple_GET_ITEM(t, 1), timeout)) { ret = FALSE; goto bail; } got_err = FALSE; bail: if (got_err) PyErr_Print(); Py_XDECREF(t); PyGILState_Release(state); return ret; } static gboolean source_check(GSource *source) { PyGRealSource *pysource = (PyGRealSource *)source; PyObject *t; gboolean ret; PyGILState_STATE state; state = PyGILState_Ensure(); t = PyObject_CallMethod(pysource->obj, "check", NULL); if (t == NULL) { PyErr_Print(); ret = FALSE; } else { ret = PyObject_IsTrue(t); Py_DECREF(t); } PyGILState_Release(state); return ret; } static gboolean source_dispatch(GSource *source, GSourceFunc callback, gpointer user_data) { PyGRealSource *pysource = (PyGRealSource *)source; PyObject *func, *args, *tuple, *t; gboolean ret; PyGILState_STATE state; state = PyGILState_Ensure(); if (callback) { tuple = user_data; func = PyTuple_GetItem(tuple, 0); args = PyTuple_GetItem(tuple, 1); } else { func = Py_None; args = Py_None; } t = PyObject_CallMethod(pysource->obj, "dispatch", "OO", func, args); if (t == NULL) { PyErr_Print(); ret = FALSE; } else { ret = PyObject_IsTrue(t); Py_DECREF(t); } PyGILState_Release(state); return ret; } static GSourceFuncs pyg_source_funcs = { source_prepare, source_check, source_dispatch, NULL }; /** * _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 * pygi_source_set_callback (PyGObject *self_module, PyObject *args) { PyObject *self, *first, *callback, *cbargs = NULL, *data; Py_ssize_t len; len = PyTuple_Size (args); if (len < 2) { PyErr_SetString(PyExc_TypeError, "set_callback requires at least 2 arguments"); return NULL; } first = PySequence_GetSlice(args, 0, 2); if (!PyArg_ParseTuple(first, "OO:set_callback", &self, &callback)) { Py_DECREF (first); return NULL; } Py_DECREF(first); if (!pyg_boxed_check (self, G_TYPE_SOURCE)) { PyErr_SetString(PyExc_TypeError, "first argument is not a GLib.Source"); return NULL; } if (!PyCallable_Check(callback)) { PyErr_SetString(PyExc_TypeError, "second argument not callable"); return NULL; } cbargs = PySequence_GetSlice(args, 2, len); if (cbargs == NULL) return NULL; data = Py_BuildValue("(ON)", callback, cbargs); if (data == NULL) return NULL; g_source_set_callback(pyg_boxed_get (self, GSource), handler_marshal, data, destroy_notify); Py_INCREF(Py_None); return Py_None; } /** * 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* pygi_source_new (PyObject *self, PyObject *args) { PyGRealSource *source; PyObject *py_type, *boxed; g_assert (args == NULL); py_type = pygi_type_import_by_name ("GLib", "Source"); if (!py_type) return NULL; source = (PyGRealSource*) g_source_new (&pyg_source_funcs, sizeof (PyGRealSource)); /* g_source_new uses malloc, not slices */ 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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pygi-source.h0000664000000000000000000000257115074674453015371 0ustar00rootroot/* -*- mode: C; c-basic-offset: 4; indent-tabs-mode: nil; -*- */ /* * Copyright (c) 2012 Canonical Ltd. * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to * deal in the Software without restriction, including without limitation the * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or * sell copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS * IN THE SOFTWARE. */ #ifndef __PYGI_SOURCE_H__ #define __PYGI_SOURCE_H__ PyObject *pygi_source_new (PyObject *self, PyObject *args); PyObject *pygi_source_set_callback (PyGObject *self, PyObject *args); #endif /* __PYGI_SOURCE_H__ */ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pygi-struct-marshal.c0000664000000000000000000005633215074674453017041 0ustar00rootroot/* -*- Mode: C; c-basic-offset: 4 -*- * vim: tabstop=4 shiftwidth=4 expandtab * * Copyright (C) 2011 John (J5) Palmieri * Copyright (C) 2014 Simon Feltman * * 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 . */ #include #include #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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pygi-struct-marshal.h0000664000000000000000000000653515074674453017046 0ustar00rootroot/* -*- Mode: C; c-basic-offset: 4 -*- * vim: tabstop=4 shiftwidth=4 expandtab * * Copyright (C) 2011 John (J5) Palmieri * Copyright (C) 2014 Simon Feltman * * 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 . */ #ifndef __PYGI_STRUCT_MARSHAL_H__ #define __PYGI_STRUCT_MARSHAL_H__ #include #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__*/ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pygi-struct.c0000664000000000000000000001542115074674453015406 0ustar00rootroot/* -*- Mode: C; c-basic-offset: 4 -*- * vim: tabstop=4 shiftwidth=4 expandtab * * Copyright (C) 2009 Simon van der Linden * * pygi-struct.c: wrapper to handle non-registered structures. * * 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 . */ #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 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) { 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, pyg_pointer_get_ptr (self)); } else if (self->free_on_dealloc) { g_free (pyg_pointer_get_ptr (self)); } if (info != NULL) { g_base_info_unref (info); } if (have_error) PyErr_Restore (error_type, error_value, error_traceback); Py_TYPE (self)->tp_free ((PyObject *)self); } static PyObject * struct_new (PyTypeObject *type, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { NULL }; GIBaseInfo *info; gsize size; gpointer pointer; PyObject *self = NULL; if (!PyArg_ParseTupleAndKeywords (args, kwargs, "", kwlist)) { return NULL; } info = struct_get_info ( type ); if (info == NULL) { if (PyErr_ExceptionMatches (PyExc_AttributeError)) { PyErr_Format (PyExc_TypeError, "missing introspection information"); } return NULL; } size = g_struct_info_get_size ( (GIStructInfo *) info); if (size == 0) { PyErr_Format (PyExc_TypeError, "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; } pointer = g_try_malloc0 (size); if (pointer == NULL) { PyErr_NoMemory(); goto out; } self = pygi_struct_new (type, pointer, TRUE); if (self == NULL) { g_free (pointer); } out: g_base_info_unref (info); return (PyObject *) self; } static int struct_init (PyObject *self, PyObject *args, PyObject *kwargs) { /* Don't call PyGPointer's init, which raises an exception. */ return 0; } PYGI_DEFINE_TYPE("gi.Struct", PyGIStruct_Type, PyGIStruct); PyObject * 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; 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; } g_type = pyg_type_from_object ( (PyObject *) type); pyg_pointer_set_ptr (self, pointer); ( (PyGPointer *) self)->gtype = g_type; self->free_on_dealloc = free_on_dealloc; return (PyObject *) self; } 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_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_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; } return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pygi-struct.h0000664000000000000000000000267215074674453015417 0ustar00rootroot/* -*- Mode: C; c-basic-offset: 4 -*- * vim: tabstop=4 shiftwidth=4 expandtab * * Copyright (C) 2009 Simon van der Linden * * 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 . */ #ifndef __PYGI_STRUCT_H__ #define __PYGI_STRUCT_H__ #include #include 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); PyObject * pygi_struct_new_from_g_type (GType g_type, gpointer pointer, gboolean free_on_dealloc); int pygi_struct_register_types (PyObject *m); G_END_DECLS #endif /* __PYGI_STRUCT_H__ */ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pygi-type.c0000664000000000000000000011114715074674453015045 0ustar00rootroot/* -*- 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 . */ #include #include "pygobject-object.h" #include "pygboxed.h" #include "pygenum.h" #include "pygflags.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) { gchar *module_name; PyObject *py_module; PyObject *py_object; module_name = g_strconcat ("gi.repository.", namespace_, NULL); py_module = PyImport_ImportModule (module_name); g_free (module_name); if (py_module == NULL) { return NULL; } py_object = PyObject_GetAttrString (py_module, name); Py_DECREF (py_module); return py_object; } PyObject * pygi_type_import_by_g_type (GType g_type) { GIRepository *repository; GIBaseInfo *info; PyObject *type; repository = g_irepository_get_default(); info = g_irepository_find_by_gtype (repository, g_type); if (info == NULL) { return NULL; } type = pygi_type_import_by_gi_info (info); g_base_info_unref (info); return type; } PyObject * 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)); } PyObject * pygi_type_get_from_g_type (GType g_type) { PyObject *py_g_type; PyObject *py_type; py_g_type = pyg_type_wrapper_new (g_type); if (py_g_type == NULL) { return NULL; } py_type = PyObject_GetAttrString (py_g_type, "pytype"); if (py_type == Py_None) { py_type = pygi_type_import_by_g_type (g_type); } Py_DECREF (py_g_type); return py_type; } /* -------------- __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), "", 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. * * Returns: the Python wrapper. */ PyObject * 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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pygi-type.h0000664000000000000000000000455715074674453015060 0ustar00rootroot/* -*- 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, see . */ #ifndef __PYGI_TYPE_H__ #define __PYGI_TYPE_H__ #include #include #include #include "pygobject-internal.h" extern PyTypeObject PyGTypeWrapper_Type; typedef PyObject *(* fromvaluefunc)(const GValue *value); typedef int (*tovaluefunc)(GValue *value, PyObject *obj); typedef struct { fromvaluefunc fromvalue; tovaluefunc tovalue; } PyGTypeMarshal; PyGTypeMarshal *pyg_type_lookup(GType type); gboolean pyg_gtype_is_custom (GType gtype); void pyg_register_gtype_custom(GType gtype, fromvaluefunc from_func, tovaluefunc to_func); int pygi_type_register_types(PyObject *d); 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); int pyg_pyobj_to_unichar_conv (PyObject* py_obj, void* ptr); 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); 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__ */ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pygi-util.c0000664000000000000000000000710415074674453015036 0ustar00rootroot/* -*- 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 . */ #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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pygi-util.h0000664000000000000000000000354715074674453015052 0ustar00rootroot#ifndef __PYGI_UTIL_H__ #define __PYGI_UTIL_H__ #include #include 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__ */ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pygi-value.c0000664000000000000000000007441715074674453015210 0ustar00rootroot /* -*- 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 . */ #include #include "pygi-value.h" #include "pygi-struct.h" #include "pygi-basictype.h" #include "pygi-fundamental.h" #include "pygobject-object.h" #include "pygi-type.h" #include "pygi-fundamental.h" #include "pygenum.h" #include "pygpointer.h" #include "pygboxed.h" #include "pygflags.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 if (G_VALUE_HOLDS_OBJECT (value)) arg.v_pointer = g_value_get_object (value); else arg.v_pointer = pygi_fundamental_from_value (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_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 { GIRepository *repository; GIBaseInfo *info; GIObjectInfoSetValueFunction set_value_func = NULL; if (!PyObject_TypeCheck (obj, &PyGIFundamental_Type)) { PyErr_SetString (PyExc_TypeError, "Fundamental type is required"); return -1; } if (!G_TYPE_CHECK_INSTANCE_TYPE (pygi_fundamental_get (obj), value_type)) { PyErr_SetString (PyExc_TypeError, "Invalid fundamental type for assignment"); return -1; } repository = g_irepository_get_default(); info = g_irepository_find_by_gtype (repository, value_type); if (info && GI_IS_OBJECT_INFO (info)) { set_value_func = g_object_info_get_set_value_function_pointer ((GIObjectInfo *) info); if (set_value_func) { set_value_func (value, pygi_fundamental_get (obj)); } else { PyErr_SetString (PyExc_TypeError, "No set-value function for fundamental type"); } } else { PyErr_SetString (PyExc_TypeError, "Unknown value type"); } if (info) g_base_info_unref (info); } 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_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); } case G_TYPE_INVALID: PyErr_SetString (PyExc_TypeError, "Invalid type"); return NULL; default: { PyGTypeMarshal *bm; GIRepository *repository; GIBaseInfo *info; GIObjectInfoGetValueFunction get_value_func = NULL; if ((bm = pyg_type_lookup(G_VALUE_TYPE(value)))) return bm->fromvalue(value); repository = g_irepository_get_default (); info = g_irepository_find_by_gtype (repository, fundamental); if (info == NULL) break; if (GI_IS_OBJECT_INFO (info)) get_value_func = g_object_info_get_get_value_function_pointer ((GIObjectInfo *) info); g_base_info_unref (info); if (get_value_func) return pygi_fundamental_new (get_value_func (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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pygi-value.h0000664000000000000000000000414415074674453015203 0ustar00rootroot/* -*- 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 . */ #ifndef __PYGI_VALUE_H__ #define __PYGI_VALUE_H__ #include #include #include 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__ */ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pyginterface.c0000664000000000000000000001012715074674453015572 0ustar00rootroot/* -*- 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, see . */ #include #include #include #include "pygi-util.h" #include "pyginterface.h" #include "pygi-type.h" GQuark pyginterface_type_key; GQuark pyginterface_info_key; PYGI_DEFINE_TYPE("gobject.GInterface", PyGInterface_Type, PyObject) static int pyg_interface_init(PyObject *self, PyObject *args, PyObject *kwargs) { gchar buf[512]; if (!PyArg_ParseTuple(args, ":GInterface.__init__")) return -1; g_snprintf(buf, sizeof(buf), "%s can not be constructed", Py_TYPE(self)->tp_name); PyErr_SetString(PyExc_NotImplementedError, buf); return -1; } static void pyg_interface_free(PyObject *op) { PyObject_FREE(op); } /** * pyg_register_interface: * @dict: a module dictionary. * @class_name: the class name for the wrapper class. * @gtype: the GType of the interface. * @type: the wrapper class for the interface. * * Registers a Python class as the wrapper for a GInterface. As a * convenience it will also place a reference to the wrapper class in * the provided module dictionary. */ void pyg_register_interface(PyObject *dict, const gchar *class_name, GType gtype, PyTypeObject *type) { PyObject *o; Py_SET_TYPE(type, &PyType_Type); g_assert (Py_TYPE (&PyGInterface_Type) != NULL); type->tp_base = &PyGInterface_Type; if (PyType_Ready(type) < 0) { g_warning("could not ready `%s'", type->tp_name); return; } if (gtype) { o = pyg_type_wrapper_new(gtype); PyDict_SetItemString(type->tp_dict, "__gtype__", o); Py_DECREF(o); } 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) { 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 * pyg_lookup_interface_info(GType gtype) { return g_type_get_qdata(gtype, pyginterface_info_key); } /** * Returns 0 on success, or -1 and sets an exception. */ int pygi_interface_register_types(PyObject *d) { 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); PyDict_SetItemString(PyGInterface_Type.tp_dict, "__doc__", pyg_object_descr_doc_get()); PyDict_SetItemString(PyGInterface_Type.tp_dict, "__gdoc__", pyg_object_descr_doc_get()); PyDict_SetItemString(d, "GInterface", (PyObject *)&PyGInterface_Type); return 0; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pyginterface.h0000664000000000000000000000264115074674453015601 0ustar00rootroot/* -*- 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, see . */ #ifndef __PYGOBJECT_INTERFACE_H__ #define __PYGOBJECT_INTERFACE_H__ extern GQuark pyginterface_type_key; extern GQuark pyginterface_info_key; extern PyTypeObject PyGInterface_Type; void pyg_register_interface(PyObject *dict, const gchar *class_name, GType gtype, PyTypeObject *type); const GInterfaceInfo * pyg_lookup_interface_info(GType gtype); void pyg_register_interface_info(GType gtype, const GInterfaceInfo *info); int pygi_interface_register_types(PyObject *d); #endif /* __PYGOBJECT_INTERFACE_H__ */ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pygobject-internal.h0000664000000000000000000000022415074674453016714 0ustar00rootroot#ifndef _PYGOBJECT_INTERNAL_H_ #define _PYGOBJECT_INTERNAL_H_ #define _INSIDE_PYGOBJECT_ #include "pygobject.h" #endif /*_PYGOBJECT_INTERNAL_H_*/ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pygobject-object.c0000664000000000000000000022403315074674453016347 0ustar00rootroot/* -*- Mode: C; c-basic-offset: 4 -*- * pygtk- Python bindings for the GTK toolkit. * Copyright (C) 1998-2003 James Henstridge * * pygobject.c: wrapper for the GObject type. * * 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 . */ #include #include "pygobject-object.h" #include "pyginterface.h" #include "pygi-type.h" #include "pygboxed.h" #include "gimodule.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" #include "pygi-fundamental.h" extern PyObject *PyGIDeprecationWarning; static void pygobject_dealloc(PyGObject *self); static int pygobject_traverse(PyGObject *self, visitproc visit, void *arg); 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 void pygobject_inherit_slots(PyTypeObject *type, PyObject *bases, gboolean check_for_present); static void pygobject_find_slot_for(PyTypeObject *type, PyObject *bases, int slot_offset, gboolean check_for_present); GType PY_TYPE_OBJECT = 0; GQuark pygobject_custom_key; GQuark pygobject_class_key; GQuark pygobject_class_init_key; GQuark pygobject_wrapper_key; GQuark pygobject_has_updated_constructor_key; GQuark pygobject_instance_data_key; /* 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. */ static void canonicalize_key (gchar *key) { gchar *p; for (p = key; *p != 0; p++) { gchar c = *p; if (c != '-' && (c < '0' || c > '9') && (c < 'A' || c > 'Z') && (c < 'a' || c > 'z')) *p = '-'; } } /* -------------- class <-> wrapper manipulation --------------- */ 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 = 0; PyThreadState *_save = NULL; gboolean state_saved; GSList *closures, *tmp; 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. */ Py_UNBLOCK_THREADS; /* Modifies _save */ } tmp = closures = data->closures; #ifndef NDEBUG data->closures = NULL; data->type = NULL; #endif while (tmp) { GClosure *closure = tmp->data; /* we get next item first, because the current link gets * invalidated by pygobject_unwatch_closure */ tmp = tmp->next; g_closure_invalidate(closure); } if (data->closures != NULL) g_warning("invalidated all closures, but data->closures != NULL !"); g_free(data); if (state_saved && Py_IsInitialized ()) { Py_BLOCK_THREADS; /* Restores _save */ PyGILState_Release(state); } } static inline PyGObjectData * pygobject_data_new(void) { PyGObjectData *data; data = g_new0(PyGObjectData, 1); return data; } static inline PyGObjectData * pygobject_get_inst_data(PyGObject *self) { PyGObjectData *inst_data; if (G_UNLIKELY(!self->obj)) return NULL; inst_data = g_object_get_qdata(self->obj, pygobject_instance_data_key); if (inst_data == NULL) { inst_data = pygobject_data_new(); inst_data->type = Py_TYPE(self); Py_INCREF((PyObject *) inst_data->type); g_object_set_qdata_full(self->obj, pygobject_instance_data_key, inst_data, (GDestroyNotify) pygobject_data_free); } return inst_data; } PyTypeObject *PyGObject_MetaType = NULL; /** * pygobject_sink: * @obj: a GObject * * As Python handles reference counting for us, the "floating * reference" code in GTK is not all that useful. In fact, it can * cause leaks. This function should be called to remove the floating * references on objects on construction. **/ void pygobject_sink(GObject *obj) { /* The default behaviour for GInitiallyUnowned subclasses is to call ref_sink(). * - if the object is new and owned by someone else, its ref has been sunk and * we need to keep the one from that someone and add our own "fresh ref" * - if the object is not and owned by nobody, its ref is floating and we need * to transform it into a regular ref. */ if (G_IS_INITIALLY_UNOWNED(obj)) { g_object_ref_sink(obj); } } typedef struct { PyObject_HEAD GParamSpec **props; guint n_props; guint index; } PyGPropsIter; PYGI_DEFINE_TYPE("gi._gi.GPropsIter", PyGPropsIter_Type, PyGPropsIter); static void pyg_props_iter_dealloc(PyGPropsIter *self) { g_free(self->props); PyObject_Del((PyObject*) self); } static PyObject* pygobject_props_iter_next(PyGPropsIter *iter) { if (iter->index < iter->n_props) return pygi_fundamental_new(iter->props[iter->index++]); else { PyErr_SetNone(PyExc_StopIteration); return NULL; } } typedef struct { PyObject_HEAD /* a reference to the object containing the properties */ PyGObject *pygobject; GType gtype; } PyGProps; static void PyGProps_dealloc(PyGProps* self) { PyGObject *tmp; PyObject_GC_UnTrack((PyObject*)self); tmp = self->pygobject; self->pygobject = NULL; Py_XDECREF(tmp); PyObject_GC_Del((PyObject*)self); } static PyObject* build_parameter_list(GObjectClass *class) { GParamSpec **props; guint n_props = 0, i; PyObject *prop_str; PyObject *props_list; props = g_object_class_list_properties(class, &n_props); props_list = PyList_New(n_props); for (i = 0; i < n_props; i++) { char *name; name = g_strdup(g_param_spec_get_name(props[i])); /* hyphens cannot belong in identifiers */ g_strdelimit(name, "-", '_'); prop_str = PyUnicode_FromString (name); PyList_SetItem(props_list, i, prop_str); g_free(name); } if (props) g_free(props); return props_list; } static PyObject* PyGProps_getattro(PyGProps *self, PyObject *attr) { char *attr_name, *property_name; GObjectClass *class; GParamSpec *pspec; attr_name = PyUnicode_AsUTF8 (attr); if (!attr_name) { PyErr_Clear(); return PyObject_GenericGetAttr((PyObject *)self, attr); } class = g_type_class_ref(self->gtype); /* g_object_class_find_property recurses through the class hierarchy, * so the resulting pspec tells us the owner_type that owns the property * we're dealing with. */ property_name = g_strdup(attr_name); canonicalize_key(property_name); pspec = g_object_class_find_property(class, property_name); g_free(property_name); g_type_class_unref(class); if (!pspec) { return PyObject_GenericGetAttr((PyObject *)self, attr); } if (!self->pygobject) { /* If we're doing it without an instance, return a GParamSpec */ return pygi_fundamental_new(pspec); } return pygi_get_property_value (self->pygobject, pspec); } static gboolean set_property_from_pspec(GObject *obj, GParamSpec *pspec, PyObject *pvalue) { GValue value = { 0, }; if (pspec->flags & G_PARAM_CONSTRUCT_ONLY) { PyErr_Format(PyExc_TypeError, "property '%s' can only be set in constructor", pspec->name); return FALSE; } if (!(pspec->flags & G_PARAM_WRITABLE)) { PyErr_Format(PyExc_TypeError, "property '%s' is not writable", pspec->name); return FALSE; } g_value_init(&value, G_PARAM_SPEC_VALUE_TYPE(pspec)); if (pyg_param_gvalue_from_pyobject(&value, pvalue, pspec) < 0) { PyObject *pvalue_str = PyObject_Repr(pvalue); PyErr_Format(PyExc_TypeError, "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); Py_DECREF(pvalue_str); return FALSE; } Py_BEGIN_ALLOW_THREADS; g_object_set_property(obj, pspec->name, &value); g_value_unset(&value); Py_END_ALLOW_THREADS; return TRUE; } PYGI_DEFINE_TYPE("gi._gi.GProps", PyGProps_Type, PyGProps); static int PyGProps_setattro(PyGProps *self, PyObject *attr, PyObject *pvalue) { GParamSpec *pspec; char *attr_name, *property_name; GObject *obj; int ret = -1; if (pvalue == NULL) { PyErr_SetString(PyExc_TypeError, "properties cannot be " "deleted"); return -1; } attr_name = PyUnicode_AsUTF8 (attr); if (!attr_name) { PyErr_Clear(); return PyObject_GenericSetAttr((PyObject *)self, attr, pvalue); } if (!self->pygobject) { PyErr_SetString(PyExc_TypeError, "cannot set GOject properties without an instance"); return -1; } obj = self->pygobject->obj; property_name = g_strdup(attr_name); canonicalize_key(property_name); /* g_object_class_find_property recurses through the class hierarchy, * so the resulting pspec tells us the owner_type that owns the property * we're dealing with. */ pspec = g_object_class_find_property(G_OBJECT_GET_CLASS(obj), property_name); g_free(property_name); if (!pspec) { return PyObject_GenericSetAttr((PyObject *)self, attr, pvalue); } if (!pyg_gtype_is_custom (pspec->owner_type)) { /* This GType is not implemented in Python: see if we can set the * property via gi. */ ret = pygi_set_property_value (self->pygobject, pspec, pvalue); if (ret == 0) return 0; else if (ret == -1 && PyErr_Occurred()) return -1; } /* This GType is implemented in Python, or we failed to set it via gi: * do a straightforward set. */ if (!set_property_from_pspec(obj, pspec, pvalue)) return -1; return 0; } static int pygobject_props_traverse(PyGProps *self, visitproc visit, void *arg) { if (self->pygobject && visit((PyObject *) self->pygobject, arg) < 0) return -1; return 0; } static PyObject* pygobject_props_get_iter(PyGProps *self) { PyGPropsIter *iter; GObjectClass *class; iter = PyObject_NEW(PyGPropsIter, &PyGPropsIter_Type); class = g_type_class_ref(self->gtype); iter->props = g_object_class_list_properties(class, &iter->n_props); iter->index = 0; g_type_class_unref(class); 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) { GObjectClass *class; GParamSpec **props; guint n_props; class = g_type_class_ref(self->gtype); props = g_object_class_list_properties(class, &n_props); g_type_class_unref(class); g_free(props); return (Py_ssize_t)n_props; } static PySequenceMethods _PyGProps_as_sequence = { (lenfunc) PyGProps_length, 0, 0, 0, 0, 0, 0 }; PYGI_DEFINE_TYPE("gi._gi.GPropsDescr", PyGPropsDescr_Type, PyObject); static PyObject * pyg_props_descr_descr_get(PyObject *self, PyObject *obj, PyObject *type) { PyGProps *gprops; gprops = PyObject_GC_New(PyGProps, &PyGProps_Type); if (obj == NULL || obj == Py_None) { gprops->pygobject = NULL; gprops->gtype = pyg_type_from_object(type); } else { if (!PyObject_IsInstance(obj, (PyObject *) &PyGObject_Type)) { PyErr_SetString(PyExc_TypeError, "cannot use GObject property" " descriptor on non-GObject instances"); return NULL; } Py_INCREF(obj); gprops->pygobject = (PyGObject *) obj; gprops->gtype = pyg_type_from_object(obj); } return (PyObject *) gprops; } /** * pygobject_register_class: * @dict: the module dictionary. A reference to the type will be stored here. * @type_name: not used ? * @gtype: the GType of the GObject subclass. * @type: the Python type object for this wrapper. * @static_bases: a tuple of Python type objects that are the bases of * this type * * This function is used to register a Python type as the wrapper for * a particular GObject subclass. It will also insert a reference to * the wrapper class into the module dictionary passed as a reference, * which simplifies initialisation. */ void pygobject_register_class(PyObject *dict, const gchar *type_name, GType gtype, PyTypeObject *type, PyObject *static_bases) { PyObject *o; const char *class_name, *s; PyObject *runtime_bases; PyObject *bases_list, *bases, *mod_name; int i; class_name = type->tp_name; s = strrchr(class_name, '.'); if (s != NULL) class_name = s + 1; runtime_bases = pyg_type_get_bases(gtype); if (static_bases) { PyTypeObject *py_parent_type = (PyTypeObject *) PyTuple_GET_ITEM(static_bases, 0); bases_list = PySequence_List(static_bases); /* we start at index 1 because we want to skip the primary * base, otherwise we might get MRO conflict */ for (i = 1; i < PyTuple_GET_SIZE(runtime_bases); ++i) { PyObject *base = PyTuple_GET_ITEM(runtime_bases, i); int contains = PySequence_Contains(bases_list, base); if (contains < 0) PyErr_Print(); else if (!contains) { if (!PySequence_Contains(py_parent_type->tp_mro, base)) { #if 0 g_message("Adding missing base %s to type %s", ((PyTypeObject *)base)->tp_name, type->tp_name); #endif PyList_Append(bases_list, base); } } } bases = PySequence_Tuple(bases_list); Py_DECREF(bases_list); Py_DECREF(runtime_bases); } else bases = runtime_bases; Py_SET_TYPE(type, PyGObject_MetaType); type->tp_bases = bases; if (G_LIKELY(bases)) { type->tp_base = (PyTypeObject *)PyTuple_GetItem(bases, 0); Py_INCREF(type->tp_base); } pygobject_inherit_slots(type, bases, TRUE); if (PyType_Ready(type) < 0) { g_warning ("couldn't make the type `%s' ready", type->tp_name); return; } /* Set type.__module__ to the name of the module, * otherwise it'll default to 'gobject', see #376099 */ s = strrchr(type->tp_name, '.'); if (s != NULL) { mod_name = PyUnicode_FromStringAndSize (type->tp_name, (int)(s - type->tp_name)); PyDict_SetItemString(type->tp_dict, "__module__", mod_name); Py_DECREF(mod_name); } if (gtype) { o = pyg_type_wrapper_new(gtype); PyDict_SetItemString(type->tp_dict, "__gtype__", o); Py_DECREF(o); /* stash a pointer to the python class with the GType */ Py_INCREF(type); g_type_set_qdata(gtype, pygobject_class_key, type); } /* set up __doc__ descriptor on type */ PyDict_SetItemString(type->tp_dict, "__doc__", pyg_object_descr_doc_get()); PyDict_SetItemString(dict, (char *)class_name, (PyObject *)type); } static void pyg_toggle_notify (gpointer data, GObject *object, gboolean is_last_ref) { PyGObject *self; PyGILState_STATE state; state = PyGILState_Ensure(); /* 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); } 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 reference counting strategy to start using toggle ref to keep the wrapper alive while the GObject lives. In contrast, while inst_dict was NULL the python wrapper is allowed to die at will and is recreated on demand. */ static inline void pygobject_toggle_ref_ensure (PyGObject *self) { if (pygobject_toggle_ref_is_active (self)) return; 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, NULL); g_object_unref(self->obj); } /* Called when an custom gobject is initalized via g_object_new instead of its constructor. The next time the wrapper is access via pygobject_new_full it will sink the floating reference instead of adding a new reference and causing a leak */ void pygobject_ref_float(PyGObject *self) { /* should only be floated once */ g_assert(!(self->private_flags.flags & PYGOBJECT_IS_FLOATING_REF)); self->private_flags.flags |= PYGOBJECT_IS_FLOATING_REF; } /* Called by gobject_new_full, if the floating flag is set remove it, otherwise ref the pyobject */ void pygobject_ref_sink(PyGObject *self) { if (self->private_flags.flags & PYGOBJECT_IS_FLOATING_REF) self->private_flags.flags &= ~PYGOBJECT_IS_FLOATING_REF; else Py_INCREF ( (PyObject *) self); } /** * pygobject_register_wrapper: * @self: the wrapper instance * * In the constructor of PyGTK wrappers, this function should be * called after setting the obj member. It will tie the wrapper * instance to the GObject so that the same wrapper instance will * always be used for this GObject instance. */ void pygobject_register_wrapper(PyObject *self) { PyGObject *gself; g_return_if_fail(self != NULL); g_return_if_fail(PyObject_TypeCheck(self, &PyGObject_Type)); gself = (PyGObject *)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); pygobject_toggle_ref_ensure (gself); } static PyObject * pyg_type_get_bases(GType gtype) { GType *interfaces, parent_type, interface_type; guint n_interfaces; PyTypeObject *py_parent_type, *py_interface_type; PyObject *bases; guint i; if (G_UNLIKELY(gtype == G_TYPE_OBJECT)) return NULL; /* Lookup the parent type */ parent_type = g_type_parent(gtype); py_parent_type = pygobject_lookup_class(parent_type); interfaces = g_type_interfaces(gtype, &n_interfaces); bases = PyTuple_New(n_interfaces + 1); /* We will always put the parent at the first position in bases */ Py_INCREF(py_parent_type); /* PyTuple_SetItem steals a reference */ PyTuple_SetItem(bases, 0, (PyObject *) py_parent_type); /* And traverse interfaces */ if (n_interfaces) { for (i = 0; i < n_interfaces; i++) { interface_type = interfaces[i]; py_interface_type = pygobject_lookup_class(interface_type); Py_INCREF(py_interface_type); /* PyTuple_SetItem steals a reference */ PyTuple_SetItem(bases, i + 1, (PyObject *) py_interface_type); } } g_free(interfaces); return bases; } /** * pygobject_new_with_interfaces * @gtype: the GType of the GObject subclass. * * Creates a new PyTypeObject from the given GType with interfaces attached in * bases. * * Returns: a PyTypeObject for the new type or NULL if it couldn't be created */ static PyTypeObject * pygobject_new_with_interfaces(GType gtype) { PyGILState_STATE state; PyObject *o; PyTypeObject *type; PyObject *dict; PyTypeObject *py_parent_type; PyObject *bases; state = PyGILState_Ensure(); bases = pyg_type_get_bases(gtype); py_parent_type = (PyTypeObject *) PyTuple_GetItem(bases, 0); dict = PyDict_New(); o = pyg_type_wrapper_new(gtype); PyDict_SetItemString(dict, "__gtype__", o); Py_DECREF(o); /* set up __doc__ descriptor on type */ PyDict_SetItemString(dict, "__doc__", pyg_object_descr_doc_get()); /* 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", g_type_name (gtype), bases, dict); if (type == NULL) { PyErr_Print(); PyGILState_Release(state); return NULL; } /* Workaround python tp_(get|set)attr slot inheritance bug. * Fixes bug #144135. */ if (!type->tp_getattr && py_parent_type->tp_getattr) { type->tp_getattro = NULL; type->tp_getattr = py_parent_type->tp_getattr; } if (!type->tp_setattr && py_parent_type->tp_setattr) { type->tp_setattro = NULL; type->tp_setattr = py_parent_type->tp_setattr; } /* override more python stupid hacks behind our back */ type->tp_dealloc = py_parent_type->tp_dealloc; type->tp_alloc = py_parent_type->tp_alloc; type->tp_free = py_parent_type->tp_free; type->tp_traverse = py_parent_type->tp_traverse; type->tp_clear = py_parent_type->tp_clear; pygobject_inherit_slots(type, bases, FALSE); if (PyType_Ready(type) < 0) { g_warning ("couldn't make the type `%s' ready", type->tp_name); PyGILState_Release(state); return NULL; } /* stash a pointer to the python class with the GType */ Py_INCREF(type); g_type_set_qdata(gtype, pygobject_class_key, type); PyGILState_Release(state); return type; } /* Pick appropriate value for given slot (at slot_offset inside * PyTypeObject structure). It must be a pointer, e.g. a pointer to a * function. We use the following heuristic: * * - Scan all types listed as bases of the type. * - If for exactly one base type slot value is non-NULL and * different from that of 'object' and 'GObject', set current type * slot into that value. * - Otherwise (if there is more than one such base type or none at * all) don't touch it and live with Python default. * * The intention here is to propagate slot from custom wrappers to * wrappers created at runtime when appropriate. We prefer to be on * the safe side, so if there is potential collision (more than one * custom slot value), we discard custom overrides altogether. * * When registering type with pygobject_register_class(), i.e. a type * that has been manually created (likely with Codegen help), * `check_for_present' should be set to TRUE. In this case, the * function will never overwrite any non-NULL slots already present in * the type. If `check_for_present' is FALSE, such non-NULL slots are * though to be set by Python interpreter and so will be overwritten * if heuristic above says so. */ static void pygobject_inherit_slots(PyTypeObject *type, PyObject *bases, gboolean check_for_present) { static int slot_offsets[] = { offsetof(PyTypeObject, tp_richcompare), offsetof(PyTypeObject, tp_richcompare), offsetof(PyTypeObject, tp_hash), offsetof(PyTypeObject, tp_iter), offsetof(PyTypeObject, tp_repr), offsetof(PyTypeObject, tp_str), }; gsize i; /* Happens when registering gobject.GObject itself, at least. */ if (!bases) return; for (i = 0; i < G_N_ELEMENTS(slot_offsets); ++i) pygobject_find_slot_for(type, bases, slot_offsets[i], check_for_present); } static void pygobject_find_slot_for(PyTypeObject *type, PyObject *bases, int slot_offset, gboolean check_for_present) { #define TYPE_SLOT(type) (* (void **) (void *) (((char *) (type)) + slot_offset)) void *found_slot = NULL; 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 * in this type already and there actually is. Don't * overwrite it. */ return; } for (i = 0; i < num_bases; ++i) { PyTypeObject *base_type = (PyTypeObject *) PyTuple_GetItem(bases, i); void *slot = TYPE_SLOT(base_type); if (slot == NULL) continue; if (slot == TYPE_SLOT(&PyGObject_Type) || slot == TYPE_SLOT(&PyBaseObject_Type)) continue; if (found_slot != NULL && found_slot != slot) { /* We have a conflict: more than one base use different * custom slots. To be on the safe side, we bail out. */ return; } found_slot = slot; } /* Only perform the final assignment if at least one base has a * custom value. Otherwise just leave this type's slot untouched. */ if (found_slot != NULL) TYPE_SLOT(type) = found_slot; #undef TYPE_SLOT } /** * pygobject_lookup_class: * @gtype: the GType of the GObject subclass. * * This function looks up the wrapper class used to represent * instances of a GObject represented by @gtype. If no wrapper class * 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 */ PyTypeObject * pygobject_lookup_class(GType gtype) { PyTypeObject *py_type; if (gtype == G_TYPE_INTERFACE) 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); 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); PyErr_Clear (); g_type_set_qdata(gtype, pyginterface_type_key, py_type); } } return py_type; } /** * pygobject_new_full: * @obj: a GObject instance. * @steal: whether to steal a ref from the GObject or add (sink) a new one. * @g_class: the GObjectClass * * This function gets a reference to a wrapper for the given GObject * instance. If a wrapper has already been created, a new reference * to that wrapper will be returned. Otherwise, a wrapper instance * will be created. * * Returns: a reference to the wrapper for the GObject. */ PyObject * pygobject_new_full(GObject *obj, gboolean steal, gpointer g_class) { PyGObject *self; if (obj == NULL) { Py_RETURN_NONE; } /* If the GObject already has a PyObject wrapper stashed in its qdata, re-use it. */ self = (PyGObject *)g_object_get_qdata(obj, pygobject_wrapper_key); if (self != NULL) { /* Note the use of "pygobject_ref_sink" here only deals with PyObject * wrapper ref counts and has nothing to do with GObject. */ pygobject_ref_sink(self); /* If steal is true, we also want to decref the incoming GObjects which * already have a Python wrapper because the wrapper is already holding a * strong reference. */ if (steal) g_object_unref (obj); } else { /* create wrapper */ PyGObjectData *inst_data = pyg_object_peek_inst_data(obj); PyTypeObject *tp; if (inst_data) tp = inst_data->type; else { if (g_class) tp = pygobject_lookup_class(G_OBJECT_CLASS_TYPE(g_class)); else tp = pygobject_lookup_class(G_OBJECT_TYPE(obj)); } g_assert(tp != NULL); /* need to bump type refcount if created with pygobject_new_with_interfaces(). fixes bug #141042 */ if (tp->tp_flags & Py_TPFLAGS_HEAPTYPE) Py_INCREF(tp); self = PyObject_GC_New(PyGObject, tp); if (self == NULL) return NULL; self->inst_dict = NULL; self->weakreflist = NULL; self->private_flags.flags = 0; self->obj = obj; /* If we are not stealing a ref or the object is floating, * add a regular ref or sink the object. */ if (g_object_is_floating (obj)) self->private_flags.flags |= PYGOBJECT_GOBJECT_WAS_FLOATING; if (!steal || self->private_flags.flags & PYGOBJECT_GOBJECT_WAS_FLOATING) g_object_ref_sink (obj); pygobject_register_wrapper((PyObject *)self); PyObject_GC_Track((PyObject *)self); } return (PyObject *)self; } PyObject * pygobject_new(GObject *obj) { return pygobject_new_full(obj, /*steal=*/FALSE, NULL); } static void 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); } /** * pygobject_watch_closure: * @self: a GObject wrapper instance * @closure: a GClosure to watch * * Adds a closure to the list of watched closures for the wrapper. * The closure must be one returned by pyg_closure_new(). When the * cycle GC traverses the wrapper instance, it will enumerate the * references to Python objects stored in watched closures. If the * cycle GC tells the wrapper to clear itself, the watched closures * will be invalidated. */ void pygobject_watch_closure(PyObject *self, GClosure *closure) { PyGObject *gself; PyGObjectData *data; g_return_if_fail(self != NULL); g_return_if_fail(PyObject_TypeCheck(self, &PyGObject_Type)); g_return_if_fail(closure != NULL); 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); } /* -------------- PyGObject behaviour ----------------- */ PYGI_DEFINE_TYPE("gi._gi.GObject", PyGObject_Type, PyGObject); static void pygobject_dealloc(PyGObject *self) { /* Untrack must be done first. This is because followup calls such as * ClearWeakRefs could call into Python and cause new allocations to * happen, which could in turn could trigger the garbage collector, * which would then get confused as it is tracking this half-deallocated * object. */ PyObject_GC_UnTrack((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 */ pygobject_get_inst_data(self); pygobject_clear(self); /* the following causes problems with subclassed types */ /* Py_TYPE(self)->tp_free((PyObject *)self); */ PyObject_GC_Del(self); } static PyObject* pygobject_richcompare(PyObject *self, PyObject *other, int op) { int isinst; isinst = PyObject_IsInstance(self, (PyObject*)&PyGObject_Type); if (isinst == -1) return NULL; if (!isinst) { Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } isinst = PyObject_IsInstance(other, (PyObject*)&PyGObject_Type); if (isinst == -1) return NULL; if (!isinst) { Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } return pyg_ptr_richcompare(((PyGObject*)self)->obj, ((PyGObject*)other)->obj, op); } static Py_hash_t pygobject_hash(PyGObject *self) { return (Py_hash_t)(gintptr)(self->obj); } static PyObject * pygobject_repr(PyGObject *self) { PyObject *module, *repr; gchar *module_str, *namespace; 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; } static int pygobject_traverse(PyGObject *self, visitproc visit, void *arg) { int ret = 0; GSList *tmp; PyGObjectData *data = pygobject_get_inst_data(self); if (self->inst_dict) ret = visit(self->inst_dict, arg); if (ret != 0) return ret; /* 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; if (closure->callback) ret = visit(closure->callback, arg); if (ret != 0) return ret; if (closure->extra_args) ret = visit(closure->extra_args, arg); if (ret != 0) return ret; if (closure->swap_data) ret = visit(closure->swap_data, arg); if (ret != 0) return ret; } } return ret; } static inline int pygobject_clear(PyGObject *self) { if (self->obj) { g_object_set_qdata_full(self->obj, pygobject_wrapper_key, NULL, NULL); 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; g_object_unref(self->obj); Py_END_ALLOW_THREADS; } self->obj = NULL; } Py_CLEAR(self->inst_dict); return 0; } static void pygobject_free(PyObject *op) { PyObject_GC_Del(op); } static gboolean pygobject_prepare_construct_properties(GObjectClass *class, PyObject *kwargs, guint *n_properties, const char **names[], const GValue **values) { *n_properties = 0; *names = NULL; *values = NULL; if (kwargs) { Py_ssize_t pos = 0; PyObject *key; PyObject *value; Py_ssize_t len; len = PyDict_Size(kwargs); *names = g_new(const char*, len); *values = g_new0(GValue, len); while (PyDict_Next(kwargs, &pos, &key, &value)) { GParamSpec *pspec; GValue *gvalue = &(*values)[*n_properties]; const gchar *key_str = PyUnicode_AsUTF8 (key); pspec = g_object_class_find_property(class, key_str); if (!pspec) { PyErr_Format(PyExc_TypeError, "gobject `%s' doesn't support property `%s'", G_OBJECT_CLASS_NAME(class), key_str); return FALSE; } 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; } (*names)[*n_properties] = g_strdup(key_str); ++(*n_properties); } } return TRUE; } /* ---------------- PyGObject methods ----------------- */ static int pygobject_init(PyGObject *self, PyObject *args, PyObject *kwargs) { GType object_type; guint n_properties = 0, i; const GValue *values = NULL; const char **names = NULL; GObjectClass *class; /* 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); if (!object_type) return -1; if (G_TYPE_IS_ABSTRACT(object_type)) { PyErr_Format(PyExc_TypeError, "cannot create instance of abstract " "(non-instantiable) type `%s'", g_type_name(object_type)); return -1; } if ((class = g_type_class_ref (object_type)) == NULL) { PyErr_SetString(PyExc_TypeError, "could not get a reference to type class"); return -1; } if (!pygobject_prepare_construct_properties (class, kwargs, &n_properties, &names, &values)) goto cleanup; if (pygobject_constructv(self, n_properties, names, values)) 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); return (self->obj) ? 0 : -1; } #define CHECK_GOBJECT(self) \ if (!G_IS_OBJECT(self->obj)) { \ PyErr_Format(PyExc_TypeError, \ "object at %p of type %s is not initialized", \ self, Py_TYPE(self)->tp_name); \ return NULL; \ } static PyObject * pygobject_get_property (PyGObject *self, PyObject *args) { gchar *param_name; if (!PyArg_ParseTuple (args, "s:GObject.get_property", ¶m_name)) { return NULL; } CHECK_GOBJECT(self); return pygi_get_property_value_by_name (self, param_name); } static PyObject * pygobject_get_properties(PyGObject *self, PyObject *args) { Py_ssize_t len, i; PyObject *tuple; if ((len = PyTuple_Size(args)) < 1) { PyErr_SetString(PyExc_TypeError, "requires at least one argument"); return NULL; } tuple = PyTuple_New(len); for (i = 0; i < len; i++) { PyObject *py_property = PyTuple_GetItem(args, i); gchar *property_name; PyObject *item; if (!PyUnicode_Check (py_property)) { PyErr_SetString(PyExc_TypeError, "Expected string argument for property."); goto fail; } 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 * pygobject_set_property(PyGObject *self, PyObject *args) { gchar *param_name; GParamSpec *pspec; PyObject *pvalue; int ret = -1; if (!PyArg_ParseTuple(args, "sO:GObject.set_property", ¶m_name, &pvalue)) 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; } ret = pygi_set_property_value (self, pspec, pvalue); if (ret == 0) goto done; else if (PyErr_Occurred()) return NULL; if (!set_property_from_pspec(self->obj, pspec, pvalue)) return NULL; done: Py_INCREF(Py_None); return Py_None; } static PyObject * pygobject_set_properties(PyGObject *self, PyObject *args, PyObject *kwargs) { GObjectClass *class; Py_ssize_t pos; PyObject *value; PyObject *key; PyObject *result = NULL; CHECK_GOBJECT(self); class = G_OBJECT_GET_CLASS(self->obj); g_object_freeze_notify (G_OBJECT(self->obj)); pos = 0; while (kwargs && PyDict_Next (kwargs, &pos, &key, &value)) { gchar *key_str = PyUnicode_AsUTF8 (key); GParamSpec *pspec; int ret = -1; pspec = g_object_class_find_property(class, key_str); if (!pspec) { gchar buf[512]; g_snprintf(buf, sizeof(buf), "object `%s' doesn't support property `%s'", g_type_name(G_OBJECT_TYPE(self->obj)), key_str); PyErr_SetString(PyExc_TypeError, buf); goto exit; } ret = pygi_set_property_value (self, pspec, value); if (ret != 0) { /* Non-zero return code means that either an error occured ...*/ if (PyErr_Occurred()) goto exit; /* ... or the property couldn't be found , so let's try the default * call. */ if (!set_property_from_pspec(G_OBJECT(self->obj), pspec, value)) goto exit; } } result = Py_None; exit: g_object_thaw_notify (G_OBJECT(self->obj)); Py_XINCREF(result); return result; } /* custom closure for gobject bindings */ static void pygbinding_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); PyGILState_Release(state); pc->callback = NULL; pc->extra_args = NULL; } static void pygbinding_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; GValue *out_value; state = PyGILState_Ensure(); /* construct Python tuple for the parameter values */ params = PyTuple_New(2); PyTuple_SetItem (params, 0, pyg_value_as_pyobject(¶m_values[0], FALSE)); PyTuple_SetItem (params, 1, pyg_value_as_pyobject(¶m_values[1], FALSE)); /* params passed to function may have extra arguments */ if (pc->extra_args) { PyObject *tuple = params; params = PySequence_Concat(tuple, pc->extra_args); Py_DECREF(tuple); } ret = PyObject_CallObject(pc->callback, params); if (!ret) { PyErr_Print (); goto out; } else if (ret == Py_None) { g_value_set_boolean (return_value, FALSE); goto out; } out_value = g_value_get_boxed (¶m_values[2]); if (pyg_value_from_pyobject (out_value, ret) != 0) { PyErr_SetString (PyExc_ValueError, "can't convert value"); PyErr_Print (); g_value_set_boolean (return_value, FALSE); } else { g_value_set_boolean (return_value, TRUE); } Py_DECREF(ret); out: Py_DECREF(params); PyGILState_Release(state); } static GClosure * pygbinding_closure_new (PyObject *callback, PyObject *extra_args) { GClosure *closure; g_return_val_if_fail(callback != NULL, NULL); closure = g_closure_new_simple(sizeof(PyGClosure), NULL); g_closure_add_invalidate_notifier(closure, NULL, pygbinding_closure_invalidate); g_closure_set_marshal(closure, pygbinding_marshal); Py_INCREF(callback); ((PyGClosure *)closure)->callback = callback; if (extra_args && extra_args != Py_None) { Py_INCREF(extra_args); if (!PyTuple_Check(extra_args)) { PyObject *tmp = PyTuple_New(1); PyTuple_SetItem(tmp, 0, extra_args); extra_args = tmp; } ((PyGClosure *)closure)->extra_args = extra_args; } return closure; } static PyObject * pygobject_bind_property(PyGObject *self, PyObject *args, PyObject *kwargs) { gchar *source_name, *target_name; gchar *source_canon, *target_canon; PyObject *target, *source_repr, *target_repr; PyObject *transform_to, *transform_from, *user_data = NULL; GBinding *binding; GBindingFlags flags = G_BINDING_DEFAULT; GClosure *to_closure = NULL, *from_closure = NULL; transform_from = NULL; transform_to = NULL; static char *kwlist[] = { "source_property", "target", "target_property", "flags", "transform_to", "transform_from", "user_data", NULL }; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sOs|iOOO:GObject.bind_property", kwlist, &source_name, &target, &target_name, &flags, &transform_to, &transform_from, &user_data)) return NULL; CHECK_GOBJECT(self); if (!PyObject_TypeCheck(target, &PyGObject_Type)) { PyErr_SetString(PyExc_TypeError, "Second argument must be a GObject"); return NULL; } if (transform_to && transform_to != Py_None) { if (!PyCallable_Check (transform_to)) { PyErr_SetString (PyExc_TypeError, "transform_to must be callable or None"); return NULL; } to_closure = pygbinding_closure_new (transform_to, user_data); } if (transform_from && transform_from != Py_None) { if (!PyCallable_Check (transform_from)) { PyErr_SetString (PyExc_TypeError, "transform_from must be callable or None"); return NULL; } from_closure = pygbinding_closure_new (transform_from, user_data); } /* Canonicalize underscores to hyphens. Note the results must be freed. */ source_canon = g_strdelimit(g_strdup(source_name), "_", '-'); target_canon = g_strdelimit(g_strdup(target_name), "_", '-'); binding = g_object_bind_property_with_closures (G_OBJECT(self->obj), source_canon, pygobject_get(target), target_canon, flags, to_closure, from_closure); g_free(source_canon); g_free(target_canon); source_canon = target_canon = NULL; if (binding == NULL) { source_repr = PyObject_Repr((PyObject*)self); target_repr = PyObject_Repr(target); PyErr_Format(PyExc_TypeError, "Cannot create binding from %s.%s to %s.%s", PyUnicode_AsUTF8 (source_repr), source_name, PyUnicode_AsUTF8 (target_repr), target_name); Py_DECREF(source_repr); Py_DECREF(target_repr); return NULL; } return pygobject_new (G_OBJECT (binding)); } static PyObject * connect_helper(PyGObject *self, gchar *name, PyObject *callback, PyObject *extra_args, PyObject *object, gboolean after) { guint sigid; GQuark detail = 0; GClosure *closure = NULL; gulong handlerid; GSignalQuery query_info; if (!g_signal_parse_name(name, G_OBJECT_TYPE(self->obj), &sigid, &detail, TRUE)) { PyObject *repr = PyObject_Repr((PyObject*)self); PyErr_Format(PyExc_TypeError, "%s: unknown signal name: %s", 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 * something in the gi repository. */ closure = pygi_signal_closure_new (self, query_info.itype, query_info.signal_name, callback, extra_args, object); } if (!closure) { /* The signal is either implemented at the Python level, or it comes * from a foreign class that we don't have introspection data for. */ closure = pyg_closure_new (callback, extra_args, object); } pygobject_watch_closure((PyObject *)self, closure); handlerid = g_signal_connect_closure_by_id(self->obj, sigid, detail, closure, after); return pygi_gulong_to_py (handlerid); } static PyObject * pygobject_connect(PyGObject *self, PyObject *args) { PyObject *first, *callback, *extra_args, *ret; gchar *name; Py_ssize_t len; len = PyTuple_Size(args); if (len < 2) { PyErr_SetString(PyExc_TypeError, "GObject.connect requires at least 2 arguments"); return NULL; } first = PySequence_GetSlice(args, 0, 2); if (!PyArg_ParseTuple(first, "sO:GObject.connect", &name, &callback)) { Py_DECREF(first); return NULL; } Py_DECREF(first); if (!PyCallable_Check(callback)) { PyErr_SetString(PyExc_TypeError, "second argument must be callable"); return NULL; } CHECK_GOBJECT(self); extra_args = PySequence_GetSlice(args, 2, len); if (extra_args == NULL) return NULL; ret = connect_helper(self, name, callback, extra_args, NULL, FALSE); Py_DECREF(extra_args); return ret; } static PyObject * pygobject_connect_after(PyGObject *self, PyObject *args) { PyObject *first, *callback, *extra_args, *ret; gchar *name; Py_ssize_t len; len = PyTuple_Size(args); if (len < 2) { PyErr_SetString(PyExc_TypeError, "GObject.connect_after requires at least 2 arguments"); return NULL; } first = PySequence_GetSlice(args, 0, 2); if (!PyArg_ParseTuple(first, "sO:GObject.connect_after", &name, &callback)) { Py_DECREF(first); return NULL; } Py_DECREF(first); if (!PyCallable_Check(callback)) { PyErr_SetString(PyExc_TypeError, "second argument must be callable"); return NULL; } CHECK_GOBJECT(self); extra_args = PySequence_GetSlice(args, 2, len); if (extra_args == NULL) return NULL; ret = connect_helper(self, name, callback, extra_args, NULL, TRUE); Py_DECREF(extra_args); return ret; } static PyObject * pygobject_connect_object(PyGObject *self, PyObject *args) { PyObject *first, *callback, *extra_args, *object, *ret; gchar *name; Py_ssize_t len; len = PyTuple_Size(args); if (len < 3) { PyErr_SetString(PyExc_TypeError, "GObject.connect_object requires at least 3 arguments"); return NULL; } first = PySequence_GetSlice(args, 0, 3); if (!PyArg_ParseTuple(first, "sOO:GObject.connect_object", &name, &callback, &object)) { Py_DECREF(first); return NULL; } Py_DECREF(first); if (!PyCallable_Check(callback)) { PyErr_SetString(PyExc_TypeError, "second argument must be callable"); return NULL; } CHECK_GOBJECT(self); extra_args = PySequence_GetSlice(args, 3, len); if (extra_args == NULL) return NULL; ret = connect_helper(self, name, callback, extra_args, object, FALSE); Py_DECREF(extra_args); return ret; } static PyObject * pygobject_connect_object_after(PyGObject *self, PyObject *args) { PyObject *first, *callback, *extra_args, *object, *ret; gchar *name; Py_ssize_t len; len = PyTuple_Size(args); if (len < 3) { PyErr_SetString(PyExc_TypeError, "GObject.connect_object_after requires at least 3 arguments"); return NULL; } first = PySequence_GetSlice(args, 0, 3); if (!PyArg_ParseTuple(first, "sOO:GObject.connect_object_after", &name, &callback, &object)) { Py_DECREF(first); return NULL; } Py_DECREF(first); if (!PyCallable_Check(callback)) { PyErr_SetString(PyExc_TypeError, "second argument must be callable"); return NULL; } CHECK_GOBJECT(self); extra_args = PySequence_GetSlice(args, 3, len); if (extra_args == NULL) return NULL; ret = connect_helper(self, name, callback, extra_args, object, TRUE); Py_DECREF(extra_args); return ret; } static PyObject * pygobject_emit(PyGObject *self, PyObject *args) { guint signal_id, i, j; Py_ssize_t len; GQuark detail; PyObject *first, *py_ret, *repr = NULL; gchar *name; GSignalQuery query; GValue *params, ret = { 0, }; len = PyTuple_Size(args); if (len < 1) { PyErr_SetString(PyExc_TypeError,"GObject.emit needs at least one arg"); return NULL; } first = PySequence_GetSlice(args, 0, 1); if (!PyArg_ParseTuple(first, "s:GObject.emit", &name)) { Py_DECREF(first); return NULL; } Py_DECREF(first); CHECK_GOBJECT(self); if (!g_signal_parse_name(name, G_OBJECT_TYPE(self->obj), &signal_id, &detail, TRUE)) { repr = PyObject_Repr((PyObject*)self); PyErr_Format(PyExc_TypeError, "%s: unknown signal name: %s", PyUnicode_AsUTF8 (repr), name); Py_DECREF(repr); return NULL; } g_signal_query(signal_id, &query); if ((gsize)len != query.n_params + 1) { gchar buf[128]; g_snprintf(buf, sizeof(buf), "%d parameters needed for signal %s; %ld given", query.n_params, name, (long int) (len - 1)); PyErr_SetString(PyExc_TypeError, buf); return NULL; } params = g_new0(GValue, query.n_params + 1); g_value_init(¶ms[0], G_OBJECT_TYPE(self->obj)); g_value_set_object(¶ms[0], G_OBJECT(self->obj)); for (i = 0; i < query.n_params; i++) g_value_init(¶ms[i + 1], query.param_types[i] & ~G_SIGNAL_TYPE_STATIC_SCOPE); for (i = 0; i < query.n_params; i++) { PyObject *item = PyTuple_GetItem(args, i+1); if (pyg_value_from_pyobject(¶ms[i+1], item) < 0) { gchar buf[128]; g_snprintf(buf, sizeof(buf), "could not convert type %s to %s required for parameter %d", Py_TYPE(item)->tp_name, G_VALUE_TYPE_NAME(¶ms[i+1]), i); PyErr_SetString(PyExc_TypeError, buf); for (j = 0; j <= i; j++) g_value_unset(¶ms[j]); g_free(params); return NULL; } } 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); if (!was_floating) g_value_unset(&ret); } else { Py_INCREF(Py_None); py_ret = Py_None; } return py_ret; } static PyObject * pygobject_chain_from_overridden(PyGObject *self, PyObject *args) { GSignalInvocationHint *ihint; guint signal_id, i; Py_ssize_t len; PyObject *py_ret; const gchar *name; GSignalQuery query; GValue *params, ret = { 0, }; CHECK_GOBJECT(self); ihint = g_signal_get_invocation_hint(self->obj); if (!ihint) { PyErr_SetString(PyExc_TypeError, "could not find signal invocation " "information for this object."); return NULL; } signal_id = ihint->signal_id; name = g_signal_name(signal_id); len = PyTuple_Size(args); if (signal_id == 0) { PyErr_SetString(PyExc_TypeError, "unknown signal name"); return NULL; } g_signal_query(signal_id, &query); if (len < 0 || (gsize)len != query.n_params) { gchar buf[128]; g_snprintf(buf, sizeof(buf), "%d parameters needed for signal %s; %ld given", query.n_params, name, (long int) len); PyErr_SetString(PyExc_TypeError, buf); return NULL; } params = g_new0(GValue, query.n_params + 1); g_value_init(¶ms[0], G_OBJECT_TYPE(self->obj)); g_value_set_object(¶ms[0], G_OBJECT(self->obj)); for (i = 0; i < query.n_params; i++) g_value_init(¶ms[i + 1], query.param_types[i] & ~G_SIGNAL_TYPE_STATIC_SCOPE); for (i = 0; i < query.n_params; i++) { PyObject *item = PyTuple_GetItem(args, i); if (pyg_boxed_check(item, (query.param_types[i] & ~G_SIGNAL_TYPE_STATIC_SCOPE))) { g_value_set_static_boxed(¶ms[i+1], pyg_boxed_get(item, void)); } else if (pyg_value_from_pyobject(¶ms[i+1], item) < 0) { gchar buf[128]; g_snprintf(buf, sizeof(buf), "could not convert type %s to %s required for parameter %d", Py_TYPE(item)->tp_name, g_type_name(G_VALUE_TYPE(¶ms[i+1])), i); PyErr_SetString(PyExc_TypeError, buf); for (i = 0; i < query.n_params + 1; i++) g_value_unset(¶ms[i]); g_free(params); return NULL; } } if (query.return_type != G_TYPE_NONE) g_value_init(&ret, query.return_type & ~G_SIGNAL_TYPE_STATIC_SCOPE); g_signal_chain_from_overridden(params, &ret); for (i = 0; i < query.n_params + 1; i++) g_value_unset(¶ms[i]); g_free(params); if (query.return_type != G_TYPE_NONE) { py_ret = pyg_value_as_pyobject(&ret, TRUE); g_value_unset(&ret); } else { Py_INCREF(Py_None); py_ret = Py_None; } return py_ret; } static PyObject * pygobject_weak_ref(PyGObject *self, PyObject *args) { Py_ssize_t len; PyObject *callback = NULL, *user_data = NULL; PyObject *retval; CHECK_GOBJECT(self); if ((len = PySequence_Length(args)) >= 1) { callback = PySequence_ITEM(args, 0); user_data = PySequence_GetSlice(args, 1, len); } retval = pygobject_weak_ref_new(self->obj, callback, user_data); Py_XDECREF(callback); Py_XDECREF(user_data); return retval; } static PyObject * pygobject_copy(PyGObject *self) { PyErr_SetString(PyExc_TypeError, "GObject descendants' instances are non-copyable"); return NULL; } static PyObject * pygobject_deepcopy(PyGObject *self, PyObject *args) { PyErr_SetString(PyExc_TypeError, "GObject descendants' instances are non-copyable"); return NULL; } static PyObject * pygobject_disconnect_by_func(PyGObject *self, PyObject *args) { PyObject *pyfunc = NULL, *repr = NULL; GClosure *closure = NULL; guint retval; CHECK_GOBJECT(self); if (!PyArg_ParseTuple(args, "O:GObject.disconnect_by_func", &pyfunc)) return NULL; if (!PyCallable_Check(pyfunc)) { PyErr_SetString(PyExc_TypeError, "first argument must be callable"); return NULL; } closure = gclosure_from_pyfunc(self, pyfunc); if (!closure) { repr = PyObject_Repr((PyObject*)pyfunc); PyErr_Format(PyExc_TypeError, "nothing connected to %s", PyUnicode_AsUTF8 (repr)); Py_DECREF(repr); return NULL; } retval = g_signal_handlers_disconnect_matched(self->obj, G_SIGNAL_MATCH_CLOSURE, 0, 0, closure, NULL, NULL); return pygi_guint_to_py (retval); } static PyObject * pygobject_handler_block_by_func(PyGObject *self, PyObject *args) { PyObject *pyfunc = NULL, *repr = NULL; GClosure *closure = NULL; guint retval; CHECK_GOBJECT(self); if (!PyArg_ParseTuple(args, "O:GObject.handler_block_by_func", &pyfunc)) return NULL; if (!PyCallable_Check(pyfunc)) { PyErr_SetString(PyExc_TypeError, "first argument must be callable"); return NULL; } closure = gclosure_from_pyfunc(self, pyfunc); if (!closure) { repr = PyObject_Repr((PyObject*)pyfunc); PyErr_Format(PyExc_TypeError, "nothing connected to %s", PyUnicode_AsUTF8 (repr)); Py_DECREF(repr); return NULL; } retval = g_signal_handlers_block_matched(self->obj, G_SIGNAL_MATCH_CLOSURE, 0, 0, closure, NULL, NULL); return pygi_guint_to_py (retval); } static PyObject * pygobject_handler_unblock_by_func(PyGObject *self, PyObject *args) { PyObject *pyfunc = NULL, *repr = NULL; GClosure *closure = NULL; guint retval; CHECK_GOBJECT(self); if (!PyArg_ParseTuple(args, "O:GObject.handler_unblock_by_func", &pyfunc)) return NULL; if (!PyCallable_Check(pyfunc)) { PyErr_SetString(PyExc_TypeError, "first argument must be callable"); return NULL; } closure = gclosure_from_pyfunc(self, pyfunc); if (!closure) { repr = PyObject_Repr((PyObject*)pyfunc); PyErr_Format(PyExc_TypeError, "nothing connected to %s", PyUnicode_AsUTF8 (repr)); Py_DECREF(repr); return NULL; } retval = g_signal_handlers_unblock_matched(self->obj, G_SIGNAL_MATCH_CLOSURE, 0, 0, closure, NULL, NULL); return pygi_guint_to_py (retval); } static PyMethodDef pygobject_methods[] = { { "get_property", (PyCFunction)pygobject_get_property, METH_VARARGS }, { "get_properties", (PyCFunction)pygobject_get_properties, METH_VARARGS }, { "set_property", (PyCFunction)pygobject_set_property, METH_VARARGS }, { "set_properties", (PyCFunction)pygobject_set_properties, METH_VARARGS|METH_KEYWORDS }, { "bind_property", (PyCFunction)pygobject_bind_property, METH_VARARGS|METH_KEYWORDS }, { "connect", (PyCFunction)pygobject_connect, METH_VARARGS }, { "connect_after", (PyCFunction)pygobject_connect_after, METH_VARARGS }, { "connect_object", (PyCFunction)pygobject_connect_object, METH_VARARGS }, { "connect_object_after", (PyCFunction)pygobject_connect_object_after, METH_VARARGS }, { "disconnect_by_func", (PyCFunction)pygobject_disconnect_by_func, METH_VARARGS }, { "handler_block_by_func", (PyCFunction)pygobject_handler_block_by_func, METH_VARARGS }, { "handler_unblock_by_func", (PyCFunction)pygobject_handler_unblock_by_func, METH_VARARGS }, { "emit", (PyCFunction)pygobject_emit, METH_VARARGS }, { "chain", (PyCFunction)pygobject_chain_from_overridden,METH_VARARGS }, { "weak_ref", (PyCFunction)pygobject_weak_ref, METH_VARARGS }, { "__copy__", (PyCFunction)pygobject_copy, METH_NOARGS }, { "__deepcopy__", (PyCFunction)pygobject_deepcopy, METH_VARARGS }, { 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(); pygobject_toggle_ref_ensure (self); } Py_INCREF(self->inst_dict); return self->inst_dict; } #endif static PyObject * pygobject_get_refcount(PyGObject *self, void *closure) { if (self->obj == NULL) { PyErr_Format(PyExc_TypeError, "GObject instance is not yet created"); return NULL; } return pygi_guint_to_py (self->obj->ref_count); } static PyObject * pygobject_get_pointer(PyGObject *self, void *closure) { return PyCapsule_New (self->obj, NULL, NULL); } static int pygobject_setattro(PyObject *self, PyObject *name, PyObject *value) { int res; res = PyGObject_Type.tp_base->tp_setattro(self, name, value); 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 } }; /* ------------------------------------ */ /* ****** GObject weak reference ****** */ /* ------------------------------------ */ typedef struct { PyObject_HEAD GObject *obj; PyObject *callback; PyObject *user_data; gboolean have_floating_ref; } PyGObjectWeakRef; PYGI_DEFINE_TYPE("gi._gi.GObjectWeakRef", PyGObjectWeakRef_Type, PyGObjectWeakRef); static int pygobject_weak_ref_traverse(PyGObjectWeakRef *self, visitproc visit, void *arg) { if (self->callback && visit(self->callback, arg) < 0) return -1; if (self->user_data && visit(self->user_data, arg) < 0) return -1; return 0; } static void pygobject_weak_ref_notify(PyGObjectWeakRef *self, GObject *dummy) { self->obj = NULL; if (self->callback) { PyObject *retval; PyGILState_STATE state = PyGILState_Ensure(); retval = PyObject_Call(self->callback, self->user_data, NULL); if (retval) { if (retval != Py_None) PyErr_Format(PyExc_TypeError, "GObject weak notify callback returned a value" " of type %s, should return None", Py_TYPE(retval)->tp_name); Py_DECREF(retval); PyErr_Print(); } else PyErr_Print(); Py_CLEAR(self->callback); Py_CLEAR(self->user_data); if (self->have_floating_ref) { self->have_floating_ref = FALSE; Py_DECREF((PyObject *) self); } PyGILState_Release(state); } } static inline int pygobject_weak_ref_clear(PyGObjectWeakRef *self) { Py_CLEAR(self->callback); Py_CLEAR(self->user_data); if (self->obj) { g_object_weak_unref(self->obj, (GWeakNotify) pygobject_weak_ref_notify, self); self->obj = NULL; } return 0; } static void pygobject_weak_ref_dealloc(PyGObjectWeakRef *self) { PyObject_GC_UnTrack((PyObject *)self); pygobject_weak_ref_clear(self); PyObject_GC_Del(self); } static PyObject * pygobject_weak_ref_new(GObject *obj, PyObject *callback, PyObject *user_data) { PyGObjectWeakRef *self; self = PyObject_GC_New(PyGObjectWeakRef, &PyGObjectWeakRef_Type); self->callback = callback; self->user_data = user_data; Py_XINCREF(self->callback); Py_XINCREF(self->user_data); self->obj = obj; g_object_weak_ref(self->obj, (GWeakNotify) pygobject_weak_ref_notify, self); if (callback != NULL) { /* when we have a callback, we should INCREF the weakref * object to make it stay alive even if it goes out of scope */ self->have_floating_ref = TRUE; Py_INCREF((PyObject *) self); } return (PyObject *) self; } static PyObject * pygobject_weak_ref_unref(PyGObjectWeakRef *self, PyObject *args) { if (!self->obj) { PyErr_SetString(PyExc_ValueError, "weak ref already unreffed"); return NULL; } g_object_weak_unref(self->obj, (GWeakNotify) pygobject_weak_ref_notify, self); self->obj = NULL; if (self->have_floating_ref) { self->have_floating_ref = FALSE; Py_DECREF(self); } Py_INCREF(Py_None); return Py_None; } static PyMethodDef pygobject_weak_ref_methods[] = { { "unref", (PyCFunction)pygobject_weak_ref_unref, METH_NOARGS}, { NULL, NULL, 0} }; static PyObject * pygobject_weak_ref_call(PyGObjectWeakRef *self, PyObject *args, PyObject *kw) { static char *argnames[] = {NULL}; if (!PyArg_ParseTupleAndKeywords(args, kw, ":__call__", argnames)) return NULL; if (self->obj) return pygobject_new(self->obj); else { Py_INCREF(Py_None); return Py_None; } } static gpointer pyobject_copy(gpointer boxed) { PyObject *object = boxed; PyGILState_STATE state; state = PyGILState_Ensure(); Py_INCREF(object); PyGILState_Release(state); return object; } static void pyobject_free(gpointer boxed) { PyObject *object = boxed; PyGILState_STATE state; state = PyGILState_Ensure(); Py_DECREF(object); PyGILState_Release(state); } /** * Returns 0 on success, or -1 and sets an exception. */ int pyi_object_register_types(PyObject *d) { PyObject *o, *descr; pygobject_custom_key = g_quark_from_static_string("PyGObject::custom"); pygobject_class_key = g_quark_from_static_string("PyGObject::class"); pygobject_class_init_key = g_quark_from_static_string("PyGObject::class-init"); pygobject_wrapper_key = g_quark_from_static_string("PyGObject::wrapper"); pygobject_has_updated_constructor_key = g_quark_from_static_string("PyGObject::has-updated-constructor"); pygobject_instance_data_key = g_quark_from_static_string("PyGObject::instance-data"); /* GObject */ if (!PY_TYPE_OBJECT) PY_TYPE_OBJECT = g_boxed_type_register_static("PyObject", pyobject_copy, pyobject_free); PyGObject_Type.tp_dealloc = (destructor)pygobject_dealloc; PyGObject_Type.tp_richcompare = pygobject_richcompare; PyGObject_Type.tp_repr = (reprfunc)pygobject_repr; PyGObject_Type.tp_hash = (hashfunc)pygobject_hash; PyGObject_Type.tp_setattro = (setattrofunc)pygobject_setattro; PyGObject_Type.tp_flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE | Py_TPFLAGS_HAVE_GC); PyGObject_Type.tp_traverse = (traverseproc)pygobject_traverse; PyGObject_Type.tp_clear = (inquiry)pygobject_clear; 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; PyGObject_Type.tp_new = PyType_GenericNew; pygobject_register_class(d, "GObject", G_TYPE_OBJECT, &PyGObject_Type, NULL); PyDict_SetItemString(PyGObject_Type.tp_dict, "__gdoc__", pyg_object_descr_doc_get()); /* GProps */ PyGProps_Type.tp_dealloc = (destructor)PyGProps_dealloc; PyGProps_Type.tp_as_sequence = (PySequenceMethods*)&_PyGProps_as_sequence; PyGProps_Type.tp_getattro = (getattrofunc)PyGProps_getattro; PyGProps_Type.tp_setattro = (setattrofunc)PyGProps_setattro; PyGProps_Type.tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_GC; PyGProps_Type.tp_doc = "The properties of the GObject accessible as " "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 -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 -1; descr = PyObject_New(PyObject, &PyGPropsDescr_Type); PyDict_SetItemString(PyGObject_Type.tp_dict, "props", descr); PyDict_SetItemString(PyGObject_Type.tp_dict, "__module__", o=PyUnicode_FromString ("gi._gi")); Py_DECREF(o); /* GPropsIter */ PyGPropsIter_Type.tp_dealloc = (destructor)pyg_props_iter_dealloc; PyGPropsIter_Type.tp_flags = Py_TPFLAGS_DEFAULT; PyGPropsIter_Type.tp_doc = "GObject properties iterator"; PyGPropsIter_Type.tp_iternext = (iternextfunc)pygobject_props_iter_next; if (PyType_Ready(&PyGPropsIter_Type) < 0) return -1; PyGObjectWeakRef_Type.tp_dealloc = (destructor)pygobject_weak_ref_dealloc; PyGObjectWeakRef_Type.tp_call = (ternaryfunc)pygobject_weak_ref_call; PyGObjectWeakRef_Type.tp_flags = Py_TPFLAGS_DEFAULT|Py_TPFLAGS_HAVE_GC; PyGObjectWeakRef_Type.tp_doc = "A GObject weak reference"; PyGObjectWeakRef_Type.tp_traverse = (traverseproc)pygobject_weak_ref_traverse; PyGObjectWeakRef_Type.tp_clear = (inquiry)pygobject_weak_ref_clear; PyGObjectWeakRef_Type.tp_methods = pygobject_weak_ref_methods; if (PyType_Ready(&PyGObjectWeakRef_Type) < 0) return -1; PyDict_SetItemString(d, "GObjectWeakRef", (PyObject *) &PyGObjectWeakRef_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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pygobject-object.h0000664000000000000000000000365315074674453016357 0ustar00rootroot#ifndef _PYGOBJECT_OBJECT_H_ #define _PYGOBJECT_OBJECT_H_ #include #include #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_*/ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pygobject.h0000664000000000000000000005771215074674453015120 0ustar00rootroot/* -*- Mode: C; c-basic-offset: 4 -*- */ #ifndef _PYGOBJECT_H_ #define _PYGOBJECT_H_ #include #include #include G_BEGIN_DECLS /* PyGClosure is a _private_ structure */ typedef void (* PyClosureExceptionHandler) (GValue *ret, guint n_param_values, const GValue *params); typedef struct _PyGClosure PyGClosure; typedef struct _PyGObjectData PyGObjectData; struct _PyGClosure { GClosure closure; PyObject *callback; PyObject *extra_args; /* tuple of extra args to pass to callback */ PyObject *swap_data; /* other object for gtk_signal_connect__object */ PyClosureExceptionHandler exception_handler; }; typedef enum { PYGOBJECT_USING_TOGGLE_REF = 1 << 0, PYGOBJECT_IS_FLOATING_REF = 1 << 1, PYGOBJECT_GOBJECT_WAS_FLOATING = 1 << 2 } PyGObjectFlags; /* closures is just an alias for what is found in the * PyGObjectData */ typedef struct { PyObject_HEAD GObject *obj; PyObject *inst_dict; /* the instance dictionary -- must be last */ PyObject *weakreflist; /* list of weak references */ /*< private >*/ /* using union to preserve ABI compatibility (structure size * must not change) */ union { GSList *closures; /* stale field; no longer updated DO-NOT-USE! */ PyGObjectFlags flags; } private_flags; } PyGObject; #define pygobject_get(v) (((PyGObject *)(v))->obj) #define pygobject_check(v,base) (PyObject_TypeCheck(v,base)) typedef struct { PyObject_HEAD gpointer boxed; GType gtype; gboolean free_on_dealloc; } 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 { PyObject_HEAD gpointer pointer; GType gtype; } 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); typedef void (*PyGThreadBlockFunc) (void); typedef int (*PyGClassInitFunc) (gpointer gclass, PyTypeObject *pyclass); typedef PyTypeObject * (*PyGTypeRegistrationFunction) (const gchar *name, gpointer data); struct _PyGObject_Functions { /* * All field names in here are considered private, * use the macros below instead, which provides stability */ void (* register_class)(PyObject *dict, const gchar *class_name, GType gtype, PyTypeObject *type, PyObject *bases); void (* register_wrapper)(PyObject *self); PyTypeObject *(* lookup_class)(GType type); PyObject *(* newgobj)(GObject *obj); GClosure *(* closure_new)(PyObject *callback, PyObject *extra_args, PyObject *swap_data); void (* object_watch_closure)(PyObject *self, GClosure *closure); GDestroyNotify destroy_notify; GType (* type_from_object)(PyObject *obj); PyObject *(* type_wrapper_new)(GType type); gint (* enum_get_value)(GType enum_type, PyObject *obj, gint *val); gint (* flags_get_value)(GType flag_type, PyObject *obj, guint *val); void (* register_gtype_custom)(GType gtype, PyObject *(* from_func)(const GValue *value), int (* to_func)(GValue *value, PyObject *obj)); int (* value_from_pyobject)(GValue *value, PyObject *obj); PyObject *(* value_as_pyobject)(const GValue *value, gboolean copy_boxed); void (* register_interface)(PyObject *dict, const gchar *class_name, GType gtype, PyTypeObject *type); PyTypeObject *boxed_type; void (* register_boxed)(PyObject *dict, const gchar *class_name, GType boxed_type, PyTypeObject *type); PyObject *(* boxed_new)(GType boxed_type, gpointer boxed, gboolean copy_boxed, gboolean own_ref); PyTypeObject *pointer_type; void (* register_pointer)(PyObject *dict, const gchar *class_name, GType pointer_type, PyTypeObject *type); PyObject *(* pointer_new)(GType boxed_type, gpointer pointer); void (* enum_add_constants)(PyObject *module, GType enum_type, const gchar *strip_prefix); void (* flags_add_constants)(PyObject *module, GType flags_type, const gchar *strip_prefix); const gchar *(* constant_strip_prefix)(const gchar *name, const gchar *strip_prefix); gboolean (* error_check)(GError **error); /* hooks to register handlers for getting GDK threads to cooperate * with python threading */ void (* set_thread_block_funcs) (PyGThreadBlockFunc block_threads_func, PyGThreadBlockFunc unblock_threads_func); PyGThreadBlockFunc block_threads; PyGThreadBlockFunc unblock_threads; PyTypeObject *paramspec_type; 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); int (* gvalue_from_param_pyobject) (GValue* value, PyObject* py_obj, const GParamSpec* pspec); PyTypeObject *enum_type; PyObject *(*enum_add)(PyObject *module, const char *type_name_, const char *strip_prefix, GType gtype); PyObject* (*enum_from_gtype)(GType gtype, int value); PyTypeObject *flags_type; PyObject *(*flags_add)(PyObject *module, const char *type_name_, const char *strip_prefix, GType gtype); PyObject* (*flags_from_gtype)(GType gtype, guint value); gboolean threads_enabled; int (*enable_threads) (void); int (*gil_state_ensure) (void); void (*gil_state_release) (int flag); void (*register_class_init) (GType gtype, PyGClassInitFunc class_init); void (*register_interface_info) (GType gtype, const GInterfaceInfo *info); void (*closure_set_exception_handler) (GClosure *closure, PyClosureExceptionHandler handler); void (*add_warning_redirection) (const char *domain, PyObject *warning); void (*disable_warning_redirections) (void); /* type_register_custom API now removed, but leave a pointer here to not * break ABI. */ void *_type_register_custom; gboolean (*gerror_exception_check) (GError **error); PyObject* (*option_group_new) (GOptionGroup *group); GType (* type_from_object_strict) (PyObject *obj, gboolean strict); PyObject *(* newgobj_full)(GObject *obj, gboolean steal, gpointer g_class); PyTypeObject *object_type; int (* value_from_pyobject_with_error)(GValue *value, PyObject *obj); }; /* 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() #define pyg_unblock_threads() #ifndef _INSIDE_PYGOBJECT_ #if defined(NO_IMPORT) || defined(NO_IMPORT_PYGOBJECT) extern struct _PyGObject_Functions *_PyGObject_API; #else struct _PyGObject_Functions *_PyGObject_API; #endif #define pygobject_register_class (_PyGObject_API->register_class) #define pygobject_register_wrapper (_PyGObject_API->register_wrapper) #define pygobject_lookup_class (_PyGObject_API->lookup_class) #define pygobject_new (_PyGObject_API->newgobj) #define pygobject_new_full (_PyGObject_API->newgobj_full) #define PyGObject_Type (*_PyGObject_API->object_type) #define pyg_closure_new (_PyGObject_API->closure_new) #define pygobject_watch_closure (_PyGObject_API->object_watch_closure) #define pyg_closure_set_exception_handler (_PyGObject_API->closure_set_exception_handler) #define pyg_destroy_notify (_PyGObject_API->destroy_notify) #define pyg_type_from_object_strict (_PyGObject_API->type_from_object_strict) #define pyg_type_from_object (_PyGObject_API->type_from_object) #define pyg_type_wrapper_new (_PyGObject_API->type_wrapper_new) #define pyg_enum_get_value (_PyGObject_API->enum_get_value) #define pyg_flags_get_value (_PyGObject_API->flags_get_value) #define pyg_register_gtype_custom (_PyGObject_API->register_gtype_custom) #define pyg_value_from_pyobject (_PyGObject_API->value_from_pyobject) #define pyg_value_from_pyobject_with_error (_PyGObject_API->value_from_pyobject_with_error) #define pyg_value_as_pyobject (_PyGObject_API->value_as_pyobject) #define pyg_register_interface (_PyGObject_API->register_interface) #define PyGBoxed_Type (*_PyGObject_API->boxed_type) #define pyg_register_boxed (_PyGObject_API->register_boxed) #define pyg_boxed_new (_PyGObject_API->boxed_new) #define PyGPointer_Type (*_PyGObject_API->pointer_type) #define pyg_register_pointer (_PyGObject_API->register_pointer) #define pyg_pointer_new (_PyGObject_API->pointer_new) #define pyg_enum_add_constants (_PyGObject_API->enum_add_constants) #define pyg_flags_add_constants (_PyGObject_API->flags_add_constants) #define pyg_constant_strip_prefix (_PyGObject_API->constant_strip_prefix) #define pyg_error_check (_PyGObject_API->error_check) #define PyGParamSpec_Type (*_PyGObject_API->paramspec_type) #define pyg_param_spec_new (_PyGObject_API->paramspec_new) #define pyg_param_spec_from_object (_PyGObject_API->paramspec_get) #define pyg_pyobj_to_unichar_conv (_PyGObject_API->pyobj_to_unichar_conv) #define pyg_parse_constructor_args (_PyGObject_API->parse_constructor_args) #define pyg_param_gvalue_as_pyobject (_PyGObject_API->value_as_pyobject) #define pyg_param_gvalue_from_pyobject (_PyGObject_API->gvalue_from_param_pyobject) #define PyGEnum_Type (*_PyGObject_API->enum_type) #define pyg_enum_add (_PyGObject_API->enum_add) #define pyg_enum_from_gtype (_PyGObject_API->enum_from_gtype) #define PyGFlags_Type (*_PyGObject_API->flags_type) #define pyg_flags_add (_PyGObject_API->flags_add) #define pyg_flags_from_gtype (_PyGObject_API->flags_from_gtype) #define pyg_register_class_init (_PyGObject_API->register_class_init) #define pyg_register_interface_info (_PyGObject_API->register_interface_info) #define pyg_add_warning_redirection (_PyGObject_API->add_warning_redirection) #define pyg_disable_warning_redirections (_PyGObject_API->disable_warning_redirections) #define pyg_gerror_exception_check (_PyGObject_API->gerror_exception_check) #define pyg_option_group_new (_PyGObject_API->option_group_new) /** * pygobject_init: * @req_major: minimum version major number, or -1 * @req_minor: minimum version minor number, or -1 * @req_micro: minimum version micro number, or -1 * * Imports and initializes the 'gobject' python module. Can * optionally check for a required minimum version if @req_major, * @req_minor, and @req_micro are all different from -1. * * Returns: a new reference to the gobject module on success, NULL in * case of failure (and raises ImportError). **/ static inline PyObject * pygobject_init(int req_major, int req_minor, int req_micro) { PyObject *gobject, *cobject; gobject = PyImport_ImportModule("gi._gobject"); if (!gobject) { 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); #if PY_VERSION_HEX < 0x03000000 PyErr_Format(PyExc_ImportError, "could not import gobject (error was: %s)", PyString_AsString(py_orig_exc)); #else { /* Can not use PyErr_Format because it doesn't have * a format string for dealing with PyUnicode objects * like PyUnicode_FromFormat has */ PyObject *errmsg = PyUnicode_FromFormat("could not import gobject (error was: %U)", py_orig_exc); if (errmsg) { PyErr_SetObject(PyExc_ImportError, errmsg); Py_DECREF(errmsg); } /* if errmsg is NULL then we might have OOM * PyErr should already be set and trying to * return our own error would be futile */ } #endif Py_DECREF(py_orig_exc); } else { PyErr_SetString(PyExc_ImportError, "could not import gobject (no error given)"); } return NULL; } cobject = PyObject_GetAttrString(gobject, "_PyGObject_API"); if (cobject && PyCapsule_CheckExact(cobject)) { _PyGObject_API = (struct _PyGObject_Functions *) PyCapsule_GetPointer(cobject, "gobject._PyGObject_API"); 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; } if (req_major != -1) { int found_major, found_minor, found_micro; PyObject *version; version = PyObject_GetAttrString(gobject, "pygobject_version"); if (!version) { PyErr_SetString(PyExc_ImportError, "could not import gobject (version too old)"); Py_DECREF(gobject); return NULL; } if (!PyArg_ParseTuple(version, "iii", &found_major, &found_minor, &found_micro)) { PyErr_SetString(PyExc_ImportError, "could not import gobject (version has invalid format)"); Py_DECREF(version); Py_DECREF(gobject); return NULL; } Py_DECREF(version); if (req_major != found_major || req_minor > found_minor || (req_minor == found_minor && req_micro > found_micro)) { PyErr_Format(PyExc_ImportError, "could not import gobject (version mismatch, %d.%d.%d is required, " "found %d.%d.%d)", req_major, req_minor, req_micro, found_major, found_minor, found_micro); Py_DECREF(gobject); return NULL; } } return gobject; } /** * PYLIST_FROMGLIBLIST: * @type: the type of the GLib list e.g. #GList or #GSList * @prefix: the prefix of functions that manipulate a list of the type * given by type. * * A macro that creates a type specific code block which converts a GLib * list (#GSList or #GList) to a Python list. The first two args of the macro * are used to specify the type and list function prefix so that the type * specific macros can be generated. * * The rest of the args are for the standard args for the type specific * macro(s) created from this macro. */ #define PYLIST_FROMGLIBLIST(type,prefix,py_list,list,item_convert_func,\ list_free,list_item_free) \ G_STMT_START \ { \ gint i, len; \ PyObject *item; \ void (*glib_list_free)(type*) = list_free; \ GFunc glib_list_item_free = (GFunc)list_item_free; \ \ len = prefix##_length(list); \ py_list = PyList_New(len); \ for (i = 0; i < len; i++) { \ gpointer list_item = prefix##_nth_data(list, i); \ \ item = item_convert_func; \ PyList_SetItem(py_list, i, item); \ } \ if (glib_list_item_free != NULL) \ prefix##_foreach(list, glib_list_item_free, NULL); \ if (glib_list_free != NULL) \ glib_list_free(list); \ } G_STMT_END /** * PYLIST_FROMGLIST: * @py_list: the name of the Python list * * @list: the #GList to be converted to a Python list * * @item_convert_func: the function that converts a list item to a Python * object. The function must refer to the list item using "@list_item" and * must return a #PyObject* object. An example conversion function is: * [[ * PyString_FromString(list_item) * ]] * A more elaborate function is: * [[ * pyg_boxed_new(GTK_TYPE_RECENT_INFO, list_item, TRUE, TRUE) * ]] * @list_free: the name of a function that takes a single arg (the list) and * frees its memory. Can be NULL if the list should not be freed. An example * is: * [[ * g_list_free * ]] * @list_item_free: the name of a #GFunc function that frees the memory used * by the items in the list or %NULL if the list items do not have to be * freed. A simple example is: * [[ * g_free * ]] * * A macro that adds code that converts a #GList to a Python list. * */ #define PYLIST_FROMGLIST(py_list,list,item_convert_func,list_free,\ list_item_free) \ PYLIST_FROMGLIBLIST(GList,g_list,py_list,list,item_convert_func,\ list_free,list_item_free) /** * PYLIST_FROMGSLIST: * @py_list: the name of the Python list * * @list: the #GSList to be converted to a Python list * * @item_convert_func: the function that converts a list item to a Python * object. The function must refer to the list item using "@list_item" and * must return a #PyObject* object. An example conversion function is: * [[ * PyString_FromString(list_item) * ]] * A more elaborate function is: * [[ * pyg_boxed_new(GTK_TYPE_RECENT_INFO, list_item, TRUE, TRUE) * ]] * @list_free: the name of a function that takes a single arg (the list) and * frees its memory. Can be %NULL if the list should not be freed. An example * is: * [[ * g_list_free * ]] * @list_item_free: the name of a #GFunc function that frees the memory used * by the items in the list or %NULL if the list items do not have to be * freed. A simple example is: * [[ * g_free * ]] * * A macro that adds code that converts a #GSList to a Python list. * */ #define PYLIST_FROMGSLIST(py_list,list,item_convert_func,list_free,\ list_item_free) \ PYLIST_FROMGLIBLIST(GSList,g_slist,py_list,list,item_convert_func,\ list_free,list_item_free) /** * PYLIST_ASGLIBLIST * @type: the type of the GLib list e.g. GList or GSList * @prefix: the prefix of functions that manipulate a list of the type * given by type e.g. g_list or g_slist * * A macro that creates a type specific code block to be used to convert a * Python list to a GLib list (GList or GSList). The first two args of the * macro are used to specify the type and list function prefix so that the * type specific macros can be generated. * * The rest of the args are for the standard args for the type specific * macro(s) created from this macro. */ #define PYLIST_ASGLIBLIST(type,prefix,py_list,list,check_func,\ convert_func,child_free_func,errormsg,errorreturn) \ G_STMT_START \ { \ Py_ssize_t i, n_list; \ GFunc glib_child_free_func = (GFunc)child_free_func; \ \ if (!(py_list = PySequence_Fast(py_list, ""))) { \ errormsg; \ return errorreturn; \ } \ n_list = PySequence_Fast_GET_SIZE(py_list); \ for (i = 0; i < n_list; i++) { \ PyObject *py_item = PySequence_Fast_GET_ITEM(py_list, i); \ \ if (!check_func) { \ if (glib_child_free_func) \ prefix##_foreach(list, glib_child_free_func, NULL); \ prefix##_free(list); \ Py_DECREF(py_list); \ errormsg; \ return errorreturn; \ } \ list = prefix##_prepend(list, convert_func); \ }; \ Py_DECREF(py_list); \ list = prefix##_reverse(list); \ } \ G_STMT_END /** * PYLIST_ASGLIST * @py_list: the Python list to be converted * @list: the #GList list to be converted * @check_func: the expression that takes a #PyObject* arg (must be named * @py_item) and returns an int value indicating if the Python object matches * the required list item type (0 - %False or 1 - %True). An example is: * [[ * (PyString_Check(py_item)||PyUnicode_Check(py_item)) * ]] * @convert_func: the function that takes a #PyObject* arg (must be named * py_item) and returns a pointer to the converted list object. An example * is: * [[ * pygobject_get(py_item) * ]] * @child_free_func: the name of a #GFunc function that frees a GLib list * item or %NULL if the list item does not have to be freed. This function is * used to help free the items in a partially created list if there is an * error. An example is: * [[ * g_free * ]] * @errormsg: a function that sets up a Python error message. An example is: * [[ * PyErr_SetString(PyExc_TypeError, "strings must be a sequence of" "strings * or unicode objects") * ]] * @errorreturn: the value to return if an error occurs, e.g.: * [[ * %NULL * ]] * * A macro that creates code that converts a Python list to a #GList. The * returned list must be freed using the appropriate list free function when * it's no longer needed. If an error occurs the child_free_func is used to * release the memory used by the list items and then the list memory is * freed. */ #define PYLIST_ASGLIST(py_list,list,check_func,convert_func,child_free_func,\ errormsg,errorreturn) \ PYLIST_ASGLIBLIST(GList,g_list,py_list,list,check_func,convert_func,\ child_free_func,errormsg,errorreturn) /** * PYLIST_ASGSLIST * @py_list: the Python list to be converted * @list: the #GSList list to be converted * @check_func: the expression that takes a #PyObject* arg (must be named * @py_item) and returns an int value indicating if the Python object matches * the required list item type (0 - %False or 1 - %True). An example is: * [[ * (PyString_Check(py_item)||PyUnicode_Check(py_item)) * ]] * @convert_func: the function that takes a #PyObject* arg (must be named * py_item) and returns a pointer to the converted list object. An example * is: * [[ * pygobject_get(py_item) * ]] * @child_free_func: the name of a #GFunc function that frees a GLib list * item or %NULL if the list item does not have to be freed. This function is * used to help free the items in a partially created list if there is an * error. An example is: * [[ * g_free * ]] * @errormsg: a function that sets up a Python error message. An example is: * [[ * PyErr_SetString(PyExc_TypeError, "strings must be a sequence of" "strings * or unicode objects") * ]] * @errorreturn: the value to return if an error occurs, e.g.: * [[ * %NULL * ]] * * A macro that creates code that converts a Python list to a #GSList. The * returned list must be freed using the appropriate list free function when * it's no longer needed. If an error occurs the child_free_func is used to * release the memory used by the list items and then the list memory is * freed. */ #define PYLIST_ASGSLIST(py_list,list,check_func,convert_func,child_free_func,\ errormsg,errorreturn) \ PYLIST_ASGLIBLIST(GSList,g_slist,py_list,list,check_func,convert_func,\ child_free_func,errormsg,errorreturn) #endif /* !_INSIDE_PYGOBJECT_ */ G_END_DECLS #endif /* !_PYGOBJECT_H_ */ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pygoptioncontext.c0000664000000000000000000002652515074674453016560 0ustar00rootroot/* -*- Mode: C; c-basic-offset: 4 -*- * pygtk- Python bindings for the GTK toolkit. * Copyright (C) 2006 Johannes Hoelzl * * pygoptioncontext.c: GOptionContext wrapper * * 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 . */ #include #include "pygoptioncontext.h" #include "pygi-error.h" #include "pygi-util.h" #include "pygi-basictype.h" 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: * @context: a GOptionContext * * Returns: A new GOptionContext wrapper. */ PyObject * pyg_option_context_new (GOptionContext *context) { PyGOptionContext *self; self = (PyGOptionContext *)PyObject_NEW(PyGOptionContext, &PyGOptionContext_Type); if (self == NULL) return NULL; self->context = context; self->main_group = NULL; return (PyObject *)self; } static int pyg_option_context_init(PyGOptionContext *self, PyObject *args, PyObject *kwargs) { char *parameter_string; if (!PyArg_ParseTuple(args, "s:gi._gi.GOptionContext.__init__", ¶meter_string)) return -1; self->context = g_option_context_new(parameter_string); return 0; } static void pyg_option_context_dealloc(PyGOptionContext *self) { Py_CLEAR(self->main_group); if (self->context != NULL) { GOptionContext *tmp = self->context; self->context = NULL; g_option_context_free(tmp); } PyObject_Del(self); } static PyObject * pyg_option_context_parse(PyGOptionContext *self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "argv", NULL }; PyObject *arg; PyObject *new_argv, *argv; Py_ssize_t argv_length, pos; gint argv_length_int; char **argv_content, **original; GError *error = NULL; gboolean result; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O:GOptionContext.parse", kwlist, &argv)) return NULL; if (!PyList_Check(argv)) { PyErr_SetString(PyExc_TypeError, "GOptionContext.parse expects a list of strings."); return NULL; } argv_length = PyList_Size(argv); if (argv_length == -1) { PyErr_SetString(PyExc_TypeError, "GOptionContext.parse expects a list of strings."); return NULL; } argv_content = g_new(char*, argv_length + 1); argv_content[argv_length] = NULL; for (pos = 0; pos < argv_length; pos++) { arg = PyList_GetItem(argv, pos); argv_content[pos] = g_strdup(PyUnicode_AsUTF8 (arg)); if (argv_content[pos] == NULL) { g_strfreev(argv_content); return NULL; } } original = g_strdupv(argv_content); g_assert(argv_length <= G_MAXINT); argv_length_int = (gint)argv_length; Py_BEGIN_ALLOW_THREADS; result = g_option_context_parse(self->context, &argv_length_int, &argv_content, &error); Py_END_ALLOW_THREADS; argv_length = argv_length_int; if (!result) { g_strfreev(argv_content); g_strfreev(original); pygi_error_check(&error); return NULL; } new_argv = PyList_New(g_strv_length(argv_content)); for (pos = 0; pos < argv_length; pos++) { arg = PyUnicode_FromString (argv_content[pos]); PyList_SetItem(new_argv, pos, arg); } g_strfreev(original); g_strfreev(argv_content); return new_argv; } static PyObject * pyg_option_context_set_help_enabled(PyGOptionContext *self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "help_enable", NULL }; PyObject *help_enabled; if (! PyArg_ParseTupleAndKeywords(args, kwargs, "O:GOptionContext.set_help_enabled", kwlist, &help_enabled)) return NULL; g_option_context_set_help_enabled(self->context, PyObject_IsTrue(help_enabled)); Py_INCREF(Py_None); return Py_None; } static PyObject * pyg_option_context_get_help_enabled(PyGOptionContext *self) { return pygi_gboolean_to_py (g_option_context_get_help_enabled(self->context)); } static PyObject * pyg_option_context_set_ignore_unknown_options(PyGOptionContext *self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "ignore_unknown_options", NULL }; PyObject *ignore_unknown_options; if (! PyArg_ParseTupleAndKeywords(args, kwargs, "O:GOptionContext.set_ignore_unknown_options", kwlist, &ignore_unknown_options)) return NULL; g_option_context_set_ignore_unknown_options(self->context, PyObject_IsTrue(ignore_unknown_options)); Py_INCREF(Py_None); return Py_None; } static PyObject * pyg_option_context_get_ignore_unknown_options(PyGOptionContext *self) { return pygi_gboolean_to_py ( g_option_context_get_ignore_unknown_options(self->context)); } static PyObject * pyg_option_context_set_main_group(PyGOptionContext *self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "group", NULL }; GOptionGroup *g_group; PyObject *group; if (! PyArg_ParseTupleAndKeywords(args, kwargs, "O:GOptionContext.set_main_group", kwlist, &group)) return NULL; if (PyObject_IsInstance(group, (PyObject*) &PyGOptionGroup_Type) != 1) { PyErr_SetString(PyExc_TypeError, "GOptionContext.set_main_group expects a GOptionGroup."); return NULL; } g_group = pyglib_option_group_transfer_group(group); if (g_group == NULL) { PyErr_SetString(PyExc_RuntimeError, "Group is already in a OptionContext."); return NULL; } g_option_context_set_main_group(self->context, g_group); Py_INCREF(group); self->main_group = (PyGOptionGroup*) group; Py_INCREF(Py_None); return Py_None; } static PyObject * pyg_option_context_get_main_group(PyGOptionContext *self) { if (self->main_group == NULL) { Py_INCREF(Py_None); return Py_None; } Py_INCREF(self->main_group); return (PyObject*) self->main_group; } static PyObject * pyg_option_context_add_group(PyGOptionContext *self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "group", NULL }; GOptionGroup *g_group; PyObject *group; if (! PyArg_ParseTupleAndKeywords(args, kwargs, "O:GOptionContext.add_group", kwlist, &group)) return NULL; if (PyObject_IsInstance(group, (PyObject*) &PyGOptionGroup_Type) != 1) { PyErr_SetString(PyExc_TypeError, "GOptionContext.add_group expects a GOptionGroup."); return NULL; } g_group = pyglib_option_group_transfer_group(group); if (g_group == NULL) { PyErr_SetString(PyExc_RuntimeError, "Group is already in a OptionContext."); return NULL; } Py_INCREF(group); g_option_context_add_group(self->context, g_group); Py_INCREF(Py_None); return Py_None; } 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 pyg_ptr_richcompare(((PyGOptionContext*)self)->context, ((PyGOptionContext*)other)->context, op); else { Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } } static PyObject * pyg_option_get_context(PyGOptionContext *self) { return PyCapsule_New (self->context, "goption.context", NULL); } static PyMethodDef pyg_option_context_methods[] = { { "parse", (PyCFunction)pyg_option_context_parse, METH_VARARGS | METH_KEYWORDS }, { "set_help_enabled", (PyCFunction)pyg_option_context_set_help_enabled, METH_VARARGS | METH_KEYWORDS }, { "get_help_enabled", (PyCFunction)pyg_option_context_get_help_enabled, METH_NOARGS }, { "set_ignore_unknown_options", (PyCFunction)pyg_option_context_set_ignore_unknown_options, METH_VARARGS | METH_KEYWORDS }, { "get_ignore_unknown_options", (PyCFunction)pyg_option_context_get_ignore_unknown_options, METH_NOARGS }, { "set_main_group", (PyCFunction)pyg_option_context_set_main_group, METH_VARARGS | METH_KEYWORDS }, { "get_main_group", (PyCFunction)pyg_option_context_get_main_group, METH_NOARGS }, { "add_group", (PyCFunction)pyg_option_context_add_group, METH_VARARGS | METH_KEYWORDS }, { "_get_context", (PyCFunction)pyg_option_get_context, METH_NOARGS }, { NULL, NULL, 0 }, }; /** * 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; 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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pygoptioncontext.h0000664000000000000000000000234415074674453016556 0ustar00rootroot/* -*- 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, see . */ #ifndef __PYG_OPTIONCONTEXT_H__ #define __PYG_OPTIONCONTEXT_H__ #include "pygoptiongroup.h" extern PyTypeObject PyGOptionContext_Type; typedef struct { PyObject_HEAD PyGOptionGroup *main_group; GOptionContext *context; } PyGOptionContext; PyObject* pyg_option_context_new(GOptionContext *context); int pygi_option_context_register_types(PyObject *d); #endif /* __PYG_OPTIONCONTEXT_H__ */ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pygoptiongroup.c0000664000000000000000000002160615074674453016223 0ustar00rootroot/* -*- Mode: C; c-basic-offset: 4 -*- * pygobject - Python bindings for the GLib, GObject and GIO * Copyright (C) 2006 Johannes Hoelzl * * pygoptiongroup.c: GOptionContext and GOptionGroup wrapper * * 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 . */ #include #include "pygoptiongroup.h" #include "pygi-error.h" #include "pygi-util.h" PYGI_DEFINE_TYPE("gi._gi.OptionGroup", PyGOptionGroup_Type, PyGOptionGroup) /** * pyg_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 * pyg_option_group_new (GOptionGroup *group) { PyGOptionGroup *self; self = (PyGOptionGroup *)PyObject_NEW(PyGOptionGroup, &PyGOptionGroup_Type); if (self == NULL) return NULL; self->group = group; self->other_owner = TRUE; self->is_in_context = FALSE; return (PyObject *)self; } static gboolean check_if_owned(PyGOptionGroup *self) { if (self->other_owner) { PyErr_SetString(PyExc_ValueError, "The GOptionGroup was not created by " "gi._gi.OptionGroup(), so operation is not possible."); return TRUE; } return FALSE; } static void destroy_g_group(PyGOptionGroup *self) { PyGILState_STATE state; state = PyGILState_Ensure(); self->group = NULL; Py_CLEAR(self->callback); g_slist_foreach(self->strings, (GFunc) g_free, NULL); g_slist_free(self->strings); self->strings = NULL; if (self->is_in_context) { Py_DECREF(self); } PyGILState_Release(state); } static int pyg_option_group_init(PyGOptionGroup *self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "name", "description", "help_description", "callback", NULL }; char *name, *description, *help_description; PyObject *callback; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "zzzO:GOptionGroup.__init__", kwlist, &name, &description, &help_description, &callback)) return -1; self->group = g_option_group_new(name, description, help_description, self, (GDestroyNotify) destroy_g_group); self->other_owner = FALSE; self->is_in_context = FALSE; Py_INCREF(callback); self->callback = callback; return 0; } static void pyg_option_group_dealloc(PyGOptionGroup *self) { if (!self->other_owner && !self->is_in_context) { GOptionGroup *tmp = self->group; self->group = NULL; if (tmp) { G_GNUC_BEGIN_IGNORE_DEPRECATIONS g_option_group_free(tmp); G_GNUC_END_IGNORE_DEPRECATIONS } } PyObject_Del(self); } static gboolean arg_func(const gchar *option_name, const gchar *value, PyGOptionGroup *self, GError **error) { PyObject *ret; PyGILState_STATE state; gboolean no_error; state = PyGILState_Ensure(); if (value == NULL) ret = PyObject_CallFunction(self->callback, "sOO", option_name, Py_None, self); else ret = PyObject_CallFunction(self->callback, "ssO", option_name, value, self); if (ret != NULL) { Py_DECREF(ret); no_error = TRUE; } else no_error = pygi_gerror_exception_check(error) != -1; PyGILState_Release(state); return no_error; } static PyObject * pyg_option_group_add_entries(PyGOptionGroup *self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "entries", NULL }; gssize entry_count, pos; PyObject *entry_tuple, *list; GOptionEntry *entries; if (check_if_owned(self)) return NULL; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O:GOptionGroup.add_entries", kwlist, &list)) return NULL; if (!PyList_Check(list)) { PyErr_SetString(PyExc_TypeError, "GOptionGroup.add_entries expected a list of entries"); return NULL; } entry_count = PyList_Size(list); if (entry_count == -1) { PyErr_SetString(PyExc_TypeError, "GOptionGroup.add_entries expected a list of entries"); return NULL; } entries = g_new0(GOptionEntry, entry_count + 1); for (pos = 0; pos < entry_count; pos++) { gchar *long_name, *description, *arg_description; entry_tuple = PyList_GetItem(list, pos); if (!PyTuple_Check(entry_tuple)) { PyErr_SetString(PyExc_TypeError, "GOptionGroup.add_entries " "expected a list of entries"); g_free(entries); return NULL; } if (!PyArg_ParseTuple(entry_tuple, "scisz", &long_name, &(entries[pos].short_name), &(entries[pos].flags), &description, &arg_description)) { PyErr_SetString(PyExc_TypeError, "GOptionGroup.add_entries " "expected a list of entries"); g_free(entries); return NULL; } long_name = g_strdup(long_name); self->strings = g_slist_prepend(self->strings, long_name); entries[pos].long_name = long_name; description = g_strdup(description); self->strings = g_slist_prepend(self->strings, description); entries[pos].description = description; arg_description = g_strdup(arg_description); self->strings = g_slist_prepend(self->strings, arg_description); entries[pos].arg_description = arg_description; entries[pos].arg = G_OPTION_ARG_CALLBACK; entries[pos].arg_data = arg_func; } g_option_group_add_entries(self->group, entries); g_free(entries); Py_INCREF(Py_None); return Py_None; } static PyObject * pyg_option_group_set_translation_domain(PyGOptionGroup *self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "domain", NULL }; char *domain; if (check_if_owned(self)) return NULL; if (self->group == NULL) { PyErr_SetString(PyExc_RuntimeError, "The corresponding GOptionGroup was already freed, " "probably through the release of GOptionContext"); return NULL; } if (!PyArg_ParseTupleAndKeywords(args, kwargs, "z:GOptionGroup.set_translate_domain", kwlist, &domain)) return NULL; g_option_group_set_translation_domain(self->group, domain); Py_INCREF(Py_None); return Py_None; } static PyObject* pyg_option_group_richcompare(PyObject *self, PyObject *other, int op) { if (Py_TYPE(self) == Py_TYPE(other) && Py_TYPE(self) == &PyGOptionGroup_Type) { return pyg_ptr_richcompare(((PyGOptionGroup*)self)->group, ((PyGOptionGroup*)other)->group, op); } else { Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } } static PyMethodDef pyg_option_group_methods[] = { { "add_entries", (PyCFunction)pyg_option_group_add_entries, METH_VARARGS | METH_KEYWORDS }, { "set_translation_domain", (PyCFunction)pyg_option_group_set_translation_domain, METH_VARARGS | METH_KEYWORDS }, { NULL, NULL, 0 }, }; /** * 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; 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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pygoptiongroup.h0000664000000000000000000000256715074674453016235 0ustar00rootroot/* -*- 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, see . */ #ifndef __PYG_OPTIONGROUP_H__ #define __PYG_OPTIONGROUP_H__ #include #include extern PyTypeObject PyGOptionGroup_Type; typedef struct { PyObject_HEAD GOptionGroup *group; gboolean other_owner, is_in_context; PyObject *callback; GSList *strings; /* all strings added with the entries, are freed on GOptionGroup.destroy() */ } PyGOptionGroup; PyObject* pyg_option_group_new(GOptionGroup *group); int pygi_option_group_register_types(PyObject *d); #endif /* __PYG_OPTIONGROUP_H__ */ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pygpointer.c0000664000000000000000000001360215074674453015313 0ustar00rootroot/* -*- Mode: C; c-basic-offset: 4 -*- * pygtk- Python bindings for the GTK toolkit. * Copyright (C) 1998-2003 James Henstridge * * pygpointer.c: wrapper for GPointer * * 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 . */ #include #include #include #include "pygpointer.h" #include "pygi-type.h" #include "pygi-type.h" #include "pygi-util.h" GQuark pygpointer_class_key; PYGI_DEFINE_TYPE("gobject.GPointer", PyGPointer_Type, PyGPointer); static void pyg_pointer_dealloc(PyGPointer *self) { Py_TYPE(self)->tp_free((PyObject *)self); } static PyObject* pyg_pointer_richcompare(PyObject *self, PyObject *other, int op) { if (Py_TYPE(self) == Py_TYPE(other)) return pyg_ptr_richcompare (pyg_pointer_get_ptr (self), pyg_pointer_get_ptr (other), op); else { Py_INCREF(Py_NotImplemented); return Py_NotImplemented; } } static Py_hash_t pyg_pointer_hash(PyGPointer *self) { return (Py_hash_t)(gintptr)(pyg_pointer_get_ptr (self)); } static PyObject * pyg_pointer_repr(PyGPointer *self) { gchar buf[128]; 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 pyg_pointer_init(PyGPointer *self, PyObject *args, PyObject *kwargs) { gchar buf[512]; if (!PyArg_ParseTuple(args, ":GPointer.__init__")) return -1; pyg_pointer_set_ptr (self, NULL); self->gtype = 0; g_snprintf(buf, sizeof(buf), "%s can not be constructed", Py_TYPE(self)->tp_name); PyErr_SetString(PyExc_NotImplementedError, buf); return -1; } static void pyg_pointer_free(PyObject *op) { PyObject_FREE(op); } /** * pyg_register_pointer: * @dict: the module dictionary to store the wrapper class. * @class_name: the Python name for the wrapper class. * @pointer_type: the GType of the pointer type being wrapped. * @type: the wrapper class. * * Registers a wrapper for a pointer type. The wrapper class will be * a subclass of gobject.GPointer, and a reference to the wrapper * class will be stored in the provided module dictionary. */ void pyg_register_pointer(PyObject *dict, const gchar *class_name, GType pointer_type, PyTypeObject *type) { PyObject *o; g_return_if_fail(dict != NULL); g_return_if_fail(class_name != NULL); g_return_if_fail(pointer_type != 0); if (!type->tp_dealloc) type->tp_dealloc = (destructor)pyg_pointer_dealloc; Py_SET_TYPE(type, &PyType_Type); g_assert (Py_TYPE (&PyGPointer_Type) != NULL); type->tp_base = &PyGPointer_Type; if (PyType_Ready(type) < 0) { g_warning("could not get type `%s' ready", type->tp_name); return; } PyDict_SetItemString(type->tp_dict, "__gtype__", o=pyg_type_wrapper_new(pointer_type)); Py_DECREF(o); g_type_set_qdata(pointer_type, pygpointer_class_key, type); PyDict_SetItemString(dict, (char *)class_name, (PyObject *)type); } /** * pyg_pointer_new: * @pointer_type: the GType of the pointer value. * @pointer: the pointer value. * * Creates a wrapper for a pointer value. Since G_TYPE_POINTER types * don't register any information about how to copy/free them, there * is no guarantee that the pointer will remain valid, and there is * nothing registered to release the pointer when the pointer goes out * of scope. This is why we don't recommend people use these types. * * Returns: the boxed wrapper. */ PyObject * pyg_pointer_new(GType pointer_type, gpointer pointer) { PyGILState_STATE state; PyGPointer *self; PyTypeObject *tp; g_return_val_if_fail(pointer_type != 0, NULL); state = PyGILState_Ensure(); if (!pointer) { Py_INCREF(Py_None); PyGILState_Release(state); return Py_None; } tp = g_type_get_qdata(pointer_type, pygpointer_class_key); if (!tp) tp = (PyTypeObject *)pygi_type_import_by_g_type(pointer_type); if (!tp) tp = (PyTypeObject *)&PyGPointer_Type; /* fallback */ self = PyObject_NEW(PyGPointer, tp); PyGILState_Release(state); if (self == NULL) return NULL; pyg_pointer_set_ptr (self, pointer); self->gtype = pointer_type; return (PyObject *)self; } /** * 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; PyGPointer_Type.tp_richcompare = pyg_pointer_richcompare; PyGPointer_Type.tp_repr = (reprfunc)pyg_pointer_repr; PyGPointer_Type.tp_hash = (hashfunc)pyg_pointer_hash; 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; 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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pygpointer.h0000664000000000000000000000244215074674453015320 0ustar00rootroot/* -*- 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 . */ #ifndef __PYGOBJECT_POINTER_H__ #define __PYGOBJECT_POINTER_H__ #include 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__ */ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pygspawn.c0000664000000000000000000002077315074674453014772 0ustar00rootroot/* -*- Mode: C; c-basic-offset: 4 -*- * pyglib - Python bindings for GLib toolkit. * Copyright (C) 1998-2003 James Henstridge * 2004-2008 Johan Dahlin * * pygspawn.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, see . */ #include #include #include "pygi-util.h" #include "pygi-basictype.h" #include "pygspawn.h" #include "pygi-error.h" struct _PyGChildSetupData { PyObject *func; PyObject *data; }; typedef struct { PyLongObject obj; /* * This exists for two reasons: * 1. We must only close once (ideally we would not have "close" in python) * 2. In PyPy we cannot use PyLong_AsLong during free */ GPid unclosed; } PyGPid; PYGI_DEFINE_TYPE("gi._gi.Pid", PyGPid_Type, PyGPid) static PyObject * pyg_pid_close(PyObject *self, PyObject *args, PyObject *kwargs) { PyGPid* gpid = (PyGPid*) self; if (gpid->unclosed) g_spawn_close_pid(gpid->unclosed); #ifdef G_OS_WIN32 gpid->unclosed = NULL; #else gpid->unclosed = 0; #endif Py_INCREF(Py_None); return Py_None; } static PyMethodDef pyg_pid_methods[] = { { "close", (PyCFunction)pyg_pid_close, METH_NOARGS }, { NULL, NULL, 0 } }; static void pyg_pid_free(PyObject *self) { PyGPid* gpid = (PyGPid*) self; if (gpid->unclosed) g_spawn_close_pid(gpid->unclosed); PyLong_Type.tp_free((void *) self); } static int pyg_pid_tp_init(PyObject *self, PyObject *args, PyObject *kwargs) { PyErr_SetString(PyExc_TypeError, "gi._gi.Pid cannot be manually instantiated"); return -1; } PyObject * pyg_pid_new(GPid 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 _pyg_spawn_async_callback(gpointer user_data) { struct _PyGChildSetupData *data; PyObject *retval; PyGILState_STATE gil; data = (struct _PyGChildSetupData *) user_data; gil = PyGILState_Ensure(); if (data->data) retval = PyObject_CallFunction(data->func, "O", data->data); else retval = PyObject_CallFunction(data->func, NULL); if (retval) Py_DECREF(retval); else PyErr_Print(); Py_DECREF(data->func); Py_XDECREF(data->data); g_slice_free(struct _PyGChildSetupData, data); PyGILState_Release(gil); } PyObject * pyglib_spawn_async(PyObject *object, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "argv", "envp", "working_directory", "flags", "child_setup", "user_data", "standard_input", "standard_output", "standard_error", NULL }; PyObject *pyargv, *pyenvp = NULL; char **argv, **envp = NULL; PyObject *func = Py_None, *user_data = NULL; char *working_directory = NULL; int flags = 0, _stdin = -1, _stdout = -1, _stderr = -1; PyObject *pystdin = NULL, *pystdout = NULL, *pystderr = NULL; gint *standard_input, *standard_output, *standard_error; struct _PyGChildSetupData *callback_data = NULL; GError *error = NULL; GPid child_pid = 0; Py_ssize_t len, i; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O|OsiOOOOO:gi._gi.spawn_async", kwlist, &pyargv, &pyenvp, &working_directory, &flags, &func, &user_data, &pystdin, &pystdout, &pystderr)) return NULL; if (pystdin && PyObject_IsTrue(pystdin)) standard_input = &_stdin; else standard_input = NULL; if (pystdout && PyObject_IsTrue(pystdout)) standard_output = &_stdout; else standard_output = NULL; if (pystderr && PyObject_IsTrue(pystderr)) standard_error = &_stderr; else standard_error = NULL; /* parse argv */ if (!PySequence_Check(pyargv)) { PyErr_SetString(PyExc_TypeError, "gi._gi.spawn_async: " "first argument must be a sequence of strings"); return NULL; } len = PySequence_Length(pyargv); argv = g_new0(char *, len + 1); for (i = 0; i < len; ++i) { PyObject *tmp = PySequence_ITEM(pyargv, i); if (tmp == NULL || !PyUnicode_Check (tmp)) { PyErr_SetString(PyExc_TypeError, "gi._gi.spawn_async: " "first argument must be a sequence of strings"); g_free(argv); Py_XDECREF(tmp); return NULL; } argv[i] = PyUnicode_AsUTF8 (tmp); Py_DECREF(tmp); } /* parse envp */ if (pyenvp) { if (!PySequence_Check(pyenvp)) { PyErr_SetString(PyExc_TypeError, "gi._gi.spawn_async: " "second argument must be a sequence of strings"); g_free(argv); return NULL; } len = PySequence_Length(pyenvp); envp = g_new0(char *, len + 1); for (i = 0; i < len; ++i) { PyObject *tmp = PySequence_ITEM(pyenvp, i); if (tmp == NULL || !PyUnicode_Check (tmp)) { PyErr_SetString(PyExc_TypeError, "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] = PyUnicode_AsUTF8 (tmp); Py_DECREF(tmp); } } if (func != Py_None) { if (!PyCallable_Check(func)) { PyErr_SetString(PyExc_TypeError, "child_setup parameter must be callable or None"); g_free(argv); if (envp) g_free(envp); return NULL; } callback_data = g_slice_new(struct _PyGChildSetupData); callback_data->func = func; callback_data->data = user_data; Py_INCREF(callback_data->func); if (callback_data->data) Py_INCREF(callback_data->data); } if (!g_spawn_async_with_pipes(working_directory, argv, envp, flags, (func != Py_None ? _pyg_spawn_async_callback : NULL), callback_data, &child_pid, standard_input, standard_output, standard_error, &error)) { g_free(argv); if (envp) g_free(envp); if (callback_data) { Py_DECREF(callback_data->func); Py_XDECREF(callback_data->data); g_slice_free(struct _PyGChildSetupData, callback_data); } pygi_error_check(&error); return NULL; } g_free(argv); if (envp) g_free(envp); if (standard_input) pystdin = pygi_gint_to_py(*standard_input); else { Py_INCREF(Py_None); pystdin = Py_None; } if (standard_output) pystdout = pygi_gint_to_py(*standard_output); else { Py_INCREF(Py_None); pystdout = Py_None; } if (standard_error) pystderr = pygi_gint_to_py(*standard_error); else { Py_INCREF(Py_None); pystderr = Py_None; } return Py_BuildValue("NNNN", pyg_pid_new(child_pid), pystdin, pystdout, pystderr); } /** * Returns 0 on success, or -1 and sets an exception. */ int pygi_spawn_register_types(PyObject *d) { 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 = 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; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pygspawn.h0000664000000000000000000000207115074674453014766 0ustar00rootroot/* -*- 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, see . */ #ifndef __PYG_PID_H__ #define __PYG_PID_H__ PyObject * pyg_pid_new(GPid pid); int pygi_spawn_register_types(PyObject *d); PyObject * pyglib_spawn_async(PyObject *self, PyObject *args, PyObject *kwargs); #endif /* __PYG_PID_H__ */ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/pygtkcompat.py0000664000000000000000000000132715074674453015664 0ustar00rootrootimport warnings from gi import PyGIDeprecationWarning warnings.warn('gi.pygtkcompat is being deprecated in favor of using "pygtkcompat" directly.', PyGIDeprecationWarning) # pyflakes.ignore from pygtkcompat import (enable, enable_gtk, enable_vte, enable_poppler, enable_webkit, enable_gudev, enable_gst, enable_goocanvas) __all__ = ['enable', 'enable_gtk', 'enable_vte', 'enable_poppler', 'enable_webkit', 'enable_gudev', 'enable_gst', 'enable_goocanvas'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/repository/__init__.py0000664000000000000000000000175215074674453017302 0ustar00rootroot# -*- Mode: Python; py-indent-offset: 4 -*- # vim: tabstop=4 shiftwidth=4 expandtab # # Copyright (C) 2009 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 St, Fifth Floor, Boston, MA 02110-1301 # USA import sys from ..importer import DynamicImporter sys.meta_path.append(DynamicImporter('gi.repository')) del DynamicImporter del sys ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/repository/meson.build0000664000000000000000000000016515074674453017330 0ustar00rootrootpython_sources = ['__init__.py'] python.install_sources(python_sources, subdir : join_paths('gi', 'repository') ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/gi/types.py0000664000000000000000000003234715074674453014474 0ustar00rootroot# -*- Mode: Python; py-indent-offset: 4 -*- # vim: tabstop=4 shiftwidth=4 expandtab # # Copyright (C) 2005-2009 Johan Dahlin # # types.py: base types for introspected items. # # 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 re from ._constants import TYPE_INVALID from .docstring import generate_doc_string from ._gi import \ InterfaceInfo, \ ObjectInfo, \ StructInfo, \ VFuncInfo, \ register_interface_info, \ hook_up_vfunc_implementation, \ GInterface from . import _gi StructInfo, GInterface # pyflakes from . import _propertyhelper as propertyhelper from . import _signalhelper as signalhelper 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): def _setup_methods(cls): 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('-', '_') setattr(cls, name, property(field_info.get_value, field_info.set_value)) def _setup_constants(cls): for constant_info in cls.__info__.get_constants(): name = constant_info.get_name() value = constant_info.get_value() setattr(cls, name, value) def _setup_vfuncs(cls): for vfunc_name, py_vfunc in cls.__dict__.items(): 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 # classes may shadow vfuncs from classes higher in the hierarchy. vfunc_info = None for base in cls.__mro__: method = getattr(base, vfunc_name, None) if method is not None and isinstance(method, VFuncInfo): 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 # on the object. Instead we have to search through # InterfaceInfo.get_vfuncs(). Note that the infos returned by # get_vfuncs() use the C vfunc name (ie. there is no "do_" prefix). if vfunc_info is None: vfunc_info = find_vfunc_info_in_interface(cls.__bases__, vfunc_name[len("do_"):]) if vfunc_info is not None: # 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. 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) def _setup_native_vfuncs(cls): # Only InterfaceInfo and ObjectInfo have the get_vfuncs() method. # We skip InterfaceInfo because interfaces have no implementations for vfuncs. # Also check if __info__ in __dict__, not hasattr('__info__', ...) # because we do not want to accidentally retrieve __info__ from a base class. class_info = cls.__dict__.get('__info__') if class_info is None or not isinstance(class_info, ObjectInfo): return # Special case skipping of vfuncs for GObject.Object because they will break # the static bindings which will try to use them. if cls.__module__ == 'gi.repository.GObject' and cls.__name__ == 'Object': return for vfunc_info in class_info.get_vfuncs(): name = 'do_%s' % vfunc_info.__name__ setattr(cls, name, vfunc_info) def find_vfunc_info_in_interface(bases, vfunc_name): for base in bases: # All wrapped interfaces inherit from GInterface. # This can be seen in IntrospectionModule.__getattr__() in module.py. # We do not need to search regular classes here, only wrapped interfaces. # We also skip GInterface, because it is not wrapped and has no __info__ attr. # Skip bases without __info__ (static _gi.GObject) if base is GInterface or\ not issubclass(base, GInterface) or\ not hasattr(base, '__info__'): continue # Only look at this classes vfuncs if it is an interface. if isinstance(base.__info__, InterfaceInfo): for vfunc in base.__info__.get_vfuncs(): if vfunc.get_name() == vfunc_name: return vfunc # Recurse into the parent classes vfunc = find_vfunc_info_in_interface(base.__bases__, vfunc_name) if vfunc is not None: return vfunc return None def find_vfunc_conflict_in_bases(vfunc, bases): for klass in bases: if not hasattr(klass, '__info__') or \ not hasattr(klass.__info__, 'get_vfuncs'): continue vfuncs = klass.__info__.get_vfuncs() vfunc_name = vfunc.get_name() for v in vfuncs: if v.get_name() == vfunc_name and v != vfunc: return klass aklass = find_vfunc_conflict_in_bases(vfunc, klass.__bases__) if aklass is not None: return aklass return None class _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 if cls.__module__ == 'gi.repository.' + cls.__info__.get_namespace(): is_gi_defined = True is_python_defined = False if not is_gi_defined and cls.__module__ != GObjectMeta.__module__: is_python_defined = True 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() if isinstance(cls.__info__, ObjectInfo): cls._setup_fields() elif isinstance(cls.__info__, InterfaceInfo): register_interface_info(cls.__info__.get_g_type()) 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 interface considerations. We override Python's MRO calculation to account for the fact that GObject classes are not affected by the diamond problem: http://en.wikipedia.org/wiki/Diamond_problem Based on http://www.python.org/download/releases/2.3/mro/ """ # TODO: If this turns out being too slow, consider using generators bases = [] bases_of_subclasses = [[C]] if C.__bases__: for base in C.__bases__: # Python causes MRO's to be calculated starting with the lowest # base class and working towards the descendant, storing the result # 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. bases_of_subclasses += [list(base.__mro__)] bases_of_subclasses += [list(C.__bases__)] while bases_of_subclasses: for subclass_bases in bases_of_subclasses: candidate = subclass_bases[0] not_head = [s for s in bases_of_subclasses if candidate in s[1:]] if not_head and GInterface not in candidate.__bases__: candidate = None # conflict, reject candidate else: break if candidate is None: raise TypeError('Cannot create a consistent method resolution ' 'order (MRO)') bases.append(candidate) for subclass_bases in bases_of_subclasses[:]: # remove candidate if subclass_bases and subclass_bases[0] == candidate: del subclass_bases[0] if not subclass_bases: bases_of_subclasses.remove(subclass_bases) 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_) # Avoid touching anything else than the base class. g_type = cls.__info__.get_g_type() if g_type != TYPE_INVALID and g_type.pytype is not None: return cls._setup_fields() cls._setup_methods() for method_info in cls.__info__.get_methods(): if method_info.is_constructor() and \ method_info.__name__ == 'new' and \ (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__) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/meson.build0000664000000000000000000001476715074674453014527 0ustar00rootrootproject( 'pygobject', 'c', version : '3.50.2', meson_version : '>= 0.64.0', default_options : ['warning_level=1', 'buildtype=debugoptimized'] ) pygobject_version = meson.project_version() version_arr = pygobject_version.split('.') pygobject_version_major = version_arr[0].to_int() pygobject_version_minor = version_arr[1].to_int() pygobject_version_micro = version_arr[2].to_int() platform_version = '@0@.0'.format(pygobject_version_major) pymod = import('python') python = pymod.find_installation(get_option('python'), pure: false) if python.language_version().version_compare('< 3.9') error('Requires Python >= 3.9') endif python_dep = python.dependency() glib_version_req = '>= 2.64.0' gi_version_req = '>= 1.64.0' pycairo_version_req = '>= 1.16.0' libffi_version_req = '>= 3.0' gi_dep = dependency('gobject-introspection-1.0', version : gi_version_req, fallback: ['gobject-introspection', 'girepo_dep']) glib_dep = dependency('glib-2.0', version : glib_version_req, fallback: ['glib', 'libglib_dep']) gobject_dep = dependency('gobject-2.0', version : glib_version_req, fallback: ['glib', 'libgobject_dep']) gio_dep = dependency('gio-2.0', version : glib_version_req, fallback: ['glib', 'libgio_dep']) gmodule_dep = dependency('gmodule-2.0', version : glib_version_req, fallback: ['glib', 'libgmodule_dep']) ffi_dep = dependency('libffi', version : libffi_version_req, fallback : ['libffi', 'ffi_dep']) with_pycairo = get_option('pycairo') cc = meson.get_compiler('c') if not with_pycairo.disabled() cairo_dep = dependency('cairo', required: with_pycairo.enabled() and cc.get_id() != 'msvc') cairo_gobject_dep = dependency('cairo-gobject', required: with_pycairo.enabled() and cc.get_id() != 'msvc') if cc.get_id() == 'msvc' and (not cairo_gobject_dep.found() or not cairo_dep.found()) if cc.has_header('cairo.h') and cc.has_header ('cairo-gobject.h') cairo_dep = cc.find_library ('cairo', required: with_pycairo) cairo_gobject_dep = cc.find_library ('cairo-gobject', required: with_pycairo) endif endif # Find pycairo with target Python (TODO: extract version as well, see setup.py) r = run_command( python, '-c', ''' import pathlib, sys from importlib.util import find_spec spec = find_spec("cairo") if spec is None: sys.stderr.write("cairo module spec not found") sys.exit(1) src_path = pathlib.Path(r"@0@") inc_path = pathlib.Path(spec.origin).parent / "include" try: sys.stdout.write(str(inc_path.relative_to(src_path))) except ValueError: sys.stdout.write(str(inc_path)) '''.format(meson.current_source_dir()), check: false, ) if r.returncode() == 0 message('Found pycairo with target Python: ' + r.stdout()) pycairo_inc_dir = include_directories(r.stdout()) pycairo_dep = declare_dependency( include_directories: pycairo_inc_dir, ) else message('pycairo not found via target Python, falling back to pkg-config (@0@)'.format(r.stderr())) # Find pycairo with pkg-config pycairo_dep = dependency( 'py3cairo', version: pycairo_version_req, fallback: ['pycairo', 'pycairo_dep'], default_options: ['python=' + get_option('python')], required: with_pycairo, ) endif else cairo_dep = dependency('', required: false) pycairo_dep = dependency('', required: false) endif main_c_args = [] if cc.get_id() == 'msvc' main_c_args += [ '-FImsvc_recommended_pragmas.h' ] else main_c_args += [ '-Wall', '-Warray-bounds', '-Wcast-align', '-Wduplicated-branches', '-Wextra', '-Wformat=2', '-Wformat-nonliteral', '-Wformat-security', '-Wimplicit-function-declaration', '-Winit-self', '-Wjump-misses-init', '-Wlogical-op', '-Wmissing-declarations', '-Wmissing-format-attribute', '-Wmissing-include-dirs', '-Wmissing-noreturn', '-Wmissing-prototypes', '-Wnested-externs', '-Wnull-dereference', '-Wold-style-definition', '-Wpacked', '-Wpointer-arith', '-Wrestrict', '-Wreturn-type', '-Wshadow', '-Wsign-compare', '-Wstrict-aliasing', '-Wstrict-prototypes', '-Wswitch-default', '-Wundef', '-Wunused-but-set-variable', '-Wwrite-strings', ] main_c_args += [ '-Wno-incompatible-pointer-types-discards-qualifiers', '-Wno-missing-field-initializers', '-Wno-unused-parameter', '-Wno-discarded-qualifiers', '-Wno-sign-conversion', '-Wno-cast-function-type', '-Wno-int-conversion', ] main_c_args += [ '-fno-strict-aliasing', '-fvisibility=hidden', ] main_c_args = cc.get_supported_arguments(main_c_args) endif pyext_c_args = ['-DPY_SSIZE_T_CLEAN'] cdata = configuration_data() cdata.set('PYGOBJECT_MAJOR_VERSION', pygobject_version_major) cdata.set('PYGOBJECT_MINOR_VERSION', pygobject_version_minor) cdata.set('PYGOBJECT_MICRO_VERSION', pygobject_version_micro) if gio_dep.version().version_compare('< 2.67.4') cdata.set('g_memdup2(ptr,sz)', '(G_LIKELY(((guint64)(sz)) < G_MAXUINT)) ? g_memdup(ptr,sz) : (g_abort(),NULL)') endif configure_file(output : 'config.h', configuration : cdata) pkgconf = configuration_data() pkgconf.set('prefix', join_paths(get_option('prefix'))) pkgconf.set('exec_prefix', '${prefix}') pkgconf.set('includedir', join_paths('${prefix}', get_option('includedir'))) pkgconf.set('datarootdir', join_paths('${prefix}', get_option('datadir'))) pkgconf.set('datadir', '${datarootdir}') pkgconf.set('VERSION', pygobject_version) for_wheel = get_option('wheel') if not for_wheel pkg_install_dir = '@0@/pkgconfig'.format(get_option('libdir')) configure_file(input : 'pygobject-@0@.pc.in'.format(platform_version), output : 'pygobject-@0@.pc'.format(platform_version), configuration : pkgconf, install_dir : pkg_install_dir) if pygobject_version_minor.is_odd() py_version = '@0@.dev0'.format(pygobject_version) else py_version = pygobject_version endif pkginfo_conf = configuration_data() pkginfo_conf.set('VERSION', py_version) configure_file(input : 'METADATA.in', output : 'METADATA', configuration : pkginfo_conf, install_dir : python.get_install_dir(pure : false) / 'PyGObject-@0@.dist-info'.format(py_version)) endif pygobject_dep = declare_dependency( include_directories: include_directories('gi'), dependencies: [gobject_dep, ffi_dep], version: meson.project_version(), ) subdir('gi') subdir('pygtkcompat') with_tests = get_option('tests') if with_tests subdir('tests') endif devenv = environment() devenv.prepend('PYTHONPATH', [ meson.current_source_dir(), meson.current_build_dir(), ]) meson.add_devenv(devenv) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/meson_options.txt0000664000000000000000000000050615074674453016004 0ustar00rootrootoption('python', type : 'string', value : 'python3') option('pycairo', type : 'feature', value : 'auto', description : 'build with pycairo integration') option('tests', type : 'boolean', value : true, description : 'build unit tests') option('wheel', type : 'boolean', value : false, description : 'build for a Python wheel') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/pygobject-3.0.pc.in0000664000000000000000000000130115074674453015556 0ustar00rootrootprefix=@prefix@ exec_prefix=@exec_prefix@ includedir=@includedir@ datarootdir=@datarootdir@ datadir=@datadir@ # you can use the --variable=pygobjectincludedir argument to # pkg-config to get this value. You might want to use this to # install additional headers. pygobjectincludedir=${includedir}/pygobject-3.0 Name: PyGObject Description: Python bindings for GObject Requires: gobject-2.0 Requires.private: libffi Version: @VERSION@ Cflags: -I${pygobjectincludedir} # overridesdir has now moved to the gi module # third parties can access it in a python script: # # import gi # installdir = gi._overridesdir # # the version of python you run the script from # will determine the actual overrides path ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/pygobject.doap0000664000000000000000000000506115074674453015203 0ustar00rootroot PyGObject Python bindings for GObject Introspection GObject is a object system used by GTK, GStreamer and other libraries. PyGObject provides a convenient wrapper for use in Python programs when accessing GObject libraries. Like the GObject library itself PyGObject is licensed under the GNU LGPL, so is suitable for use in both free software and proprietary applications. It is already in use in many applications ranging from small single purpose scripts up to large full featured applications. PyGObject now dynamically accesses any GObject libraries that uses GObject Introspection. It replaces the need for separate modules such as PyGTK, GIO and python-gnome to build a full GNOME 3.0 application. Once new functionality is added to gobject library it is instantly available as a Python API without the need for intermediate Python glue. C Python Ignacio Casal Quinteiro icq Christoph Reiter creiter Arjan Molenaar amolenaar Dan Yeaw danyeaw ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/pygtkcompat/__init__.py0000664000000000000000000000104315074674453017017 0ustar00rootroot # pyflakes.ignore from .pygtkcompat import (enable, enable_gtk, enable_vte, enable_poppler, enable_webkit, enable_gudev, enable_gst, enable_goocanvas) __all__ = ['enable', 'enable_gtk', 'enable_vte', 'enable_poppler', 'enable_webkit', 'enable_gudev', 'enable_gst', 'enable_goocanvas'] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/pygtkcompat/generictreemodel.py0000664000000000000000000003403515074674453020604 0ustar00rootroot# -*- Mode: Python; py-indent-offset: 4 -*- # generictreemodel - GenericTreeModel implementation for pygtk compatibility. # Copyright (C) 2013 Simon Feltman # # generictreemodel.py: GenericTreeModel implementation for pygtk compatibility # # 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 . # System import sys import random import collections import ctypes import platform import warnings # GObject import gi from gi.repository import GObject from gi.repository import Gtk class _CTreeIter(ctypes.Structure): _fields_ = [('stamp', ctypes.c_int), ('user_data', ctypes.c_void_p), ('user_data2', ctypes.c_void_p), ('user_data3', ctypes.c_void_p)] @classmethod def from_iter(cls, iter): offset = sys.getsizeof(object()) # size of PyObject_HEAD return ctypes.POINTER(cls).from_address(id(iter) + offset) if platform.python_implementation() == "PyPy": def _get_user_data_as_pyobject(iter): raise NotImplementedError("Not yet supported under PyPy") else: def _get_user_data_as_pyobject(iter): citer = _CTreeIter.from_iter(iter) return ctypes.cast(citer.contents.user_data, ctypes.py_object).value def handle_exception(default_return): """Returns a function which can act as a decorator for wrapping exceptions and returning "default_return" upon an exception being thrown. This is used to wrap Gtk.TreeModel "do_" method implementations so we can return a proper value from the override upon an exception occurring with client code implemented by the "on_" methods. """ def decorator(func): def wrapped_func(*args, **kargs): try: return func(*args, **kargs) except: # Use excepthook directly to avoid any printing to the screen # if someone installed an except hook. sys.excepthook(*sys.exc_info()) return default_return return wrapped_func return decorator class GenericTreeModel(GObject.GObject, Gtk.TreeModel): """A base implementation of a Gtk.TreeModel for python. The GenericTreeModel eases implementing the Gtk.TreeModel interface in Python. The class can be subclassed to provide a TreeModel implementation which works directly with Python objects instead of iterators. All of the on_* methods should be overridden by subclasses to provide the underlying implementation a way to access custom model data. For the purposes of this API, all custom model data supplied or handed back through the overridable API will use the argument names: node, parent, and child in regards to user data python objects. The create_tree_iter, set_user_data, invalidate_iters, iter_is_valid methods are available to help manage Gtk.TreeIter objects and their Python object references. GenericTreeModel manages a pool of user data nodes that have been used with iters. This pool stores a references to user data nodes as a dictionary value with the key being the integer id of the data. This id is what the Gtk.TreeIter objects use to reference data in the pool. References will be removed from the pool when the model is deleted or explicitly by using the optional "node" argument to the "row_deleted" method when notifying the model of row deletion. """ leak_references = GObject.Property(default=True, type=bool, blurb="If True, strong references to user data attached to iters are " "stored in a dictionary pool (default). Otherwise the user data is " "stored as a raw pointer to a python object without a reference.") # # Methods # def __init__(self): """Initialize. Make sure to call this from derived classes if overridden.""" warnings.warn("pygtkcompat is deprecated, see https://pygobject.gnome.org for migration instructions", gi.PyGIDeprecationWarning) super(GenericTreeModel, self).__init__() self.stamp = 0 #: Dictionary of (id(user_data): user_data), used when leak-references=False self._held_refs = dict() # Set initial stamp self.invalidate_iters() def iter_depth_first(self): """Depth-first iteration of the entire TreeModel yielding the python nodes.""" stack = collections.deque([None]) while stack: it = stack.popleft() if it is not None: yield self.get_user_data(it) children = [self.iter_nth_child(it, i) for i in range(self.iter_n_children(it))] stack.extendleft(reversed(children)) def invalidate_iter(self, iter): """Clear user data and its reference from the iter and this model.""" iter.stamp = 0 if iter.user_data: if iter.user_data in self._held_refs: del self._held_refs[iter.user_data] iter.user_data = None def invalidate_iters(self): """ This method invalidates all TreeIter objects associated with this custom tree model and frees their locally pooled references. """ self.stamp = random.randint(-2147483648, 2147483647) self._held_refs.clear() def iter_is_valid(self, iter): """ :Returns: True if the gtk.TreeIter specified by iter is valid for the custom tree model. """ return iter.stamp == self.stamp def get_user_data(self, iter): """Get the user_data associated with the given TreeIter. GenericTreeModel stores arbitrary Python objects mapped to instances of Gtk.TreeIter. This method allows to retrieve the Python object held by the given iterator. """ if self.leak_references: return self._held_refs[iter.user_data] else: return _get_user_data_as_pyobject(iter) def set_user_data(self, iter, user_data): """Applies user_data and stamp to the given iter. If the models "leak_references" property is set, a reference to the user_data is stored with the model to ensure we don't run into bad memory problems with the TreeIter. """ iter.user_data = id(user_data) if user_data is None: self.invalidate_iter(iter) else: iter.stamp = self.stamp if self.leak_references: self._held_refs[iter.user_data] = user_data def create_tree_iter(self, user_data): """Create a Gtk.TreeIter instance with the given user_data specific for this model. Use this method to create Gtk.TreeIter instance instead of directly calling Gtk.Treeiter(), this will ensure proper reference managment of wrapped used_data. """ iter = Gtk.TreeIter() self.set_user_data(iter, user_data) return iter def _create_tree_iter(self, data): """Internal creation of a (bool, TreeIter) pair for returning directly back to the view interfacing with this model.""" if data is None: return (False, None) else: it = self.create_tree_iter(data) return (True, it) def row_deleted(self, path, node=None): """Notify the model a row has been deleted. Use the node parameter to ensure the user_data reference associated with the path is properly freed by this model. :Parameters: path : Gtk.TreePath Path to the row that has been deleted. node : object Python object used as the node returned from "on_get_iter". This is optional but ensures the model will not leak references to this object. """ super(GenericTreeModel, self).row_deleted(path) node_id = id(node) if node_id in self._held_refs: del self._held_refs[node_id] # # GtkTreeModel Interface Implementation # @handle_exception(0) def do_get_flags(self): """Internal method.""" return self.on_get_flags() @handle_exception(0) def do_get_n_columns(self): """Internal method.""" return self.on_get_n_columns() @handle_exception(GObject.TYPE_INVALID) def do_get_column_type(self, index): """Internal method.""" return self.on_get_column_type(index) @handle_exception((False, None)) def do_get_iter(self, path): """Internal method.""" return self._create_tree_iter(self.on_get_iter(path)) @handle_exception(False) def do_iter_next(self, iter): """Internal method.""" if iter is None: next_data = self.on_iter_next(None) else: next_data = self.on_iter_next(self.get_user_data(iter)) self.set_user_data(iter, next_data) return next_data is not None @handle_exception(None) def do_get_path(self, iter): """Internal method.""" path = self.on_get_path(self.get_user_data(iter)) if path is None: return None else: return Gtk.TreePath(path) @handle_exception(None) def do_get_value(self, iter, column): """Internal method.""" return self.on_get_value(self.get_user_data(iter), column) @handle_exception((False, None)) def do_iter_children(self, parent): """Internal method.""" data = self.get_user_data(parent) if parent else None return self._create_tree_iter(self.on_iter_children(data)) @handle_exception(False) def do_iter_has_child(self, parent): """Internal method.""" return self.on_iter_has_child(self.get_user_data(parent)) @handle_exception(0) def do_iter_n_children(self, iter): """Internal method.""" if iter is None: return self.on_iter_n_children(None) return self.on_iter_n_children(self.get_user_data(iter)) @handle_exception((False, None)) def do_iter_nth_child(self, parent, n): """Internal method.""" if parent is None: data = self.on_iter_nth_child(None, n) else: data = self.on_iter_nth_child(self.get_user_data(parent), n) return self._create_tree_iter(data) @handle_exception((False, None)) def do_iter_parent(self, child): """Internal method.""" return self._create_tree_iter(self.on_iter_parent(self.get_user_data(child))) @handle_exception(None) def do_ref_node(self, iter): self.on_ref_node(self.get_user_data(iter)) @handle_exception(None) def do_unref_node(self, iter): self.on_unref_node(self.get_user_data(iter)) # # Python Subclass Overridables # def on_get_flags(self): """Overridable. :Returns Gtk.TreeModelFlags: The flags for this model. See: Gtk.TreeModelFlags """ raise NotImplementedError def on_get_n_columns(self): """Overridable. :Returns: The number of columns for this model. """ raise NotImplementedError def on_get_column_type(self, index): """Overridable. :Returns: The column type for the given index. """ raise NotImplementedError def on_get_iter(self, path): """Overridable. :Returns: A python object (node) for the given TreePath. """ raise NotImplementedError def on_iter_next(self, node): """Overridable. :Parameters: node : object Node at current level. :Returns: A python object (node) following the given node at the current level. """ raise NotImplementedError def on_get_path(self, node): """Overridable. :Returns: A TreePath for the given node. """ raise NotImplementedError def on_get_value(self, node, column): """Overridable. :Parameters: node : object column : int Column index to get the value from. :Returns: The value of the column for the given node.""" raise NotImplementedError def on_iter_children(self, parent): """Overridable. :Returns: The first child of parent or None if parent has no children. If parent is None, return the first node of the model. """ raise NotImplementedError def on_iter_has_child(self, node): """Overridable. :Returns: True if the given node has children. """ raise NotImplementedError def on_iter_n_children(self, node): """Overridable. :Returns: The number of children for the given node. If node is None, return the number of top level nodes. """ raise NotImplementedError def on_iter_nth_child(self, parent, n): """Overridable. :Parameters: parent : object n : int Index of child within parent. :Returns: The child for the given parent index starting at 0. If parent None, return the top level node corresponding to "n". If "n" is larger then available nodes, return None. """ raise NotImplementedError def on_iter_parent(self, child): """Overridable. :Returns: The parent node of child or None if child is a top level node.""" raise NotImplementedError def on_ref_node(self, node): pass def on_unref_node(self, node): pass ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/pygtkcompat/meson.build0000664000000000000000000000022415074674453017050 0ustar00rootrootpython_sources = [ '__init__.py', 'generictreemodel.py', 'pygtkcompat.py'] python.install_sources(python_sources, subdir : 'pygtkcompat' ) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/pygtkcompat/pygtkcompat.py0000664000000000000000000005050715074674453017633 0ustar00rootroot# -*- Mode: Python; py-indent-offset: 4 -*- # vim: tabstop=4 shiftwidth=4 expandtab # # Copyright (C) 2011-2012 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 St, Fifth Floor, Boston, MA 02110-1301 # USA """ PyGTK compatibility layer. This modules goes a little bit longer to maintain PyGTK compatibility than the normal overrides system. It is recommended to not depend on this layer, but only use it as an intermediate step when porting your application to PyGI. Compatibility might never be 100%, but the aim is to make it possible to run a well behaved PyGTK application mostly unmodified on top of PyGI. """ import sys import warnings from collections import UserList import gi from gi.repository import GObject _patches = [] _module_patches = [] _unset = object() _enabled_registry = {} def _patch(obj, name, new_value): old_value = getattr(obj, name, _unset) setattr(obj, name, new_value) _patches.append((obj, name, old_value)) def _patch_module(name, new_value): old_value = sys.modules.get(name, _unset) sys.modules[name] = new_value _module_patches.append((name, old_value)) def _install_enums(module, dest=None, strip=''): if dest is None: dest = module modname = dest.__name__.rsplit('.', 1)[1].upper() for attr in dir(module): try: obj = getattr(module, attr, None) except: continue try: if issubclass(obj, GObject.GEnum): for value, enum in obj.__enum_values__.items(): name = enum.value_name name = name.replace(modname + '_', '') if strip and name.startswith(strip): name = name[len(strip):] _patch(dest, name, enum) except TypeError: continue try: if issubclass(obj, GObject.GFlags): for value, flag in obj.__flags_values__.items(): try: name = flag.value_names[-1].replace(modname + '_', '') except IndexError: # FIXME: this happens for some large flags which do not # fit into a long on 32 bit systems continue _patch(dest, name, flag) except TypeError: continue def _check_enabled(name, version=None): """Returns True in case it is already enabled""" if name in _enabled_registry: enabled_version = _enabled_registry[name] if enabled_version != version: raise ValueError( "%r already enabled with different version (%r)" % ( name, enabled_version)) return True else: _enabled_registry[name] = version return False def enable(): warnings.warn("pygtkcompat is deprecated, see https://pygobject.gnome.org for migration instructions", gi.PyGIDeprecationWarning) if _check_enabled(""): return # gobject from gi.repository import GLib _patch_module('glib', GLib) # gobject from gi.repository import GObject _patch_module('gobject', GObject) from gi import _propertyhelper _patch_module('gobject.propertyhelper', _propertyhelper) # gio from gi.repository import Gio _patch_module('gio', Gio) def _disable_all(): """Reverse all effects of the enable_xxx() calls except for require_version() calls and imports. """ _enabled_registry.clear() for obj, name, old_value in reversed(_patches): if old_value is _unset: delattr(obj, name) else: # try if deleting is enough (for override proxies) delattr(obj, name) if getattr(obj, name, _unset) is not old_value: setattr(obj, name, old_value) del _patches[:] for name, old_value in reversed(_module_patches): if old_value is _unset: del sys.modules[name] else: sys.modules[name] = old_value del _module_patches[:] def enable_gtk(version='3.0'): if _check_enabled("gtk", version): return if version == "4.0": raise ValueError("version 4.0 not supported") # atk gi.require_version('Atk', '1.0') from gi.repository import Atk _patch_module('atk', Atk) _install_enums(Atk) # pango gi.require_version('Pango', '1.0') from gi.repository import Pango _patch_module('pango', Pango) _install_enums(Pango) # pangocairo gi.require_version('PangoCairo', '1.0') from gi.repository import PangoCairo _patch_module('pangocairo', PangoCairo) # gdk gi.require_version('Gdk', version) gi.require_version('GdkPixbuf', '2.0') from gi.repository import Gdk from gi.repository import GdkPixbuf _patch_module('gtk.gdk', Gdk) _install_enums(Gdk) _install_enums(GdkPixbuf, dest=Gdk) _patch(Gdk, "_2BUTTON_PRESS", 5) _patch(Gdk, "BUTTON_PRESS", 4) _patch(Gdk, "screen_get_default", Gdk.Screen.get_default) _patch(Gdk, "Pixbuf", GdkPixbuf.Pixbuf) _patch(Gdk, "PixbufLoader", GdkPixbuf.PixbufLoader.new_with_type) _patch(Gdk, "pixbuf_new_from_data", GdkPixbuf.Pixbuf.new_from_data) _patch(Gdk, "pixbuf_new_from_file", GdkPixbuf.Pixbuf.new_from_file) _patch(Gdk, "pixbuf_new_from_file_at_scale", GdkPixbuf.Pixbuf.new_from_file_at_scale) _patch(Gdk, "pixbuf_new_from_file_at_size", GdkPixbuf.Pixbuf.new_from_file_at_size) _patch(Gdk, "pixbuf_new_from_inline", GdkPixbuf.Pixbuf.new_from_inline) _patch(Gdk, "pixbuf_new_from_stream", GdkPixbuf.Pixbuf.new_from_stream) _patch(Gdk, "pixbuf_new_from_stream_at_scale", GdkPixbuf.Pixbuf.new_from_stream_at_scale) _patch(Gdk, "pixbuf_new_from_xpm_data", GdkPixbuf.Pixbuf.new_from_xpm_data) _patch(Gdk, "pixbuf_get_file_info", GdkPixbuf.Pixbuf.get_file_info) orig_get_formats = GdkPixbuf.Pixbuf.get_formats def get_formats(): formats = orig_get_formats() result = [] def make_dict(format_): result = {} result['description'] = format_.get_description() result['name'] = format_.get_name() result['mime_types'] = format_.get_mime_types() result['extensions'] = format_.get_extensions() return result for format_ in formats: result.append(make_dict(format_)) return result _patch(Gdk, "pixbuf_get_formats", get_formats) orig_get_origin = Gdk.Window.get_origin def get_origin(self): return orig_get_origin(self)[1:] _patch(Gdk.Window, "get_origin", get_origin) _patch(Gdk, "screen_width", Gdk.Screen.width) _patch(Gdk, "screen_height", Gdk.Screen.height) orig_gdk_window_get_geometry = Gdk.Window.get_geometry def gdk_window_get_geometry(window): return orig_gdk_window_get_geometry(window) + (window.get_visual().get_best_depth(),) _patch(Gdk.Window, "get_geometry", gdk_window_get_geometry) # gtk gi.require_version('Gtk', version) from gi.repository import Gtk _patch_module('gtk', Gtk) _patch(Gtk, "gdk", Gdk) _patch(Gtk, "pygtk_version", (2, 99, 0)) _patch(Gtk, "gtk_version", (Gtk.MAJOR_VERSION, Gtk.MINOR_VERSION, Gtk.MICRO_VERSION)) _install_enums(Gtk) # Action def set_tool_item_type(menuaction, gtype): warnings.warn('set_tool_item_type() is not supported', gi.PyGIDeprecationWarning, stacklevel=2) _patch(Gtk.Action, "set_tool_item_type", classmethod(set_tool_item_type)) # Alignment orig_Alignment = Gtk.Alignment class Alignment(orig_Alignment): def __init__(self, xalign=0.0, yalign=0.0, xscale=0.0, yscale=0.0): orig_Alignment.__init__(self) self.props.xalign = xalign self.props.yalign = yalign self.props.xscale = xscale self.props.yscale = yscale _patch(Gtk, "Alignment", Alignment) # Box orig_pack_end = Gtk.Box.pack_end def pack_end(self, child, expand=True, fill=True, padding=0): orig_pack_end(self, child, expand, fill, padding) _patch(Gtk.Box, "pack_end", pack_end) orig_pack_start = Gtk.Box.pack_start def pack_start(self, child, expand=True, fill=True, padding=0): orig_pack_start(self, child, expand, fill, padding) _patch(Gtk.Box, "pack_start", pack_start) # TreeViewColumn orig_tree_view_column_pack_end = Gtk.TreeViewColumn.pack_end def tree_view_column_pack_end(self, cell, expand=True): orig_tree_view_column_pack_end(self, cell, expand) _patch(Gtk.TreeViewColumn, "pack_end", tree_view_column_pack_end) orig_tree_view_column_pack_start = Gtk.TreeViewColumn.pack_start def tree_view_column_pack_start(self, cell, expand=True): orig_tree_view_column_pack_start(self, cell, expand) _patch(Gtk.TreeViewColumn, "pack_start", tree_view_column_pack_start) # CellLayout orig_cell_pack_end = Gtk.CellLayout.pack_end def cell_pack_end(self, cell, expand=True): orig_cell_pack_end(self, cell, expand) _patch(Gtk.CellLayout, "pack_end", cell_pack_end) orig_cell_pack_start = Gtk.CellLayout.pack_start def cell_pack_start(self, cell, expand=True): orig_cell_pack_start(self, cell, expand) _patch(Gtk.CellLayout, "pack_start", cell_pack_start) orig_set_cell_data_func = Gtk.CellLayout.set_cell_data_func def set_cell_data_func(self, cell, func, user_data=_unset): def callback(*args): if args[-1] == _unset: args = args[:-1] return func(*args) orig_set_cell_data_func(self, cell, callback, user_data) _patch(Gtk.CellLayout, "set_cell_data_func", set_cell_data_func) # CellRenderer class GenericCellRenderer(Gtk.CellRenderer): pass _patch(Gtk, "GenericCellRenderer", GenericCellRenderer) # ComboBox orig_combo_row_separator_func = Gtk.ComboBox.set_row_separator_func def combo_row_separator_func(self, func, user_data=_unset): def callback(*args): if args[-1] == _unset: args = args[:-1] return func(*args) orig_combo_row_separator_func(self, callback, user_data) _patch(Gtk.ComboBox, "set_row_separator_func", combo_row_separator_func) # ComboBoxEntry class ComboBoxEntry(Gtk.ComboBox): def __init__(self, **kwds): Gtk.ComboBox.__init__(self, has_entry=True, **kwds) def set_text_column(self, text_column): self.set_entry_text_column(text_column) def get_text_column(self): return self.get_entry_text_column() _patch(Gtk, "ComboBoxEntry", ComboBoxEntry) def combo_box_entry_new(): return Gtk.ComboBoxEntry() _patch(Gtk, "combo_box_entry_new", combo_box_entry_new) def combo_box_entry_new_with_model(model): return Gtk.ComboBoxEntry(model=model) _patch(Gtk, "combo_box_entry_new_with_model", combo_box_entry_new_with_model) # Container def install_child_property(container, flag, pspec): warnings.warn('install_child_property() is not supported', gi.PyGIDeprecationWarning, stacklevel=2) _patch(Gtk.Container, "install_child_property", classmethod(install_child_property)) def new_text(): combo = Gtk.ComboBox() model = Gtk.ListStore(str) combo.set_model(model) combo.set_entry_text_column(0) return combo _patch(Gtk, "combo_box_new_text", new_text) def append_text(self, text): model = self.get_model() model.append([text]) _patch(Gtk.ComboBox, "append_text", append_text) _patch(Gtk, "expander_new_with_mnemonic", Gtk.Expander.new_with_mnemonic) _patch(Gtk, "icon_theme_get_default", Gtk.IconTheme.get_default) _patch(Gtk, "image_new_from_pixbuf", Gtk.Image.new_from_pixbuf) _patch(Gtk, "image_new_from_stock", Gtk.Image.new_from_stock) _patch(Gtk, "image_new_from_animation", Gtk.Image.new_from_animation) _patch(Gtk, "image_new_from_icon_set", Gtk.Image.new_from_icon_set) _patch(Gtk, "image_new_from_file", Gtk.Image.new_from_file) _patch(Gtk, "settings_get_default", Gtk.Settings.get_default) _patch(Gtk, "window_set_default_icon", Gtk.Window.set_default_icon) _patch(Gtk, "clipboard_get", Gtk.Clipboard.get) # AccelGroup _patch(Gtk.AccelGroup, "connect_group", Gtk.AccelGroup.connect) # StatusIcon _patch(Gtk, "status_icon_position_menu", Gtk.StatusIcon.position_menu) _patch(Gtk.StatusIcon, "set_tooltip", Gtk.StatusIcon.set_tooltip_text) # Scale orig_HScale = Gtk.HScale orig_VScale = Gtk.VScale class HScale(orig_HScale): def __init__(self, adjustment=None): orig_HScale.__init__(self, adjustment=adjustment) _patch(Gtk, "HScale", HScale) class VScale(orig_VScale): def __init__(self, adjustment=None): orig_VScale.__init__(self, adjustment=adjustment) _patch(Gtk, "VScale", VScale) _patch(Gtk, "stock_add", lambda items: None) # Widget _patch(Gtk.Widget, "window", property(fget=Gtk.Widget.get_window)) _patch(Gtk, "widget_get_default_direction", Gtk.Widget.get_default_direction) orig_size_request = Gtk.Widget.size_request def size_request(widget): class SizeRequest(UserList): def __init__(self, req): self.height = req.height self.width = req.width UserList.__init__(self, [self.width, self.height]) return SizeRequest(orig_size_request(widget)) _patch(Gtk.Widget, "size_request", size_request) _patch(Gtk.Widget, "hide_all", Gtk.Widget.hide) class BaseGetter(object): def __init__(self, context): self.context = context def __getitem__(self, state): color = self.context.get_background_color(state) return Gdk.Color(red=int(color.red * 65535), green=int(color.green * 65535), blue=int(color.blue * 65535)) class Styles(object): def __init__(self, widget): context = widget.get_style_context() self.base = BaseGetter(context) self.black = Gdk.Color(red=0, green=0, blue=0) class StyleDescriptor(object): def __get__(self, instance, class_): return Styles(instance) _patch(Gtk.Widget, "style", StyleDescriptor()) # TextView orig_text_view_scroll_to_mark = Gtk.TextView.scroll_to_mark def text_view_scroll_to_mark(self, mark, within_margin, use_align=False, xalign=0.5, yalign=0.5): return orig_text_view_scroll_to_mark(self, mark, within_margin, use_align, xalign, yalign) _patch(Gtk.TextView, "scroll_to_mark", text_view_scroll_to_mark) # Window orig_set_geometry_hints = Gtk.Window.set_geometry_hints def set_geometry_hints(self, geometry_widget=None, min_width=-1, min_height=-1, max_width=-1, max_height=-1, base_width=-1, base_height=-1, width_inc=-1, height_inc=-1, min_aspect=-1.0, max_aspect=-1.0): geometry = Gdk.Geometry() geom_mask = Gdk.WindowHints(0) if min_width >= 0 or min_height >= 0: geometry.min_width = max(min_width, 0) geometry.min_height = max(min_height, 0) geom_mask |= Gdk.WindowHints.MIN_SIZE if max_width >= 0 or max_height >= 0: geometry.max_width = max(max_width, 0) geometry.max_height = max(max_height, 0) geom_mask |= Gdk.WindowHints.MAX_SIZE if base_width >= 0 or base_height >= 0: geometry.base_width = max(base_width, 0) geometry.base_height = max(base_height, 0) geom_mask |= Gdk.WindowHints.BASE_SIZE if width_inc >= 0 or height_inc >= 0: geometry.width_inc = max(width_inc, 0) geometry.height_inc = max(height_inc, 0) geom_mask |= Gdk.WindowHints.RESIZE_INC if min_aspect >= 0.0 or max_aspect >= 0.0: if min_aspect <= 0.0 or max_aspect <= 0.0: raise TypeError("aspect ratios must be positive") geometry.min_aspect = min_aspect geometry.max_aspect = max_aspect geom_mask |= Gdk.WindowHints.ASPECT return orig_set_geometry_hints(self, geometry_widget, geometry, geom_mask) _patch(Gtk.Window, "set_geometry_hints", set_geometry_hints) _patch(Gtk, "window_list_toplevels", Gtk.Window.list_toplevels) _patch(Gtk, "window_set_default_icon_name", Gtk.Window.set_default_icon_name) # gtk.unixprint class UnixPrint(object): pass unixprint = UnixPrint() _patch_module('gtkunixprint', unixprint) # gtk.keysyms with warnings.catch_warnings(): warnings.simplefilter('ignore', category=RuntimeWarning) from gi.overrides import keysyms _patch_module('gtk.keysyms', keysyms) _patch(Gtk, "keysyms", keysyms) from . import generictreemodel _patch(Gtk, "GenericTreeModel", generictreemodel.GenericTreeModel) def enable_vte(): if _check_enabled("vte"): return gi.require_version('Vte', '0.0') from gi.repository import Vte _patch_module('vte', Vte) def enable_poppler(): if _check_enabled("poppler"): return gi.require_version('Poppler', '0.18') from gi.repository import Poppler _patch_module('poppler', Poppler) _patch(Poppler, "pypoppler_version", (1, 0, 0)) def enable_webkit(version='1.0'): if _check_enabled("webkit", version): return gi.require_version('WebKit', version) from gi.repository import WebKit _patch_module('webkit', WebKit) _patch(WebKit.WebView, "get_web_inspector", WebKit.WebView.get_inspector) def enable_gudev(): if _check_enabled("gudev"): return gi.require_version('GUdev', '1.0') from gi.repository import GUdev _patch_module('gudev', GUdev) def enable_gst(): if _check_enabled("gst"): return gi.require_version('Gst', '0.10') from gi.repository import Gst _patch_module('gst', Gst) _install_enums(Gst) _patch(Gst, "registry_get_default", Gst.Registry.get_default) _patch(Gst, "element_register", Gst.Element.register) _patch(Gst, "element_factory_make", Gst.ElementFactory.make) _patch(Gst, "caps_new_any", Gst.Caps.new_any) _patch(Gst, "get_pygst_version", lambda: (0, 10, 19)) _patch(Gst, "get_gst_version", lambda: (0, 10, 40)) from gi.repository import GstInterfaces _patch_module('gst.interfaces', GstInterfaces) _install_enums(GstInterfaces) from gi.repository import GstAudio _patch_module('gst.audio', GstAudio) _install_enums(GstAudio) from gi.repository import GstVideo _patch_module('gst.video', GstVideo) _install_enums(GstVideo) from gi.repository import GstBase _patch_module('gst.base', GstBase) _install_enums(GstBase) _patch(Gst, "BaseTransform", GstBase.BaseTransform) _patch(Gst, "BaseSink", GstBase.BaseSink) from gi.repository import GstController _patch_module('gst.controller', GstController) _install_enums(GstController, dest=Gst) from gi.repository import GstPbutils _patch_module('gst.pbutils', GstPbutils) _install_enums(GstPbutils) def enable_goocanvas(): if _check_enabled("goocanvas"): return gi.require_version('GooCanvas', '2.0') from gi.repository import GooCanvas _patch_module('goocanvas', GooCanvas) _install_enums(GooCanvas, strip='GOO_CANVAS_') _patch(GooCanvas, "ItemSimple", GooCanvas.CanvasItemSimple) _patch(GooCanvas, "Item", GooCanvas.CanvasItem) _patch(GooCanvas, "Image", GooCanvas.CanvasImage) _patch(GooCanvas, "Group", GooCanvas.CanvasGroup) _patch(GooCanvas, "Rect", GooCanvas.CanvasRect) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/pyproject.toml0000664000000000000000000000402215074674453015260 0ustar00rootroot[project] name = "PyGObject" description = "Python bindings for GObject Introspection" readme = 'README.rst' license = { text = "GNU Lesser General Public License v2.1 (LGPLv2.1)" } authors = [ { name="James Henstridge", email="james@daa.com.au" } ] maintainers = [ { name="Christoph Reiter", email="creiter@src.gnome.org" }, { name="Arjan Molenaar", email="amolenaar@gnome.org" }, { name="Dan Yeaw", email="danyeaw@gnome.org" }, { name="Ignacio Casal Quinteiro", email="icq@gnome.org" }, ] classifiers = [ "Development Status :: 5 - Production/Stable", "Intended Audience :: Developers", "License :: OSI Approved :: GNU Lesser General Public License v2 or later (LGPLv2+)", "Operating System :: POSIX", "Operating System :: Microsoft :: Windows", "Programming Language :: C", "Programming Language :: Python", "Topic :: Software Development :: Libraries :: Python Modules", ] requires-python = ">=3.9, <4.0" dependencies = [ "pycairo>=1.16" ] dynamic = ["version"] [project.urls] Homepage = "https://pygobject.gnome.org" Repository = "https://gitlab.gnome.org/GNOME/pygobject.git" Changelog = "https://gitlab.gnome.org/GNOME/pygobject/-/blob/main/NEWS" [tool.pdm.dev-dependencies] build = [ "setuptools", "meson-python", "ninja", "pycairo", ] test = [ "pytest", "pytest-cov", "flake8", ] docs = [ "sphinx", "sphinx-rtd-theme", "sphinx-copybutton>=0.5.2", "furo", ] [tool.pdm.options] install = [ "--no-isolation", "--config-setting=setup-args=-Dtests=true", "--config-setting=setup-args=-Dbuildtype=debug", "--config-setting=editable-verbose=true", ] build = [ "--no-wheel", "--config-setting=setup-args=-Dtests=true", ] [tool.meson-python.args] setup = ["-Dtests=false", "-Dwheel=true", "--wrap-mode=nofallback"] [tool.pytest.ini_options] testpaths = [ "tests", ] python_files = "test_*.py" addopts = [ "--import-mode=importlib", ] [build-system] build-backend = "mesonpy" requires = ["meson-python>=0.12.1", "pycairo>=1.16"] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/subprojects/.gitignore0000664000000000000000000000005215074674453016676 0ustar00rootrootglib libffi gobject-introspection pycairo ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/subprojects/glib.wrap0000664000000000000000000000021115074674453016513 0ustar00rootroot[wrap-git] directory=glib url=https://gitlab.gnome.org/GNOME/glib.git push-url=git@gitlab.gnome.org:GNOME/glib.git revision=main depth=1 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/subprojects/gobject-introspection.wrap0000664000000000000000000000032015074674453022112 0ustar00rootroot[wrap-git] directory=gobject-introspection url=https://gitlab.gnome.org/GNOME/gobject-introspection.git push-url=git@gitlab.gnome.org:GNOME/gobject-introspection.git revision=main depth=1 clone-recursive=true././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/subprojects/libffi.wrap0000664000000000000000000000022315074674453017034 0ustar00rootroot[wrap-git] directory=libffi url=https://gitlab.freedesktop.org/gstreamer/meson-ports/libffi.git revision=meson depth=1 [provide] libffi = ffi_dep ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/subprojects/pycairo.wrap0000664000000000000000000000014015074674453017245 0ustar00rootroot[wrap-git] directory=pycairo url=https://github.com/pygobject/pycairo.git revision=main depth=1 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/tests/conftest.py0000664000000000000000000001223415074674453015711 0ustar00rootrootimport os import sys import signal import subprocess import atexit import warnings import pytest @pytest.hookimpl(hookwrapper=True, tryfirst=True) def pytest_runtest_call(item): """A pytest hook which takes over sys.excepthook and raises any uncaught exception (with PyGObject this happesn often when we get called from C, like any signal handler, vfuncs tc) """ exceptions = [] def on_hook(type_, value, tback): exceptions.append((type_, value, tback)) orig_excepthook = sys.excepthook sys.excepthook = on_hook try: yield finally: sys.excepthook = orig_excepthook if exceptions: tp, value, tb = exceptions[0] raise tp(value).with_traceback(tb) def set_dll_search_path(): # Python 3.8 no longer searches for DLLs in PATH, so we have to add # everything in PATH manually. Note that unlike PATH add_dll_directory # has no defined order, so if there are two cairo DLLs in PATH we # might get a random one. if os.name != "nt" or not hasattr(os, "add_dll_directory"): return for p in os.environ.get("PATH", "").split(os.pathsep): try: os.add_dll_directory(p) except OSError: pass def init_test_environ(): set_dll_search_path() def dbus_launch_session(): if os.name == "nt" or sys.platform == "darwin": return (-1, "") try: out = subprocess.check_output([ "dbus-daemon", "--session", "--fork", "--print-address=1", "--print-pid=1"]) except (subprocess.CalledProcessError, OSError): return (-1, "") else: out = out.decode("utf-8") addr, pid = out.splitlines() return int(pid), addr pid, addr = dbus_launch_session() if pid >= 0: os.environ["DBUS_SESSION_BUS_ADDRESS"] = addr atexit.register(os.kill, pid, signal.SIGKILL) else: os.environ["DBUS_SESSION_BUS_ADDRESS"] = "." # force untranslated messages, as we check for them in some tests os.environ['LC_MESSAGES'] = 'C' os.environ['G_DEBUG'] = 'fatal-warnings fatal-criticals' if sys.platform == "darwin" or os.name == "nt": # gtk 3.22 has warnings and ciriticals on OS X, ignore for now. # On Windows glib will create an error dialog which will block tests # so it's never a good idea there to make things fatal. os.environ['G_DEBUG'] = '' # First add test directory, since we have a gi package there tests_srcdir = os.path.abspath(os.path.dirname(__file__)) srcdir = os.path.dirname(tests_srcdir) sys.path.insert(0, tests_srcdir) sys.path.insert(0, srcdir) import gi gi_builddir = os.path.dirname(gi._gi.__file__) builddir = os.path.dirname(gi_builddir) tests_builddir = os.path.join(builddir, "tests") sys.path.insert(0, tests_builddir) sys.path.insert(0, builddir) # make Gio able to find our gschemas.compiled in tests/. This needs to be set # before importing Gio. Support a separate build tree, so look in build dir # first. os.environ['GSETTINGS_BACKEND'] = 'memory' os.environ['GSETTINGS_SCHEMA_DIR'] = tests_builddir os.environ['G_FILENAME_ENCODING'] = 'UTF-8' # Avoid accessibility dbus warnings os.environ['NO_AT_BRIDGE'] = '1' # A workaround for https://gitlab.gnome.org/GNOME/glib/-/issues/2251 # The gtk4 a11y stack calls get_dbus_object_path() on the default app os.environ['GTK_A11Y'] = 'none' # Force the default theme so broken themes don't affect the tests os.environ['GTK_THEME'] = 'Adwaita' gi.require_version("GIRepository", "2.0") from gi.repository import GIRepository repo = GIRepository.Repository.get_default() repo.prepend_library_path(os.path.join(tests_builddir)) repo.prepend_search_path(tests_builddir) def try_require_version(namespace, version): try: gi.require_version(namespace, version) except ValueError: # prevent tests from running with the wrong version sys.modules["gi.repository." + namespace] = None # Optional try_require_version("Gtk", os.environ.get("TEST_GTK_VERSION", "3.0")) try_require_version("Gdk", os.environ.get("TEST_GTK_VERSION", "3.0")) try_require_version("GdkPixbuf", "2.0") try_require_version("Pango", "1.0") try_require_version("PangoCairo", "1.0") try_require_version("Atk", "1.0") # Required gi.require_versions({ "GIMarshallingTests": "1.0", "Regress": "1.0", "GLib": "2.0", "Gio": "2.0", "GObject": "2.0", }) # It's disabled for stable releases by default, this makes sure it's # always on for the tests. warnings.simplefilter('default', gi.PyGIDeprecationWarning) # Otherwise we crash on the first gtk use when e.g. DISPLAY isn't set try: from gi.repository import Gtk except ImportError: pass else: if Gtk._version == "4.0": res = Gtk.init_check() else: res = Gtk.init_check([])[0] if not res: raise RuntimeError("Gtk available, but Gtk.init_check() failed") init_test_environ() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/tests/gi/overrides/Regress.py0000664000000000000000000000266515074674453020106 0ustar00rootroot# -*- Mode: Python; py-indent-offset: 4 -*- # vim: tabstop=4 shiftwidth=4 expandtab # # Copyright (C) 2012 Martin Pitt # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public # License as published by the Free Software Foundation; either # version 2.1 of the License, or (at your option) any later version. # # This library is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU # Lesser General Public License for more details. # # You should have received a copy of the GNU Lesser General Public # License along with this library; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 # USA from ..importer import get_introspection_module from ..overrides import override Regress = get_introspection_module('Regress') REGRESS_OVERRIDE = 42 class Bitmask(Regress.Bitmask): """Replicate override of Bitmask (uint64), similar to GStreamer.""" def __init__(self, v): if not isinstance(v, int): raise TypeError("%s is not an int." % (type(v))) self.v = int(v) def __str__(self): return hex(self.v) def __eq__(self, other): return self.v == other Bitmask = override(Bitmask) __all__ = ['REGRESS_OVERRIDE', "Bitmask"] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/tests/gi/overrides/__init__.py0000664000000000000000000000011315074674453020215 0ustar00rootrootfrom pkgutil import extend_path __path__ = extend_path(__path__, __name__) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/tests/gimarshallingtestsextra.c0000664000000000000000000001272015074674453020626 0ustar00rootroot/* gimarshallingtestsextra.c * * Copyright (C) 2016 Thibault Saunier * * 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 . */ #include "gimarshallingtestsextra.h" #include void gi_marshalling_tests_compare_two_gerrors_in_gvalue (GValue *v, GValue *v1) { GError *error, * error1; g_assert_cmpstr (g_type_name (G_VALUE_TYPE (v)), ==, g_type_name (G_TYPE_ERROR)); g_assert_cmpstr (g_type_name (G_VALUE_TYPE (v1)), ==, g_type_name (G_TYPE_ERROR)); error = (GError*) g_value_get_boxed (v); error1 = (GError*) g_value_get_boxed (v1); g_assert_cmpint (error->domain, ==, error1->domain); g_assert_cmpint (error->code, ==, error1->code); g_assert_cmpstr (error->message, ==, error1->message); } /** * gi_marshalling_tests_nullable_gerror: * @error: (in) (nullable) (transfer full): * an optional #GError. * * So we've got an API which takes a `GError *` as `(in)` argument, * and we want this to be optional, so we added `(nullable)`. * * Returns: 1 or 0, depending if the error was set. */ gboolean gi_marshalling_tests_nullable_gerror(GError *error) { return error ? 1 : 0; } /** * gi_marshalling_tests_ghashtable_enum_none_in: * @hash_table: (element-type gint GIMarshallingTestsExtraEnum) (transfer none): */ void gi_marshalling_tests_ghashtable_enum_none_in (GHashTable *hash_table) { g_assert_cmpint (GPOINTER_TO_INT (g_hash_table_lookup (hash_table, GINT_TO_POINTER (1))), ==, GI_MARSHALLING_TESTS_EXTRA_ENUM_VALUE1); g_assert_cmpint (GPOINTER_TO_INT (g_hash_table_lookup (hash_table, GINT_TO_POINTER (2))), ==, GI_MARSHALLING_TESTS_EXTRA_ENUM_VALUE2); g_assert_cmpint (GPOINTER_TO_INT (g_hash_table_lookup (hash_table, GINT_TO_POINTER (3))), ==, GI_MARSHALLING_TESTS_EXTRA_ENUM_VALUE3); } /** * gi_marshalling_tests_ghashtable_enum_none_return: * * Returns: (element-type gint GIMarshallingTestsExtraEnum) (transfer none): */ GHashTable * gi_marshalling_tests_ghashtable_enum_none_return (void) { static GHashTable *hash_table = NULL; if (hash_table == NULL) { hash_table = g_hash_table_new (NULL, NULL); g_hash_table_insert (hash_table, GINT_TO_POINTER (1), GINT_TO_POINTER (GI_MARSHALLING_TESTS_EXTRA_ENUM_VALUE1)); g_hash_table_insert (hash_table, GINT_TO_POINTER (2), GINT_TO_POINTER (GI_MARSHALLING_TESTS_EXTRA_ENUM_VALUE2)); g_hash_table_insert (hash_table, GINT_TO_POINTER (3), GINT_TO_POINTER (GI_MARSHALLING_TESTS_EXTRA_ENUM_VALUE3)); } return hash_table; } /** * gi_marshalling_tests_filename_copy: * @path_in: (type filename) (nullable) * * Returns: (type filename) (nullable) */ gchar * gi_marshalling_tests_filename_copy (gchar *path_in) { return g_strdup (path_in); } /** * gi_marshalling_tests_filename_to_glib_repr: * @path_in: (type filename) (nullable) * * Returns: (array length=len) (element-type guint8) */ gchar * gi_marshalling_tests_filename_to_glib_repr (gchar *path_in, gsize *len) { *len = strlen(path_in); return g_strdup (path_in); } /** * gi_marshalling_tests_filename_exists: * @path: (type filename) */ gboolean gi_marshalling_tests_filename_exists (gchar *path) { return g_file_test (path, G_FILE_TEST_EXISTS); } /** * gi_marshalling_tests_enum_array_return_type: * @n_members: (out): The number of members * * Returns: (array length=n_members) (transfer full): An array of enum values */ GIMarshallingTestsExtraEnum * gi_marshalling_tests_enum_array_return_type (gsize *n_members) { GIMarshallingTestsExtraEnum *res = g_new0(GIMarshallingTestsExtraEnum, 3); *n_members = 3; res[0] = GI_MARSHALLING_TESTS_EXTRA_ENUM_VALUE1; res[1] = GI_MARSHALLING_TESTS_EXTRA_ENUM_VALUE2; res[2] = GI_MARSHALLING_TESTS_EXTRA_ENUM_VALUE3; return res; } GType gi_marshalling_tests_extra_flags_get_type (void) { static GType type = 0; if (G_UNLIKELY (type == 0)) { static const GFlagsValue values[] = { {GI_MARSHALLING_TESTS_EXTRA_FLAGS_VALUE1, "GI_MARSHALLING_TESTS_EXTRA_FLAGS_VALUE1", "value1"}, {GI_MARSHALLING_TESTS_EXTRA_FLAGS_VALUE2, "GI_MARSHALLING_TESTS_EXTRA_FLAGS_VALUE2", "value2"}, {0, NULL, NULL} }; type = g_flags_register_static ( g_intern_static_string ("GIMarshallingTestsExtraFlags"), values); } return type; } /** * gi_marshalling_tests_extra_flags_large_in: */ void gi_marshalling_tests_extra_flags_large_in (GIMarshallingTestsExtraFlags value) { g_assert_cmpint (value, ==, GI_MARSHALLING_TESTS_EXTRA_FLAGS_VALUE2); } /** * gi_marshalling_tests_extra_utf8_full_return_invalid: */ gchar * gi_marshalling_tests_extra_utf8_full_return_invalid (void) { return g_strdup ("invalid utf8 \xff\xfe"); } /** * gi_marshalling_tests_extra_utf8_full_out_invalid: * @utf8: (out) (transfer full): */ void gi_marshalling_tests_extra_utf8_full_out_invalid (gchar **utf8) { *utf8 = g_strdup ("invalid utf8 \xff\xfe"); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/tests/gimarshallingtestsextra.h0000664000000000000000000000460715074674453020640 0ustar00rootroot/* gimarshallingtestsextra.h * * Copyright (C) 2016 Thibault Saunier * * 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 . */ #ifndef EXTRA_TESTS #define EXTRA_TESTS #include #include #ifndef GI_TEST_EXTERN #define GI_TEST_EXTERN extern #endif typedef enum { GI_MARSHALLING_TESTS_EXTRA_ENUM_VALUE1, GI_MARSHALLING_TESTS_EXTRA_ENUM_VALUE2, GI_MARSHALLING_TESTS_EXTRA_ENUM_VALUE3 = 42 } GIMarshallingTestsExtraEnum; typedef enum { GI_MARSHALLING_TESTS_EXTRA_FLAGS_VALUE1 = 0, GI_MARSHALLING_TESTS_EXTRA_FLAGS_VALUE2 = (gint)(1 << 31), } GIMarshallingTestsExtraFlags; GI_TEST_EXTERN GType gi_marshalling_tests_extra_flags_get_type (void) G_GNUC_CONST; #define GI_MARSHALLING_TESTS_TYPE_EXTRA_FLAGS (gi_marshalling_tests_extra_flags_get_type ()) GI_TEST_EXTERN void gi_marshalling_tests_compare_two_gerrors_in_gvalue (GValue *v, GValue *v1); GI_TEST_EXTERN gboolean gi_marshalling_tests_nullable_gerror(GError *error); GI_TEST_EXTERN void gi_marshalling_tests_ghashtable_enum_none_in (GHashTable *hash_table); GI_TEST_EXTERN GHashTable * gi_marshalling_tests_ghashtable_enum_none_return (void); GI_TEST_EXTERN gchar * gi_marshalling_tests_filename_copy (gchar *path_in); GI_TEST_EXTERN gboolean gi_marshalling_tests_filename_exists (gchar *path); GI_TEST_EXTERN gchar * gi_marshalling_tests_filename_to_glib_repr (gchar *path_in, gsize *len); GI_TEST_EXTERN GIMarshallingTestsExtraEnum * gi_marshalling_tests_enum_array_return_type (gsize *n_members); GI_TEST_EXTERN void gi_marshalling_tests_extra_flags_large_in (GIMarshallingTestsExtraFlags value); GI_TEST_EXTERN gchar *gi_marshalling_tests_extra_utf8_full_return_invalid (void); GI_TEST_EXTERN void gi_marshalling_tests_extra_utf8_full_out_invalid (gchar **utf8); #endif /* EXTRA_TESTS */ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/tests/helper.py0000664000000000000000000000716115074674453015346 0ustar00rootrootimport contextlib import unittest import inspect import warnings import functools import sys from collections import namedtuple from io import StringIO import gi from gi import PyGIDeprecationWarning from gi.repository import GLib ExceptionInfo = namedtuple("ExceptionInfo", ["type", "value", "traceback"]) """The type used for storing exceptions used by capture_exceptions()""" @contextlib.contextmanager def capture_exceptions(): """Installs a temporary sys.excepthook which records all exceptions instead of printing them. """ exceptions = [] def custom_excepthook(*args): exceptions.append(ExceptionInfo(*args)) old_hook = sys.excepthook sys.excepthook = custom_excepthook try: yield exceptions finally: sys.excepthook = old_hook def ignore_gi_deprecation_warnings(func_or_class): """A unittest class and function decorator which makes them ignore PyGIDeprecationWarning. """ if inspect.isclass(func_or_class): assert issubclass(func_or_class, unittest.TestCase) cls = func_or_class for name, value in cls.__dict__.items(): if callable(value) and name.startswith("test_"): new_value = ignore_gi_deprecation_warnings(value) setattr(cls, name, new_value) return cls else: func = func_or_class @functools.wraps(func) def wrapper(*args, **kwargs): with capture_gi_deprecation_warnings(): return func(*args, **kwargs) return wrapper @contextlib.contextmanager def capture_gi_deprecation_warnings(): """Temporarily suppress PyGIDeprecationWarning output and record them""" with warnings.catch_warnings(record=True) as warn: warnings.simplefilter('always', category=PyGIDeprecationWarning) yield warn @contextlib.contextmanager def capture_glib_warnings(allow_warnings=False, allow_criticals=False): """Temporarily suppress glib warning output and record them. The test suite is run with G_DEBUG="fatal-warnings fatal-criticals" by default. Setting allow_warnings and allow_criticals will temporarily allow warnings or criticals without terminating the test run. """ old_mask = GLib.log_set_always_fatal(GLib.LogLevelFlags(0)) new_mask = old_mask if allow_warnings: new_mask &= ~GLib.LogLevelFlags.LEVEL_WARNING if allow_criticals: new_mask &= ~GLib.LogLevelFlags.LEVEL_CRITICAL GLib.log_set_always_fatal(GLib.LogLevelFlags(new_mask)) GLibWarning = gi._gi.Warning try: with warnings.catch_warnings(record=True) as warn: warnings.filterwarnings('always', category=GLibWarning) yield warn finally: GLib.log_set_always_fatal(old_mask) @contextlib.contextmanager def capture_glib_deprecation_warnings(): """Temporarily suppress glib deprecation warning output and record them""" GLibWarning = gi._gi.Warning with warnings.catch_warnings(record=True) as warn: warnings.filterwarnings( 'always', category=GLibWarning, message=".+ is deprecated and shouldn't be used anymore\\. " "It will be removed in a future version\\.") yield warn @contextlib.contextmanager def capture_output(): """ with capture_output() as (stdout, stderr): some_action() print(stdout.getvalue(), stderr.getvalue()) """ err = StringIO() out = StringIO() old_err = sys.stderr old_out = sys.stdout sys.stderr = err sys.stdout = out try: yield (out, err) finally: sys.stderr = old_err sys.stdout = old_out ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/tests/meson.build0000664000000000000000000001113115074674453015647 0ustar00rootrootgnome = import('gnome') host_system = host_machine.system() cc = meson.get_compiler('c') visibility_args = [] if get_option('default_library') != 'static' if host_system == 'windows' visibility_args += ['-DDLL_EXPORT'] if cc.get_id() == 'msvc' visibility_args += ['-DGI_TEST_EXTERN=__declspec(dllexport) extern'] visibility_args += ['-D_GI_EXTERN=__declspec(dllexport) extern'] elif cc.has_argument('-fvisibility=hidden') visibility_args += ['-DGI_TEST_EXTERN=__attribute__((visibility("default"))) __declspec(dllexport) extern'] visibility_args += ['-D_GI_EXTERN=__attribute__((visibility("default"))) __declspec(dllexport) extern'] visibility_args += ['-fvisibility=hidden'] endif elif cc.has_argument('-fvisibility=hidden') visibility_args += ['-DGI_TEST_EXTERN=__attribute__((visibility("default"))) extern'] visibility_args += ['-D_GI_EXTERN=__attribute__((visibility("default"))) extern'] visibility_args += ['-fvisibility=hidden'] endif endif if gi_dep.type_name() == 'pkgconfig' gi_datadir = gi_dep.get_variable(pkgconfig : 'gidatadir') regress_sources = [join_paths(gi_datadir, 'tests', 'regress.c')] regress_headers = [join_paths(gi_datadir, 'tests', 'regress.h')] regress_sources += [join_paths(gi_datadir, 'tests', 'annotation.c')] regress_headers += [join_paths(gi_datadir, 'tests', 'annotation.h')] regress_incdir = include_directories(join_paths(gi_datadir, 'tests')) marshalling_sources = [join_paths(gi_datadir, 'tests', 'gimarshallingtests.c')] marshalling_headers = [join_paths(gi_datadir, 'tests', 'gimarshallingtests.h')] else gi_subproject = subproject('gobject-introspection') regress_sources = gi_subproject.get_variable('test_regress_sources') regress_headers = gi_subproject.get_variable('test_regress_headers') regress_incdir = gi_subproject.get_variable('test_regress_incdirs') marshalling_sources = gi_subproject.get_variable('test_marshalling_sources') marshalling_headers = gi_subproject.get_variable('test_marshalling_headers') gi_datadir = join_paths(meson.source_root(), 'subprojects', 'gobject-introspection', 'tests') endif marshalling_sources += ['gimarshallingtestsextra.c'] marshalling_headers += ['gimarshallingtestsextra.h'] marshalling_lib = library( 'gimarshallingtests', sources : marshalling_sources, dependencies : [glib_dep, gobject_dep, gio_dep, gmodule_dep], include_directories : regress_incdir, c_args: visibility_args, ) gnome.generate_gir( marshalling_lib, sources : marshalling_sources + marshalling_headers, nsversion : '1.0', namespace : 'GIMarshallingTests', dependencies : [glib_dep, gobject_dep, gio_dep, gmodule_dep], symbol_prefix : 'gi_marshalling_tests', includes : ['Gio-2.0'], build_by_default : true, extra_args: ['--quiet'], ) regress_sources += ['regressextra.c'] regress_headers += ['regressextra.h'] regress_deps = [glib_dep, gobject_dep, gio_dep, gmodule_dep] regress_c_args = [] if cairo_dep.found() regress_deps += [cairo_dep, cairo_gobject_dep] else regress_c_args += ['-D_GI_DISABLE_CAIRO', '-DGI_TEST_DISABLE_CAIRO'] endif regress_lib = library( 'regress', sources : regress_sources, dependencies : regress_deps, include_directories : regress_incdir, c_args: regress_c_args + visibility_args, ) gnome.generate_gir( regress_lib, sources : regress_sources + regress_headers, nsversion : '1.0', namespace : 'Regress', includes : ['Gio-2.0', 'cairo-1.0'], build_by_default : true, dependencies : regress_deps, extra_args: regress_c_args + ['--quiet'], ) helper_sources = [ 'testhelpermodule.c', 'test-floating.c', 'test-thread.c', 'test-unknown.c'] helperext = python.extension_module('testhelper', helper_sources, dependencies : [python_dep, glib_dep, gobject_dep], c_args: pyext_c_args + main_c_args, include_directories: include_directories(join_paths('..', 'gi')) ) schemas = gnome.compile_schemas(build_by_default: true) envdata = environment() if gi_dep.type_name() == 'internal' envdata.append('GI_TYPELIB_PATH', join_paths(meson.project_build_root(), 'subprojects', 'gobject-introspection', 'gir')) endif if host_machine.system() == 'windows' envdata.prepend('PATH', join_paths(get_option('prefix'), get_option('bindir'))) endif python_paths = [join_paths(meson.current_build_dir(), '..')] if pycairo_dep.found() and pycairo_dep.type_name() == 'internal' python_paths += [join_paths(meson.project_build_root(), 'subprojects', 'pycairo')] endif envdata.append('PYTHONPATH', python_paths) test('pygobject-test-suite', python, args: ['-m', 'pytest'], workdir: meson.project_source_root(), env: envdata, timeout: 90) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/tests/org.gnome.test.gschema.xml0000664000000000000000000000166415074674453020520 0ustar00rootroot true "Hello" (1,2) [1,2] 'banana' 123 42 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/tests/regressextra.c0000664000000000000000000003043415074674453016376 0ustar00rootroot#include "regress.h" #include "regressextra.h" #include struct _RegressTestBoxedCWrapper { RegressTestBoxedC * cptr; }; RegressTestBoxedCWrapper * regress_test_boxed_c_wrapper_new (void) { RegressTestBoxedCWrapper *boxed; boxed = g_slice_new (RegressTestBoxedCWrapper); boxed->cptr = regress_test_boxed_c_new (); return boxed; } RegressTestBoxedCWrapper * regress_test_boxed_c_wrapper_copy (RegressTestBoxedCWrapper *self) { RegressTestBoxedCWrapper *ret_boxed; ret_boxed = g_slice_new (RegressTestBoxedCWrapper); ret_boxed->cptr = g_boxed_copy (regress_test_boxed_c_get_type(), self->cptr); return ret_boxed; } static void regress_test_boxed_c_wrapper_free (RegressTestBoxedCWrapper *boxed) { g_boxed_free (regress_test_boxed_c_get_type(), boxed->cptr); g_slice_free (RegressTestBoxedCWrapper, boxed); } G_DEFINE_BOXED_TYPE(RegressTestBoxedCWrapper, regress_test_boxed_c_wrapper, regress_test_boxed_c_wrapper_copy, regress_test_boxed_c_wrapper_free); /** * regress_test_boxed_c_wrapper_get * @self: a #RegressTestBoxedCWrapper objects * * Returns: (transfer none): associated #RegressTestBoxedC **/ RegressTestBoxedC * regress_test_boxed_c_wrapper_get (RegressTestBoxedCWrapper *self) { return self->cptr; } /** * regress_test_array_of_non_utf8_strings * Returns: (transfer full) (allow-none) (array zero-terminated=1): Array of strings */ gchar** regress_test_array_of_non_utf8_strings (void) { char **ret = g_new (char *, 2); ret[0] = g_strdup ("Andr\351 Lur\347at"); ret[1] = NULL; return ret; } /** * regress_test_array_fixed_boxed_none_out * @objs: (out) (array fixed-size=2) (transfer none): An array of #RegressTestBoxedC **/ void regress_test_array_fixed_boxed_none_out (RegressTestBoxedC ***objs) { static RegressTestBoxedC **arr; if (arr == NULL) { arr = g_new0 (RegressTestBoxedC *, 3); arr[0] = regress_test_boxed_c_new (); arr[1] = regress_test_boxed_c_new (); } *objs = arr; } /** * regress_test_gvalue_out_boxed: * @value: (out) (transfer full): the output gvalue * @init: (in): the initialisation value **/ void regress_test_gvalue_out_boxed (GValue *value, int init) { RegressTestBoxed rtb; GValue v = G_VALUE_INIT; memset(&rtb, 0, sizeof (rtb)); rtb.some_int8 = init; g_value_init (&v, REGRESS_TEST_TYPE_BOXED); g_value_set_boxed (&v, &rtb); *value = v; } /** * regress_test_glist_boxed_none_return * Return value: (element-type RegressTestBoxedC) (transfer none): **/ GList * regress_test_glist_boxed_none_return (guint count) { static GList *list = NULL; if (!list) { while (count > 0) { list = g_list_prepend (list, regress_test_boxed_c_new ()); count--; } } return list; } /** * regress_test_glist_boxed_full_return * Return value: (element-type RegressTestBoxedC) (transfer full): **/ GList * regress_test_glist_boxed_full_return (guint count) { GList *list = NULL; while (count > 0) { list = g_list_prepend (list, regress_test_boxed_c_new ()); count--; } return list; } /** * regress_test_array_of_fundamental_objects_in * @list: (array length=len) (element-type RegressTestFundamentalObject): An array of #RegressTestFundamentalObject * @len: length of the list **/ gboolean regress_test_array_of_fundamental_objects_in (RegressTestFundamentalObject **list, gsize len) { gsize i; for (i = 0; i < len; i++) { if (!REGRESS_TEST_IS_FUNDAMENTAL_OBJECT (list[i])) { return FALSE; } } return TRUE; } /** * regress_test_array_of_fundamental_objects_out * @len: (out): length of the list * Returns: (array length=len) (transfer full): An array of #RegressTestFundamentalObject **/ RegressTestFundamentalObject ** regress_test_array_of_fundamental_objects_out (gsize *len) { RegressTestFundamentalObject **objs; int i; objs = g_new (RegressTestFundamentalObject *, 2); for (i = 0; i < 2; i++) { objs[i] = (RegressTestFundamentalObject *) regress_test_fundamental_sub_object_new("foo"); } *len = 2; return objs; } /** * regress_test_fundamental_argument_in * @obj: (transfer full): A #RegressTestFundamentalObject **/ gboolean regress_test_fundamental_argument_in (RegressTestFundamentalObject *obj) { return REGRESS_TEST_IS_FUNDAMENTAL_OBJECT (obj); } /** * regress_test_fundamental_argument_out * @obj: (transfer none): A #RegressTestFundamentalObject * Returns: (transfer none): Same #RegressTestFundamentalObject **/ RegressTestFundamentalObject* regress_test_fundamental_argument_out (RegressTestFundamentalObject *obj) { return obj; } #ifndef _GI_DISABLE_CAIRO /** * regress_test_cairo_context_none_return: * * Returns: (transfer none): */ cairo_t * regress_test_cairo_context_none_return (void) { static cairo_t *cr; if (cr == NULL) { cairo_surface_t *surface; surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, 10, 10); cr = cairo_create (surface); cairo_surface_destroy (surface); } return cr; } /** * regress_test_cairo_context_full_in: * @context: (transfer full): */ void regress_test_cairo_context_full_in (cairo_t *context) { cairo_destroy (context); } /** * regress_test_cairo_path_full_return: * * Returns: (transfer full): */ cairo_path_t * regress_test_cairo_path_full_return (void) { cairo_t *cr = regress_test_cairo_context_none_return (); return cairo_copy_path (cr); } /** * regress_test_cairo_path_none_in: * @path: (transfer none): */ void regress_test_cairo_path_none_in (cairo_path_t *path) { cairo_t *cr = regress_test_cairo_context_full_return (); cairo_append_path (cr, path); g_assert (cairo_status (cr) == CAIRO_STATUS_SUCCESS); cairo_destroy (cr); } /** * regress_test_cairo_path_full_in_full_return: * @path: (transfer full): * * Returns: (transfer full): */ cairo_path_t * regress_test_cairo_path_full_in_full_return (cairo_path_t *path) { return path; } /** * regress_test_cairo_pattern_full_in: * @pattern: (transfer full): */ void regress_test_cairo_pattern_full_in (cairo_pattern_t *pattern) { cairo_pattern_destroy (pattern); } /** * regress_test_cairo_pattern_none_in: * @pattern: (transfer none): */ void regress_test_cairo_pattern_none_in (cairo_pattern_t *pattern) { cairo_t *cr = regress_test_cairo_context_full_return (); cairo_set_source (cr, pattern); g_assert (cairo_status (cr) == CAIRO_STATUS_SUCCESS); cairo_destroy (cr); } /** * regress_test_cairo_pattern_none_return: * * Returns: (transfer none): */ cairo_pattern_t* regress_test_cairo_pattern_none_return (void) { static cairo_pattern_t *pattern; if (pattern == NULL) { pattern = cairo_pattern_create_rgb(0.1, 0.2, 0.3); } return pattern; } /** * regress_test_cairo_pattern_full_return: * * Returns: (transfer full): */ cairo_pattern_t * regress_test_cairo_pattern_full_return (void) { cairo_pattern_t *pattern = cairo_pattern_create_rgb(0.5, 0.6, 0.7); return pattern; } /** * regress_test_cairo_region_full_in: * @region: (transfer full): */ void regress_test_cairo_region_full_in (cairo_region_t *region) { cairo_region_destroy (region); } /** * regress_test_cairo_surface_full_in: * @surface: (transfer full): */ void regress_test_cairo_surface_full_in (cairo_surface_t *surface) { g_assert (cairo_image_surface_get_format (surface) == CAIRO_FORMAT_ARGB32); g_assert (cairo_image_surface_get_width (surface) == 10); g_assert (cairo_image_surface_get_height (surface) == 10); cairo_surface_destroy (surface); } /** * regress_test_cairo_font_options_full_return: * * Returns: (transfer full): */ cairo_font_options_t * regress_test_cairo_font_options_full_return (void) { return cairo_font_options_create (); } /** * regress_test_cairo_font_options_none_return: * * Returns: (transfer none): */ cairo_font_options_t * regress_test_cairo_font_options_none_return (void) { static cairo_font_options_t *options; if (options == NULL) options = cairo_font_options_create (); return options; } /** * regress_test_cairo_font_options_full_in: * @options: (transfer full): */ void regress_test_cairo_font_options_full_in (cairo_font_options_t *options) { cairo_font_options_destroy (options); } /** * regress_test_cairo_font_options_none_in: * @options: (transfer none): */ void regress_test_cairo_font_options_none_in (cairo_font_options_t *options) { } /** * regress_test_cairo_matrix_none_in: * @matrix: (transfer none): */ void regress_test_cairo_matrix_none_in (const cairo_matrix_t *matrix) { cairo_matrix_t m = *matrix; g_assert (m.x0 == 0); g_assert (m.y0 == 0); g_assert (m.xx == 1); g_assert (m.xy == 0); g_assert (m.yy == 1); g_assert (m.yx == 0); } /** * regress_test_cairo_matrix_none_return: * Returns: (transfer none): */ cairo_matrix_t * regress_test_cairo_matrix_none_return (void) { static cairo_matrix_t matrix; cairo_matrix_init_identity (&matrix); return &matrix; } /** * regress_test_cairo_matrix_out_caller_allocates: * @matrix: (out): */ void regress_test_cairo_matrix_out_caller_allocates (cairo_matrix_t *matrix) { cairo_matrix_t m; cairo_matrix_init_identity (&m); *matrix = m; } #endif G_DEFINE_TYPE (RegressTestAction, regress_test_action, G_TYPE_INITIALLY_UNOWNED) enum { SIGNAL_0, ACTION_SIGNAL, ACTION2_SIGNAL, LAST_SIGNAL }; static guint regress_test_action_signals[LAST_SIGNAL] = { 0 }; static RegressTestAction * regress_test_action_do_action (RegressTestAction *self) { RegressTestAction *ret = g_object_new (regress_test_action_get_type (), NULL); return ret; } static RegressTestAction * regress_test_action_do_action2 (RegressTestAction *self) { return NULL; } static void regress_test_action_init (RegressTestAction *self) { } static void regress_test_action_class_init (RegressTestActionClass *klass) { /** * RegressTestAction::action: * * An action signal. * * Returns: (transfer full): another #RegressTestAction */ regress_test_action_signals[ACTION_SIGNAL] = g_signal_new_class_handler ("action", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_CALLBACK (regress_test_action_do_action), NULL, NULL, NULL, regress_test_action_get_type (), 0); /** * RegressTestAction::action2: * * Another action signal. * * Returns: (transfer full): another #RegressTestAction */ regress_test_action_signals[ACTION2_SIGNAL] = g_signal_new_class_handler ("action2", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION, G_CALLBACK (regress_test_action_do_action2), NULL, NULL, NULL, regress_test_action_get_type (), 0); } /* * RegressBitmask * * Mimic a primitive, fundamental type. */ static void regress_value_init_bitmask (GValue * value) { value->data[0].v_uint64 = 0; } static void regress_value_copy_bitmask (const GValue * src_value, GValue * dest_value) { dest_value->data[0].v_uint64 = src_value->data[0].v_uint64; } static void _value_transform_uint64_bitmask (const GValue * src_value, GValue * dest_value) { dest_value->data[0].v_uint64 = src_value->data[0].v_uint64; } static void _value_transform_bitmask_uint64 (const GValue * src_value, GValue * dest_value) { dest_value->data[0].v_uint64 = src_value->data[0].v_uint64; } static const GTypeValueTable _regress_bitmask_value_table = { regress_value_init_bitmask, NULL, regress_value_copy_bitmask, NULL, (char *) NULL, NULL, (char *) NULL, NULL }; GType regress_bitmask_get_type (void) { static GType regress_bitmask_type = 0; if (g_once_init_enter (®ress_bitmask_type)) { GTypeInfo _info = { 0, NULL, NULL, NULL, NULL, NULL, 0, 0, NULL, &_regress_bitmask_value_table }; GTypeFundamentalInfo _finfo = { 0 }; GType _type = g_type_register_fundamental ( g_type_fundamental_next (), "RegressBitmask", &_info, &_finfo, 0); g_once_init_leave(®ress_bitmask_type, _type); g_value_register_transform_func ( REGRESS_TYPE_BITMASK, G_TYPE_UINT64, _value_transform_bitmask_uint64); g_value_register_transform_func ( G_TYPE_UINT64, REGRESS_TYPE_BITMASK, _value_transform_uint64_bitmask); } return regress_bitmask_type; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/tests/regressextra.h0000664000000000000000000000713615074674453016406 0ustar00rootroot#ifndef REGRESS_EXTRA_H #define REGRESS_EXTRA_H #include #ifndef GI_TEST_EXTERN #define GI_TEST_EXTERN extern #endif typedef struct _RegressTestBoxedC RegressTestBoxedC; typedef struct _RegressTestBoxedCWrapper RegressTestBoxedCWrapper; GI_TEST_EXTERN GType regress_test_boxed_c_wrapper_get_type (void); GI_TEST_EXTERN RegressTestBoxedCWrapper *regress_test_boxed_c_wrapper_new (void); GI_TEST_EXTERN RegressTestBoxedCWrapper * regress_test_boxed_c_wrapper_copy (RegressTestBoxedCWrapper *self); GI_TEST_EXTERN RegressTestBoxedC *regress_test_boxed_c_wrapper_get (RegressTestBoxedCWrapper *self); GI_TEST_EXTERN gchar** regress_test_array_of_non_utf8_strings (void); GI_TEST_EXTERN void regress_test_array_fixed_boxed_none_out (RegressTestBoxedC ***objs); GI_TEST_EXTERN void regress_test_gvalue_out_boxed (GValue *value, int init); GI_TEST_EXTERN GList *regress_test_glist_boxed_none_return (guint count); GI_TEST_EXTERN GList *regress_test_glist_boxed_full_return (guint count); GI_TEST_EXTERN gboolean regress_test_array_of_fundamental_objects_in (RegressTestFundamentalObject **list, gsize len); GI_TEST_EXTERN RegressTestFundamentalObject** regress_test_array_of_fundamental_objects_out (gsize *len); GI_TEST_EXTERN gboolean regress_test_fundamental_argument_in (RegressTestFundamentalObject *obj); GI_TEST_EXTERN RegressTestFundamentalObject* regress_test_fundamental_argument_out (RegressTestFundamentalObject *obj); #ifndef _GI_DISABLE_CAIRO GI_TEST_EXTERN cairo_t *regress_test_cairo_context_none_return (void); GI_TEST_EXTERN void regress_test_cairo_context_full_in (cairo_t *context); GI_TEST_EXTERN cairo_path_t *regress_test_cairo_path_full_return (void); GI_TEST_EXTERN void regress_test_cairo_path_none_in (cairo_path_t *path); GI_TEST_EXTERN cairo_path_t * regress_test_cairo_path_full_in_full_return (cairo_path_t *path); GI_TEST_EXTERN void regress_test_cairo_pattern_full_in (cairo_pattern_t *pattern); GI_TEST_EXTERN void regress_test_cairo_pattern_none_in (cairo_pattern_t *pattern); GI_TEST_EXTERN cairo_pattern_t* regress_test_cairo_pattern_none_return (void); GI_TEST_EXTERN cairo_pattern_t * regress_test_cairo_pattern_full_return (void); GI_TEST_EXTERN cairo_font_options_t *regress_test_cairo_font_options_full_return (void); GI_TEST_EXTERN cairo_font_options_t *regress_test_cairo_font_options_none_return (void); GI_TEST_EXTERN void regress_test_cairo_font_options_full_in (cairo_font_options_t *options); GI_TEST_EXTERN void regress_test_cairo_font_options_none_in (cairo_font_options_t *options); GI_TEST_EXTERN void regress_test_cairo_region_full_in (cairo_region_t *region); GI_TEST_EXTERN void regress_test_cairo_surface_full_in (cairo_surface_t *surface); GI_TEST_EXTERN void regress_test_cairo_matrix_none_in (const cairo_matrix_t *matrix); GI_TEST_EXTERN cairo_matrix_t *regress_test_cairo_matrix_none_return (void); GI_TEST_EXTERN void regress_test_cairo_matrix_out_caller_allocates (cairo_matrix_t *matrix); #endif /* RegressTestAction */ typedef struct { GInitiallyUnowned parent; } RegressTestAction; typedef struct { GInitiallyUnownedClass parent_class; } RegressTestActionClass; GI_TEST_EXTERN GType regress_test_action_get_type (void); /** * RegressBitmask: * * A fundamental type that describes a 64-bit bitmask. * * This type resembles GStreamer's Bitmask type. */ /** * REGRESS_TYPE_BITMASK: * * a #GValue type that represents a 64-bit bitmask. * * Returns: the #GType of RegressBitmask (which is not explicitly typed) */ #define REGRESS_TYPE_BITMASK (regress_bitmask_get_type()) GI_TEST_EXTERN GType regress_bitmask_get_type (void); #endif /* REGRESS_EXTRA_H */ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/tests/test-floating.c0000664000000000000000000000626215074674453016442 0ustar00rootroot/* * test-floating.c - Source for TestFloating * Copyright (C) 2010 Collabora Ltd. * * 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 */ #include "test-floating.h" /* TestFloating */ G_DEFINE_TYPE(TestFloating, test_floating, G_TYPE_INITIALLY_UNOWNED) static void test_floating_finalize (GObject *gobject) { TestFloating *object = TEST_FLOATING (gobject); if (g_object_is_floating (object)) { g_warning ("A floating object was finalized. This means that someone\n" "called g_object_unref() on an object that had only a floating\n" "reference; the initial floating reference is not owned by anyone\n" "and must be removed without g_object_ref_sink()."); } G_OBJECT_CLASS (test_floating_parent_class)->finalize (gobject); } static void test_floating_class_init (TestFloatingClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); gobject_class->finalize = test_floating_finalize; } static void test_floating_init (TestFloating *self) { } /* TestOwnedByLibrary */ G_DEFINE_TYPE(TestOwnedByLibrary, test_owned_by_library, G_TYPE_OBJECT) static GSList *obl_instance_list = NULL; static void test_owned_by_library_class_init (TestOwnedByLibraryClass *klass) { } static void test_owned_by_library_init (TestOwnedByLibrary *self) { g_object_ref (self); obl_instance_list = g_slist_prepend (obl_instance_list, self); } void test_owned_by_library_release (TestOwnedByLibrary *self) { obl_instance_list = g_slist_remove (obl_instance_list, self); g_object_unref (self); } GSList * test_owned_by_library_get_instance_list (void) { return obl_instance_list; } /* TestFloatingAndSunk * This object is mimicking the GtkWindow behaviour, ie a GInitiallyUnowned subclass * whose floating reference has already been sunk when g_object_new() returns it. * The reference is already sunk because the instance is already owned by the instance * list. */ G_DEFINE_TYPE(TestFloatingAndSunk, test_floating_and_sunk, G_TYPE_INITIALLY_UNOWNED) static GSList *fas_instance_list = NULL; static void test_floating_and_sunk_class_init (TestFloatingAndSunkClass *klass) { } static void test_floating_and_sunk_init (TestFloatingAndSunk *self) { g_object_ref_sink (self); fas_instance_list = g_slist_prepend (fas_instance_list, self); } void test_floating_and_sunk_release (TestFloatingAndSunk *self) { fas_instance_list = g_slist_remove (fas_instance_list, self); g_object_unref (self); } GSList * test_floating_and_sunk_get_instance_list (void) { return fas_instance_list; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/tests/test-floating.h0000664000000000000000000000722215074674453016444 0ustar00rootroot/* * test-floating.h - Header for TestFloating * Copyright (C) 2010 Collabora Ltd. * * 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 */ #include /* TestFloating */ typedef struct { GInitiallyUnowned parent; } TestFloating; typedef struct { GInitiallyUnownedClass parent_class; } TestFloatingClass; #define TEST_TYPE_FLOATING (test_floating_get_type()) #define TEST_FLOATING(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TEST_TYPE_FLOATING, TestFloating)) #define TEST_FLOATING_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TEST_TYPE_FLOATING, TestFloatingClass)) #define TEST_IS_FLOATING(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TEST_TYPE_FLOATING)) #define TEST_IS_FLOATING_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), TEST_TYPE_FLOATING)) #define TEST_FLOATING_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), TEST_TYPE_FLOATING, TestFloatingClass)) GType test_floating_get_type (void); /* TestOwnedByLibrary */ typedef struct { GObject parent; } TestOwnedByLibrary; typedef struct { GObjectClass parent_class; } TestOwnedByLibraryClass; #define TEST_TYPE_OWNED_BY_LIBRARY (test_owned_by_library_get_type()) #define TEST_OWNED_BY_LIBRARY(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TEST_TYPE_OWNED_BY_LIBRARY, TestOwnedByLibrary)) #define TEST_OWNED_BY_LIBRARY_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TEST_TYPE_OWNED_BY_LIBRARY, TestOwnedByLibraryClass)) #define TEST_IS_OWNED_BY_LIBRARY(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TEST_TYPE_OWNED_BY_LIBRARY)) #define TEST_IS_OWNED_BY_LIBRARY_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), TEST_TYPE_OWNED_BY_LIBRARY)) #define TEST_OWNED_BY_LIBRARY_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), TEST_TYPE_OWNED_BY_LIBRARY, TestOwnedByLibraryClass)) GType test_owned_by_library_get_type (void); void test_owned_by_library_release (TestOwnedByLibrary *self); GSList *test_owned_by_library_get_instance_list (void); /* TestFloatingAndSunk */ typedef struct { GInitiallyUnowned parent; } TestFloatingAndSunk; typedef struct { GInitiallyUnownedClass parent_class; } TestFloatingAndSunkClass; #define TEST_TYPE_FLOATING_AND_SUNK (test_floating_and_sunk_get_type()) #define TEST_FLOATING_AND_SUNK(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TEST_TYPE_FLOATING_AND_SUNK, TestFloatingAndSunk)) #define TEST_FLOATING_AND_SUNK_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TEST_TYPE_FLOATING_AND_SUNK, TestFloatingAndSunkClass)) #define TEST_IS_FLOATING_AND_SUNK(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TEST_TYPE_FLOATING_AND_SUNK)) #define TEST_IS_FLOATING_AND_SUNK_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), TEST_TYPE_FLOATING_AND_SUNK)) #define TEST_FLOATING_AND_SUNK_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), TEST_TYPE_FLOATING_AND_SUNK, TestFloatingAndSunkClass)) GType test_floating_and_sunk_get_type (void); void test_floating_and_sunk_release (TestFloatingAndSunk *self); GSList *test_floating_and_sunk_get_instance_list (void); ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/tests/test-thread.c0000664000000000000000000000302215074674453016075 0ustar00rootroot#include "test-thread.h" enum { /* methods */ SIGNAL_EMIT_SIGNAL, SIGNAL_FROM_THREAD, LAST_SIGNAL }; static guint test_thread_signals[LAST_SIGNAL] = { 0 }; typedef enum { TEST_THREAD_A, TEST_THREAD_B } ThreadEnumType; static GType test_thread_enum_get_type (void) { static GType enum_type = 0; static GEnumValue enum_values[] = { {TEST_THREAD_A, "TEST_THREAD_A", "a as in apple"}, {0, NULL, NULL}, }; if (!enum_type) { enum_type = g_enum_register_static ("TestThreadEnum", enum_values); } return enum_type; } G_DEFINE_TYPE(TestThread, test_thread, G_TYPE_OBJECT); static void other_thread_cb (TestThread *self) { g_signal_emit_by_name (self, "from-thread", 0, NULL); g_thread_exit (0); } static void test_thread_emit_signal (TestThread *self) { self->thread = g_thread_new ("t", (GThreadFunc)other_thread_cb, self); } static void test_thread_init (TestThread *self) {} static void test_thread_class_init (TestThreadClass *klass) { test_thread_signals[SIGNAL_EMIT_SIGNAL] = g_signal_new ("emit-signal", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (TestThreadClass, emit_signal), NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0); test_thread_signals[SIGNAL_FROM_THREAD] = g_signal_new ("from-thread", G_TYPE_FROM_CLASS (klass), G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (TestThreadClass, from_thread), NULL, NULL, g_cclosure_marshal_VOID__BOXED, G_TYPE_NONE, 1, test_thread_enum_get_type ()); klass->emit_signal = test_thread_emit_signal; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/tests/test-thread.h0000664000000000000000000000151715074674453016111 0ustar00rootroot#include typedef struct { GObject parent; GThread *thread; } TestThread; typedef struct { GObjectClass parent_class; void (*emit_signal) (TestThread *sink); void (*from_thread) (TestThread *sink); } TestThreadClass; GType test_thread_get_type (void); #define TEST_TYPE_THREAD (test_thread_get_type()) #define TEST_THREAD(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TEST_TYPE_THREAD, TestTHREAD)) #define TEST_THREAD_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TEST_TYPE_THREAD, TestTHREADClass)) #define TEST_IS_THREAD(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TEST_TYPE_THREAD)) #define TEST_IS_THREAD_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), TEST_TYPE_THREAD)) #define TEST_THREAD_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), TEST_TYPE_THREAD, TestTHREADClass)) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/tests/test-unknown.c0000664000000000000000000000550215074674453016332 0ustar00rootroot#include "test-unknown.h" enum { PROP_SOME_PROPERTY = 1, }; static void test_interface_base_init (gpointer g_iface) { static gboolean initialized = FALSE; if (!initialized) { g_object_interface_install_property (g_iface, g_param_spec_string ("some-property", "some-property", "A simple test property", NULL, G_PARAM_READWRITE)); initialized = TRUE; } } GType test_interface_get_type (void) { static GType gtype = 0; if (!gtype) { static const GTypeInfo info = { sizeof (TestInterfaceIface), /* class_size */ test_interface_base_init, /* base_init */ NULL, /* base_finalize */ NULL, NULL, /* class_finalize */ NULL, /* class_data */ 0, 0, /* n_preallocs */ NULL }; gtype = g_type_register_static (G_TYPE_INTERFACE, "TestInterface", &info, 0); g_type_interface_add_prerequisite (gtype, G_TYPE_OBJECT); } return gtype; } static void test_unknown_iface_method (TestInterface *iface) { } static void test_unknown_test_interface_init (TestInterfaceIface *iface) { iface->iface_method = test_unknown_iface_method; } G_DEFINE_TYPE_WITH_CODE (TestUnknown, test_unknown, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (TEST_TYPE_INTERFACE, test_unknown_test_interface_init)); static void test_unknown_init (TestUnknown *self) {} static void test_unknown_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { } static void test_unknown_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { } static void test_unknown_class_init (TestUnknownClass *klass) { GObjectClass *gobject_class = (GObjectClass*) klass; gobject_class->get_property = test_unknown_get_property; gobject_class->set_property = test_unknown_set_property; g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_SOME_PROPERTY, g_param_spec_string ("some-property", "some-property", "A simple test property", NULL, G_PARAM_READWRITE)); } void test_interface_iface_method (TestInterface *instance) { TestInterfaceIface *iface = TEST_INTERFACE_GET_IFACE (instance); (* iface->iface_method) (instance); } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/tests/test-unknown.h0000664000000000000000000000274515074674453016345 0ustar00rootroot#include /* TestUnknown */ typedef struct { GObject parent; } TestUnknown; typedef struct { GObjectClass parent_class; } TestUnknownClass; #define TEST_TYPE_UNKNOWN (test_unknown_get_type()) #define TEST_UNKNOWN(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TEST_TYPE_UNKNOWN, TestUnknown)) #define TEST_UNKNOWN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TEST_TYPE_UNKNOWN, TestUnknownClass)) #define TEST_IS_UNKNOWN(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TEST_TYPE_UNKNOWN)) #define TEST_IS_UNKNOWN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((obj), TEST_TYPE_UNKNOWN)) #define TEST_UNKNOWN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS((obj), TEST_TYPE_UNKNOWN, TestUnknownClass)) GType test_unknown_get_type (void); /* TestInterface */ typedef struct _TestInterface TestInterface; typedef struct _TestInterfaceIface TestInterfaceIface; struct _TestInterfaceIface { GTypeInterface g_iface; /* VTable */ void (* iface_method) (TestInterface *iface); }; #define TEST_TYPE_INTERFACE (test_interface_get_type ()) #define TEST_INTERFACE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TEST_TYPE_INTERFACE, TestInterface)) #define TEST_IS_INTERFACE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TEST_TYPE_INTERFACE)) #define TEST_INTERFACE_GET_IFACE(obj) (G_TYPE_INSTANCE_GET_INTERFACE ((obj), TEST_TYPE_INTERFACE, TestInterfaceIface)) GType test_interface_get_type (void); void test_interface_iface_method (TestInterface *iface); ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/tests/test_async.py0000664000000000000000000001344515074674453016245 0ustar00rootroot# -*- Mode: Python; py-indent-offset: 4 -*- # vim: tabstop=4 shiftwidth=4 expandtab import pytest import platform import unittest import asyncio from gi.repository import GLib, Gio from gi.events import GLibEventLoopPolicy class TestAsync(unittest.TestCase): def setUp(self): policy = GLibEventLoopPolicy() asyncio.set_event_loop_policy(policy) self.addCleanup(asyncio.set_event_loop_policy, None) self.loop = policy.get_event_loop() self.addCleanup(self.loop.close) def test_async_enumerate(self): f = Gio.file_new_for_path("./") called = False def cb(): nonlocal called called = True async def run(): nonlocal called, self self.loop.call_soon(cb) iter_info = [] for info in await f.enumerate_children_async("standard::*", 0, GLib.PRIORITY_DEFAULT): iter_info.append(info.get_name()) # The await runs the mainloop and cb is called. self.assertEqual(called, True) next_info = [] enumerator = f.enumerate_children("standard::*", 0, None) while True: info = enumerator.next_file(None) if info is None: break next_info.append(info.get_name()) self.assertEqual(iter_info, next_info) self.loop.run_until_complete(run()) def test_async_cancellation(self): """Cancellation raises G_IO_ERROR_CANCELLED""" f = Gio.file_new_for_path("./") async def run(): nonlocal self # cancellable created implicitly res = f.enumerate_children_async("standard::*", 0, GLib.PRIORITY_DEFAULT) res.cancel() with self.assertRaisesRegex(GLib.GError, "Operation was cancelled"): await res # cancellable passed explicitly cancel = Gio.Cancellable() res = f.enumerate_children_async("standard::*", 0, GLib.PRIORITY_DEFAULT, cancel) self.assertEqual(res.cancellable, cancel) cancel.cancel() with self.assertRaisesRegex(GLib.GError, "Operation was cancelled"): await res self.loop.run_until_complete(run()) def test_not_completed(self): """Querying an uncompleted task raises exceptions""" f = Gio.file_new_for_path("./") async def run(): nonlocal self # cancellable created implicitly res = f.enumerate_children_async("standard::*", 0, GLib.PRIORITY_DEFAULT) with self.assertRaises(asyncio.InvalidStateError): res.result() with self.assertRaises(asyncio.InvalidStateError): res.exception() # And, await it await res self.loop.run_until_complete(run()) def test_async_cancel_completed(self): """Cancelling a completed task just cancels the cancellable""" f = Gio.file_new_for_path("./") async def run(): nonlocal self res = f.enumerate_children_async("standard::*", 0, GLib.PRIORITY_DEFAULT) await res assert not res.cancellable.is_cancelled() res.cancel() assert res.cancellable.is_cancelled() self.loop.run_until_complete(run()) def test_async_completed_add_cb(self): """Adding a done cb to a completed future queues it with call_soon""" f = Gio.file_new_for_path("./") called = False def cb(): nonlocal called called = True async def run(): nonlocal called, self res = f.enumerate_children_async("standard::*", 0, GLib.PRIORITY_DEFAULT) await res self.loop.call_soon(cb) # Python await is smart and does not iterate the EventLoop await res assert not called # So create a new future and wait on that fut = asyncio.Future() def done_cb(res): nonlocal fut fut.set_result(res.result()) res.add_done_callback(done_cb) await fut assert called self.loop.run_until_complete(run()) @pytest.mark.xfail(platform.python_implementation() == "PyPy", reason="Exception reporting does not work in pypy") def test_deleting_failed_logs(self): f = Gio.file_new_for_path("./") async def run(): nonlocal self res = f.enumerate_children_async("standard::*", 0, GLib.PRIORITY_DEFAULT) res.cancel() # Cancellation in Gio is not immediate, so sleep for a bit await asyncio.sleep(0.5) exc = None msg = None def handler(loop, context): nonlocal exc, msg msg = context['message'] exc = context['exception'] self.loop.set_exception_handler(handler) self.loop.run_until_complete(run()) self.assertRegex(msg, ".*exception was never retrieved") self.assertIsInstance(exc, GLib.GError) assert exc.matches(Gio.io_error_quark(), Gio.IOErrorEnum.CANCELLED) def test_no_running_loop(self): f = Gio.file_new_for_path("./") res = f.enumerate_children_async("standard::*", 0, GLib.PRIORITY_DEFAULT) self.assertIsNone(res) def test_wrong_default_context(self): f = Gio.file_new_for_path("./") async def run(): nonlocal self ctx = GLib.MainContext.new() GLib.MainContext.push_thread_default(ctx) self.addCleanup(GLib.MainContext.pop_thread_default, ctx) res = f.enumerate_children_async("standard::*", 0, GLib.PRIORITY_DEFAULT) self.assertIsNone(res) self.loop.run_until_complete(run()) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/tests/test_atoms.py0000664000000000000000000000706215074674453016251 0ustar00rootrootimport os import unittest try: from gi.repository import Gtk, Gdk except ImportError: Gdk = None Gtk = None from .helper import capture_glib_deprecation_warnings def is_X11(): try: from gi.repository import Gdk, GdkX11 except ImportError: return False display = Gdk.Display.get_default() return isinstance(display, GdkX11.X11Display) @unittest.skipUnless(Gdk, 'Gdk not available') @unittest.skipIf(Gdk and Gdk._version == "4.0", 'Gdk4 doesn\'t have GdkAtom') class TestGdkAtom(unittest.TestCase): def test_create(self): atom = Gdk.Atom.intern('my_string', False) self.assertEqual(atom.name(), 'my_string') def test_str(self): atom = Gdk.Atom.intern('my_string', False) self.assertEqual(str(atom), 'my_string') self.assertEqual(str(Gdk.SELECTION_CLIPBOARD), 'CLIPBOARD') def test_repr(self): # __repr__ should generate a string which is parsable when possible # http://docs.python.org/2/reference/datamodel.html#object.__repr__ atom = Gdk.Atom.intern('my_string', False) self.assertEqual(repr(atom), 'Gdk.Atom.intern("my_string", False)') self.assertEqual(eval(repr(atom)), atom) self.assertEqual(repr(Gdk.SELECTION_CLIPBOARD), 'Gdk.Atom.intern("CLIPBOARD", False)') @unittest.skipUnless(os.name != "nt", "not on Windows") def test_in_single(self): a_selection = Gdk.Atom.intern('test_clipboard', False) clipboard = Gtk.Clipboard.get(a_selection) clipboard.set_text('hello', 5) # needs a Gdk.Atom, not a string self.assertRaises(TypeError, Gtk.Clipboard.get, 'CLIPBOARD') def test_in_array(self): a_plain = Gdk.Atom.intern('text/plain', False) a_html = Gdk.Atom.intern('text/html', False) a_jpeg = Gdk.Atom.intern('image/jpeg', False) self.assertFalse(Gtk.targets_include_text([])) self.assertTrue(Gtk.targets_include_text([a_plain, a_html])) self.assertFalse(Gtk.targets_include_text([a_jpeg])) self.assertTrue(Gtk.targets_include_text([a_jpeg, a_plain])) self.assertFalse(Gtk.targets_include_image([], False)) self.assertFalse(Gtk.targets_include_image([a_plain, a_html], False)) self.assertTrue(Gtk.targets_include_image([a_jpeg], False)) self.assertTrue(Gtk.targets_include_image([a_jpeg, a_plain], False)) @unittest.skipUnless(is_X11(), "only on X11") def test_out_array(self): a_selection = Gdk.Atom.intern('my_clipboard', False) clipboard = Gtk.Clipboard.get(a_selection) # empty (res, targets) = clipboard.wait_for_targets() self.assertEqual(res, False) self.assertEqual(targets, []) # text clipboard.set_text('hello', 5) (res, targets) = clipboard.wait_for_targets() self.assertEqual(res, True) self.assertNotEqual(targets, []) self.assertEqual(type(targets[0]), Gdk.Atom) names = [t.name() for t in targets] self.assertFalse(None in names, names) self.assertTrue('TEXT' in names, names) @unittest.skipUnless(is_X11(), "only on X11") @unittest.skipIf(not Gdk or Gdk._version == "4.0", "not in gdk4") def test_out_glist(self): display = Gdk.Display.get_default() with capture_glib_deprecation_warnings(): dm = display.get_device_manager() device = dm.get_client_pointer() axes = device.list_axes() axes_names = [atom.name() for atom in axes if atom is not None] assert all(isinstance(name, str) for name in axes_names) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/tests/test_cairo.py0000664000000000000000000002720715074674453016226 0ustar00rootroot# -*- Mode: Python; py-indent-offset: 4 -*- # vim: tabstop=4 shiftwidth=4 expandtab import unittest import pytest import gi try: gi.require_foreign('cairo') import cairo has_cairo = True except ImportError: has_cairo = False has_region = has_cairo and hasattr(cairo, "Region") try: from gi.repository import Gtk, Gdk Gtk, Gdk # pyflakes except: Gtk = None Gdk = None from gi.repository import GObject, Regress @unittest.skipUnless(has_cairo, 'built without cairo support') class Test(unittest.TestCase): def test_gvalue_converters(self): surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 10, 10) context = cairo.Context(surface) matrix = cairo.Matrix() objects = { 'CairoContext': context, 'CairoSurface': surface, 'CairoFontFace': context.get_font_face(), 'CairoScaledFont': context.get_scaled_font(), 'CairoPattern': context.get_source(), 'CairoMatrix': matrix, } for type_name, cairo_obj in objects.items(): gtype = GObject.type_from_name(type_name) v = GObject.Value() assert v.init(gtype) is None assert v.get_value() is None v.set_value(None) assert v.get_value() is None v.set_value(cairo_obj) assert v.get_value() == cairo_obj def test_cairo_context(self): context = Regress.test_cairo_context_full_return() self.assertTrue(isinstance(context, cairo.Context)) surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 10, 10) context = cairo.Context(surface) Regress.test_cairo_context_none_in(context) def test_cairo_context_full_in(self): surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 10, 10) context = cairo.Context(surface) Regress.test_cairo_context_full_in(context) with pytest.raises(TypeError): Regress.test_cairo_context_full_in(object()) def test_cairo_context_none_return(self): context = Regress.test_cairo_context_none_return() self.assertTrue(isinstance(context, cairo.Context)) def test_cairo_path_full_return(self): path = Regress.test_cairo_path_full_return() if hasattr(cairo, "Path"): # pycairo 1.15.1+ assert isinstance(path, cairo.Path) def test_cairo_path_none_in(self): surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 10, 10) context = cairo.Context(surface) path = context.copy_path() Regress.test_cairo_path_none_in(path) surface.finish() with pytest.raises(TypeError): Regress.test_cairo_path_none_in(object()) def test_cairo_path_full_in_full_return(self): surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 10, 10) context = cairo.Context(surface) context.move_to(10, 10) context.curve_to(10, 10, 3, 4, 5, 6) path = context.copy_path() new_path = Regress.test_cairo_path_full_in_full_return(path) assert list(path) == list(new_path) surface.finish() def test_cairo_font_options_full_return(self): options = Regress.test_cairo_font_options_full_return() assert isinstance(options, cairo.FontOptions) def test_cairo_font_options_none_return(self): options = Regress.test_cairo_font_options_none_return() assert isinstance(options, cairo.FontOptions) def test_cairo_font_options_full_in(self): options = cairo.FontOptions() Regress.test_cairo_font_options_full_in(options) with pytest.raises(TypeError): Regress.test_cairo_font_options_full_in(object()) def test_cairo_font_options_none_in(self): options = cairo.FontOptions() Regress.test_cairo_font_options_none_in(options) def test_cairo_pattern_full_in(self): pattern = cairo.SolidPattern(1, 1, 1, 1) Regress.test_cairo_pattern_full_in(pattern) with pytest.raises(TypeError): Regress.test_cairo_pattern_full_in(object()) def test_cairo_pattern_none_in(self): pattern = cairo.SolidPattern(1, 1, 1, 1) Regress.test_cairo_pattern_none_in(pattern) def test_cairo_pattern_full_return(self): pattern = Regress.test_cairo_pattern_full_return() self.assertTrue(isinstance(pattern, cairo.Pattern)) self.assertTrue(isinstance(pattern, cairo.SolidPattern)) def test_cairo_pattern_none_return(self): pattern = Regress.test_cairo_pattern_none_return() self.assertTrue(isinstance(pattern, cairo.Pattern)) self.assertTrue(isinstance(pattern, cairo.SolidPattern)) def test_cairo_region_full_in(self): region = cairo.Region() Regress.test_cairo_region_full_in(region) with pytest.raises(TypeError): Regress.test_cairo_region_full_in(object()) def test_cairo_matrix_none_in(self): matrix = cairo.Matrix() Regress.test_cairo_matrix_none_in(matrix) with pytest.raises(TypeError): Regress.test_cairo_matrix_none_in(object()) def test_cairo_matrix_none_return(self): matrix = Regress.test_cairo_matrix_none_return() assert matrix == cairo.Matrix() def test_cairo_matrix_out_caller_allocates(self): matrix = Regress.test_cairo_matrix_out_caller_allocates() assert matrix == cairo.Matrix() def test_cairo_surface(self): surface = Regress.test_cairo_surface_none_return() self.assertTrue(isinstance(surface, cairo.ImageSurface)) self.assertTrue(isinstance(surface, cairo.Surface)) self.assertEqual(surface.get_format(), cairo.FORMAT_ARGB32) self.assertEqual(surface.get_width(), 10) self.assertEqual(surface.get_height(), 10) surface = Regress.test_cairo_surface_full_return() self.assertTrue(isinstance(surface, cairo.ImageSurface)) self.assertTrue(isinstance(surface, cairo.Surface)) self.assertEqual(surface.get_format(), cairo.FORMAT_ARGB32) self.assertEqual(surface.get_width(), 10) self.assertEqual(surface.get_height(), 10) surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 10, 10) Regress.test_cairo_surface_none_in(surface) surface = Regress.test_cairo_surface_full_out() self.assertTrue(isinstance(surface, cairo.ImageSurface)) self.assertTrue(isinstance(surface, cairo.Surface)) self.assertEqual(surface.get_format(), cairo.FORMAT_ARGB32) self.assertEqual(surface.get_width(), 10) self.assertEqual(surface.get_height(), 10) def test_cairo_surface_full_in(self): surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 10, 10) Regress.test_cairo_surface_full_in(surface) with pytest.raises(TypeError): Regress.test_cairo_surface_full_in(object()) def test_require_foreign(self): self.assertEqual(gi.require_foreign('cairo'), None) self.assertEqual(gi.require_foreign('cairo', 'Context'), None) self.assertRaises(ImportError, gi.require_foreign, 'invalid_module') self.assertRaises(ImportError, gi.require_foreign, 'invalid_module', 'invalid_symbol') self.assertRaises(ImportError, gi.require_foreign, 'cairo', 'invalid_symbol') @unittest.skipUnless(has_cairo, 'built without cairo support') @unittest.skipUnless(has_region, 'built without cairo.Region support') @unittest.skipUnless(Gdk, 'Gdk not available') class TestRegion(unittest.TestCase): def test_region_to_py(self): surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 10, 10) context = cairo.Context(surface) context.paint() region = Gdk.cairo_region_create_from_surface(surface) r = region.get_extents() self.assertEqual((r.height, r.width), (10, 10)) def test_region_from_py(self): surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 10, 10) context = cairo.Context(surface) region = cairo.Region(cairo.RectangleInt(0, 0, 42, 42)) Gdk.cairo_region(context, region) self.assertTrue("42" in repr(list(context.copy_path()))) @unittest.skipUnless(has_cairo, 'built without cairo support') @unittest.skipUnless(Gtk, 'Gtk not available') class TestPango(unittest.TestCase): def test_cairo_font_options(self): window = Gtk.Window() if Gtk._version == "4.0": window.set_font_options(cairo.FontOptions()) font_opts = window.get_font_options() else: screen = window.get_screen() font_opts = screen.get_font_options() assert font_opts is not None self.assertTrue(isinstance(font_opts.get_subpixel_order(), int)) if has_cairo: from gi.repository import cairo as CairoGObject # Use PyGI signals to test non-introspected foreign marshaling. class CairoSignalTester(GObject.Object): sig_context = GObject.Signal(arg_types=[CairoGObject.Context]) sig_surface = GObject.Signal(arg_types=[CairoGObject.Surface]) sig_font_face = GObject.Signal(arg_types=[CairoGObject.FontFace]) sig_scaled_font = GObject.Signal(arg_types=[CairoGObject.ScaledFont]) sig_pattern = GObject.Signal(arg_types=[CairoGObject.Pattern]) @unittest.skipUnless(has_cairo, 'built without cairo support') class TestSignalMarshaling(unittest.TestCase): # Tests round tripping of cairo objects through non-introspected signals. def setUp(self): self.surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, 10, 10) self.context = cairo.Context(self.surface) self.tester = CairoSignalTester() def pass_object_through_signal(self, obj, signal): """Pass the given `obj` through the `signal` emission storing the `obj` passed through the signal and returning it.""" passthrough_result = [] def callback(instance, passthrough): passthrough_result.append(passthrough) signal.connect(callback) signal.emit(obj) return passthrough_result[0] def test_context(self): result = self.pass_object_through_signal(self.context, self.tester.sig_context) self.assertTrue(isinstance(result, cairo.Context)) with pytest.raises(TypeError): self.pass_object_through_signal(object(), self.tester.sig_context) def test_surface(self): result = self.pass_object_through_signal(self.surface, self.tester.sig_surface) self.assertTrue(isinstance(result, cairo.Surface)) def test_font_face(self): font_face = self.context.get_font_face() result = self.pass_object_through_signal(font_face, self.tester.sig_font_face) self.assertTrue(isinstance(result, cairo.FontFace)) with pytest.raises(TypeError): self.pass_object_through_signal(object(), self.tester.sig_font_face) def test_scaled_font(self): scaled_font = cairo.ScaledFont(self.context.get_font_face(), cairo.Matrix(), cairo.Matrix(), self.context.get_font_options()) result = self.pass_object_through_signal(scaled_font, self.tester.sig_scaled_font) self.assertTrue(isinstance(result, cairo.ScaledFont)) with pytest.raises(TypeError): result = self.pass_object_through_signal(object(), self.tester.sig_scaled_font) def test_pattern(self): pattern = cairo.SolidPattern(1, 1, 1, 1) result = self.pass_object_through_signal(pattern, self.tester.sig_pattern) self.assertTrue(isinstance(result, cairo.Pattern)) self.assertTrue(isinstance(result, cairo.SolidPattern)) with pytest.raises(TypeError): result = self.pass_object_through_signal(object(), self.tester.sig_pattern) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/tests/test_docstring.py0000664000000000000000000001173015074674453017117 0ustar00rootrootimport unittest import gi.docstring from gi.repository import Regress from gi.repository import GIMarshallingTests from gi.repository import Gio from gi.repository import GObject from gi.repository import GLib try: from gi.repository import Gtk except ImportError: Gtk = None class Test(unittest.TestCase): def test_api(self): new_func = lambda info: 'docstring test' old_func = gi.docstring.get_doc_string_generator() gi.docstring.set_doc_string_generator(new_func) self.assertEqual(gi.docstring.get_doc_string_generator(), new_func) self.assertEqual(gi.docstring.generate_doc_string(None), 'docstring test') # Set back to original generator gi.docstring.set_doc_string_generator(old_func) self.assertEqual(gi.docstring.get_doc_string_generator(), old_func) def test_final_signature_with_full_inout(self): self.assertEqual(GIMarshallingTests.Object.full_inout.__doc__, 'full_inout(object:GIMarshallingTests.Object) -> object:GIMarshallingTests.Object') def test_overridden_doc_is_not_clobbered(self): self.assertEqual(GIMarshallingTests.OverridesObject.method.__doc__, 'Overridden doc string.') def test_allow_none_with_user_data_defaults(self): g_file_copy_doc = 'copy(self, destination:Gio.File, ' \ 'flags:Gio.FileCopyFlags, ' \ 'cancellable:Gio.Cancellable=None, ' \ 'progress_callback:Gio.FileProgressCallback=None, ' \ 'progress_callback_data=None) -> bool' self.assertEqual(Gio.File.copy.__doc__, g_file_copy_doc) def test_array_length_arg(self): self.assertEqual(GIMarshallingTests.array_in.__doc__, 'array_in(ints:list)') def test_init_function(self): # This tests implicit array length args along with skipping a # boolean return self.assertEqual(GIMarshallingTests.init_function.__doc__, 'init_function(argv:list=None) -> bool, argv:list') def test_boolean_return(self): self.assertEqual(GIMarshallingTests.boolean_return_true.__doc__, 'boolean_return_true() -> bool') @unittest.skipUnless((GLib.MAJOR_VERSION, GLib.MINOR_VERSION) >= (2, 42), "nullable was added in newer glib/gi") # https://bugzilla.gnome.org/show_bug.cgi?id=740301 def test_may_return_none(self): self.assertEqual(Gio.File.get_basename.__doc__, 'get_basename(self) -> str or None') def test_class_doc_constructors(self): doc = GIMarshallingTests.Object.__doc__ self.assertTrue('new(int_:int)' in doc) def test_struct_doc_constructors(self): doc = GIMarshallingTests.BoxedStruct.__doc__ self.assertTrue('new()' in doc) self.assertTrue('BoxedStruct()' in doc) def test_private_struct_constructors(self): # Structs without a size or constructor should have no constructor docs. doc = Regress.TestBoxedPrivate.__doc__ self.assertEqual(doc, '') def test_array_inout_etc(self): self.assertEqual(GIMarshallingTests.array_inout_etc.__doc__, 'array_inout_etc(first:int, ints:list, last:int) -> ints:list, sum:int') def test_array_out_etc(self): self.assertEqual(GIMarshallingTests.array_out_etc.__doc__, 'array_out_etc(first:int, last:int) -> ints:list, sum:int') @unittest.skipUnless(Gtk, 'no Gtk') def test_shared_array_length_with_prior_out_arg(self): # Test the 'iter' out argument does not effect length argument skipping. self.assertRegex( Gtk.ListStore.insert_with_valuesv.__doc__, 'insert_with_values.*\\(self, position:int, columns:list, values:list\\) -> iter:Gtk.TreeIter') def test_sub_class_doc(self): class A(GObject.Object): """first doc""" pass class B(A): """second doc""" pass self.assertEqual(A.__doc__, "first doc") self.assertEqual(B.__doc__, "second doc") def test_sub_class_no_doc(self): class A(GObject.Object): pass class B(A): """sub-class doc""" self.assertEqual(A.__doc__, None) self.assertEqual(B.__doc__, "sub-class doc") @unittest.expectedFailure # https://bugzilla.gnome.org/show_bug.cgi?id=734926 def test_sub_class_doc_setattr(self): class A(GObject.Object): pass class B(A): pass A.__doc__ = 'custom doc' self.assertEqual(A.__doc__, "custom doc") self.assertEqual(B.__doc__, "custom doc") def test_return_array_with_length_argument(self): self.assertEqual( GIMarshallingTests.enum_array_return_type.__doc__, "enum_array_return_type() -> list") ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/tests/test_error.py0000664000000000000000000001452415074674453016260 0ustar00rootroot# -*- Mode: Python; py-indent-offset: 4 -*- # vim: tabstop=4 shiftwidth=4 expandtab # # test_error.py: Tests for GError wrapper implementation # # Copyright (C) 2012 Will Thompson # Copyright (C) 2013 Martin Pitt # Copyright (C) 2014 Simon Feltman # # 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 unittest import pickle from gi.repository import GLib from gi.repository import GIMarshallingTests class TestType(unittest.TestCase): def test_attributes(self): e = GLib.Error('test message', 'mydomain', 42) self.assertEqual(e.message, 'test message') self.assertEqual(e.domain, 'mydomain') self.assertEqual(e.code, 42) def test_new_literal(self): mydomain = GLib.quark_from_string('mydomain') e = GLib.Error.new_literal(mydomain, 'test message', 42) self.assertEqual(e.message, 'test message') self.assertEqual(e.domain, 'mydomain') self.assertEqual(e.code, 42) def test_matches(self): mydomain = GLib.quark_from_string('mydomain') notmydomain = GLib.quark_from_string('notmydomain') e = GLib.Error('test message', 'mydomain', 42) self.assertTrue(e.matches(mydomain, 42)) self.assertFalse(e.matches(notmydomain, 42)) self.assertFalse(e.matches(mydomain, 40)) def test_str(self): e = GLib.Error('test message', 'mydomain', 42) self.assertEqual(str(e), 'mydomain: test message (42)') def test_repr(self): e = GLib.Error('test message', 'mydomain', 42) self.assertEqual(repr(e), "GLib.Error('test message', 'mydomain', 42)") def test_inheritance(self): self.assertTrue(issubclass(GLib.Error, RuntimeError)) def test_pickle(self): def check_pickle(e): assert isinstance(e, GLib.Error) new_e = pickle.loads(pickle.dumps(e)) assert type(new_e) is type(e) assert repr(e) == repr(new_e) e = GLib.Error('test message', 'mydomain', 42) check_pickle(e) try: GLib.file_get_contents("") except Exception as e: check_pickle(e) class ObjectWithVFuncException(GIMarshallingTests.Object): def do_vfunc_meth_with_err(self, x): if x == 42: return True raise GLib.Error('unexpected value %d' % x, 'mydomain', 42) class TestMarshalling(unittest.TestCase): def test_array_in_crash(self): # Previously there was a bug in invoke, in which C arrays were unwrapped # from inside GArrays to be passed to the C function. But when a GError was # set, invoke would attempt to free the C array as if it were a GArray. # This crash is only for C arrays. It does not happen for C functions which # take in GArrays. See https://bugzilla.gnome.org/show_bug.cgi?id=642708 self.assertRaises(GLib.Error, GIMarshallingTests.gerror_array_in, [1, 2, 3]) def test_out(self): # See https://bugzilla.gnome.org/show_bug.cgi?id=666098 error, debug = GIMarshallingTests.gerror_out() self.assertIsInstance(error, GLib.Error) self.assertEqual(error.domain, GIMarshallingTests.CONSTANT_GERROR_DOMAIN) self.assertEqual(error.code, GIMarshallingTests.CONSTANT_GERROR_CODE) self.assertEqual(error.message, GIMarshallingTests.CONSTANT_GERROR_MESSAGE) self.assertEqual(debug, GIMarshallingTests.CONSTANT_GERROR_DEBUG_MESSAGE) def test_out_transfer_none(self): # See https://bugzilla.gnome.org/show_bug.cgi?id=666098 error, debug = GIMarshallingTests.gerror_out_transfer_none() self.assertIsInstance(error, GLib.Error) self.assertEqual(error.domain, GIMarshallingTests.CONSTANT_GERROR_DOMAIN) self.assertEqual(error.code, GIMarshallingTests.CONSTANT_GERROR_CODE) self.assertEqual(error.message, GIMarshallingTests.CONSTANT_GERROR_MESSAGE) self.assertEqual(GIMarshallingTests.CONSTANT_GERROR_DEBUG_MESSAGE, debug) def test_return(self): # See https://bugzilla.gnome.org/show_bug.cgi?id=666098 error = GIMarshallingTests.gerror_return() self.assertIsInstance(error, GLib.Error) self.assertEqual(error.domain, GIMarshallingTests.CONSTANT_GERROR_DOMAIN) self.assertEqual(error.code, GIMarshallingTests.CONSTANT_GERROR_CODE) self.assertEqual(error.message, GIMarshallingTests.CONSTANT_GERROR_MESSAGE) def test_exception(self): with self.assertRaises(GLib.Error) as context: GIMarshallingTests.gerror() e = context.exception self.assertEqual(e.domain, GIMarshallingTests.CONSTANT_GERROR_DOMAIN) self.assertEqual(e.code, GIMarshallingTests.CONSTANT_GERROR_CODE) self.assertEqual(e.message, GIMarshallingTests.CONSTANT_GERROR_MESSAGE) def test_vfunc_no_exception(self): obj = ObjectWithVFuncException() self.assertTrue(obj.vfunc_meth_with_error(42)) def test_vfunc_gerror_exception(self): obj = ObjectWithVFuncException() with self.assertRaises(GLib.Error) as context: obj.vfunc_meth_with_error(-1) e = context.exception self.assertEqual(e.message, 'unexpected value -1') self.assertEqual(e.domain, 'mydomain') self.assertEqual(e.code, 42) def tests_compare_two_gerrors_in_gvalue(self): error = GLib.Error.new_literal(1, "error", 1) error1 = GLib.Error.new_literal(1, "error", 1) GIMarshallingTests.compare_two_gerrors_in_gvalue(error, error1) def test_nullable_error(): error = GLib.Error.new_literal(1, "error", 1) assert GIMarshallingTests.nullable_gerror(error) == 1 assert GIMarshallingTests.nullable_gerror(None) == 0 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/tests/test_events.py0000664000000000000000000003102415074674453016425 0ustar00rootrootimport sys import unittest try: if sys.platform != 'win32': from test.test_asyncio.test_events import UnixEventLoopTestsMixin as GLibEventLoopTestsMixin else: from test.test_asyncio.test_events import EventLoopTestsMixin # There is Mixin for the ProactorEventLoop, so copy the skips class GLibEventLoopTestsMixin(EventLoopTestsMixin): def test_reader_callback(self): raise unittest.SkipTest("IocpEventLoop does not have add_reader()") def test_reader_callback_cancel(self): raise unittest.SkipTest("IocpEventLoop does not have add_reader()") def test_writer_callback(self): raise unittest.SkipTest("IocpEventLoop does not have add_writer()") def test_writer_callback_cancel(self): raise unittest.SkipTest("IocpEventLoop does not have add_writer()") def test_remove_fds_after_closing(self): raise unittest.SkipTest("IocpEventLoop does not have add_reader()") from test.test_asyncio.test_subprocess import SubprocessMixin from test.test_asyncio.utils import TestCase except: class GLibEventLoopTestsMixin(): def test_unix_event_loop_tests_missing(self): import warnings warnings.warn('UnixEventLoopTestsMixin is unavailable, not running tests!') self.skipTest('UnixEventLoopTestsMixin is unavailable, not running tests!') class SubprocessMixin(): def test_subprocess_mixin_tests_missing(self): import warnings warnings.warn('SubprocessMixin is unavailable, not running tests!') self.skipTest('SubprocessMixin is unavailable, not running tests!') from unittest import TestCase import sys import gi import gi.events import asyncio import socket import threading from gi.repository import GLib try: from gi.repository import Gtk except ImportError: Gtk = None GTK4 = (Gtk and Gtk._version == "4.0") class GLibEventLoopTests(GLibEventLoopTestsMixin, TestCase): def __init__(self, *args): super().__init__(*args) self.loop = None def create_event_loop(self): return gi.events.GLibEventLoop(GLib.MainContext()) class SubprocessWatcherTests(SubprocessMixin, TestCase): def setUp(self): super().setUp() policy = gi.events.GLibEventLoopPolicy() asyncio.set_event_loop_policy(policy) self.loop = policy.get_event_loop() def tearDown(self): asyncio.set_event_loop_policy(None) self.loop.close() super().tearDown() # Fix broken test for Python 3.12 @unittest.skipUnless(sys.version_info >= (3, 12), "test is added in Python 3.12") def test_subprocess_consistent_callbacks(self): # gh-108973: Test that all subprocess protocol methods are called. # The protocol methods are not called in a determistic order. # The order depends on the event loop and the operating system. events = [] fds = [1, 2] expected = [ ('pipe_data_received', 1, b'stdout'), ('pipe_data_received', 2, b'stderr'), ('pipe_connection_lost', 1), ('pipe_connection_lost', 2), 'process_exited', ] per_fd_expected = [ 'pipe_data_received', 'pipe_connection_lost', ] class MyProtocol(asyncio.SubprocessProtocol): def __init__(self, exit_future: asyncio.Future) -> None: self.exit_future = exit_future def pipe_data_received(self, fd, data) -> None: events.append(('pipe_data_received', fd, data)) self.exit_maybe() def pipe_connection_lost(self, fd, exc) -> None: events.append(('pipe_connection_lost', fd)) self.exit_maybe() def process_exited(self) -> None: events.append('process_exited') self.exit_maybe() def exit_maybe(self): # Only exit when we got all expected events if len(events) >= len(expected): self.exit_future.set_result(True) async def main() -> None: loop = asyncio.get_running_loop() exit_future = asyncio.Future() code = 'import sys; sys.stdout.write("stdout"); sys.stderr.write("stderr")' transport, _ = await loop.subprocess_exec(lambda: MyProtocol(exit_future), sys.executable, '-c', code, stdin=None) await exit_future transport.close() return events events = self.loop.run_until_complete(main()) # First, make sure that we received all events self.assertSetEqual(set(events), set(expected)) # Second, check order of pipe events per file descriptor per_fd_events = {fd: [] for fd in fds} for event in events: if event == 'process_exited': continue name, fd = event[:2] per_fd_events[fd].append(name) for fd in fds: self.assertEqual(per_fd_events[fd], per_fd_expected, (fd, events)) class GLibEventLoopPolicyTests(unittest.TestCase): def create_policy(self): return gi.events.GLibEventLoopPolicy() def test_get_event_loop(self): policy = self.create_policy() loop = policy.get_event_loop() self.assertIsInstance(loop, gi.events.GLibEventLoop) self.assertIs(loop, policy.get_event_loop()) loop.close() def test_new_event_loop(self): policy = self.create_policy() loop = policy.new_event_loop() self.assertIsInstance(loop, gi.events.GLibEventLoop) loop.close() # Attaching a loop to the main thread fails with self.assertRaises(RuntimeError): policy.set_event_loop(loop) def test_nested_context_iteration(self): policy = self.create_policy() loop = policy.new_event_loop() called = False def cb(): nonlocal called called = True async def run(): nonlocal loop, called loop.call_soon(cb) self.assertEqual(called, False) # Iterating the main context does not cause cb to be called while loop._context.iteration(False): pass self.assertEqual(called, False) # Awaiting on anything *does* cause the cb to fire await asyncio.sleep(0) self.assertEqual(called, True) loop.run_until_complete(run()) loop.close() def test_thread_event_loop(self): policy = self.create_policy() loop = policy.new_event_loop() res = [] def thread_func(res): try: # We cannot get an event loop for the current thread with self.assertRaises(RuntimeError): policy.get_event_loop() # We can attach our loop policy.set_event_loop(loop) # Now we can get it, and it is the same self.assertIs(policy.get_event_loop(), loop) # Simple call_soon test results = [] def callback(arg1, arg2): results.append((arg1, arg2)) loop.stop() loop.call_soon(callback, 'hello', 'world') loop.run_forever() self.assertEqual(results, [('hello', 'world')]) # We can detach it again policy.set_event_loop(None) # Which means we have none and get a runtime error with self.assertRaises(RuntimeError): policy.get_event_loop() except: res += sys.exc_info() # Initially, the thread has no event loop thread = threading.Thread(target=lambda: thread_func(res)) thread.start() thread.join() if res: t, v, tb = res raise t(v).with_traceback(tb) loop.close() def test_outside_context_iteration(self): """Iterating the main context from the outside, does not cause the EventLoop to dispatch.""" policy = self.create_policy() loop = policy.new_event_loop() called = False def cb(): nonlocal called called = True loop.call_soon(cb) while loop._context.iteration(False): pass loop.close() self.assertEqual(called, False) def test_inside_context_iteration(self): """Iterating the main context from the inside, does not cause the EventLoop to dispatch.""" policy = self.create_policy() loop = policy.get_event_loop() done = asyncio.Future(loop=loop) called = False def cb(): nonlocal called called = True def ctx_iterate(): nonlocal called loop.call_soon(cb) while loop._context.iteration(False): pass self.assertEqual(called, False) # If we by-pass the override, then the callback is called while super(GLib.MainContext, loop._context).iteration(False): pass self.assertEqual(called, True) # It'll also be called (again) before run_until_complete finishes called = False loop.call_soon(cb) done.set_result(True) return GLib.SOURCE_REMOVE GLib.idle_add(ctx_iterate) loop.run_until_complete(done) loop.close() self.assertEqual(called, True) @unittest.skipUnless(Gtk, 'no Gtk') def test_recursive_stop(self): """Calling stop() on the EventLoop will quit it, even if iteration is done recursively.""" policy = self.create_policy() asyncio.set_event_loop_policy(policy) self.addCleanup(asyncio.set_event_loop_policy, None) loop = policy.get_event_loop() if not GTK4: def main_gtk(): GLib.idle_add(loop.stop) Gtk.main() GLib.idle_add(main_gtk) Gtk.main() def main_glib(): GLib.idle_add(loop.stop) GLib.MainLoop().run() GLib.idle_add(main_glib) GLib.MainLoop().run() loop.close() @unittest.skipIf(sys.platform == 'win32', 'add reader/writer not implemented') def test_source_fileobj_fd(self): """Regression test for https://gitlab.gnome.org/GNOME/pygobject/-/issues/689 """ class Echo: def __init__(self, sock, expect_bytes): self.sock = sock self.sent_bytes = 0 self.expect_bytes = expect_bytes self.done = asyncio.Future() self.data = bytes() def send(self): if self.done.done(): return if self.sent_bytes < len(self.data): self.sent_bytes += self.sock.send( self.data[self.sent_bytes:]) print('sent', self.data) if self.sent_bytes >= self.expect_bytes: self.done.set_result(None) self.sock.shutdown(socket.SHUT_WR) def recv(self): if self.done.done(): return self.data += self.sock.recv(self.expect_bytes) print('received', self.data) if len(self.data) >= self.expect_bytes: self.sock.shutdown(socket.SHUT_RD) async def run(): loop = asyncio.get_running_loop() s1, s2 = socket.socketpair() sample = b'Hello!' e = Echo(s1, len(sample)) # register using file object and file descriptor loop.add_reader(s1, e.recv) loop.add_writer(s1.fileno(), e.send) s2.sendall(sample) await asyncio.wait_for(e.done, timeout=2.0) echo = bytes() for _ in range(len(sample)): echo += s2.recv(len(sample)) if len(echo) == len(sample): break # remove using file object and file descriptor loop.remove_reader(s1) loop.remove_writer(s1.fileno()) s1.close() s2.close() # check if the data was echoed correctly self.assertEqual(sample, echo) policy = self.create_policy() loop = policy.get_event_loop() loop.run_until_complete(run()) loop.close() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/tests/test_everything.py0000664000000000000000000015716715074674453017326 0ustar00rootroot# -*- Mode: Python; py-indent-offset: 4 -*- # vim: tabstop=4 shiftwidth=4 expandtab import unittest import traceback import ctypes import warnings import sys import os import re import platform import gc import timeit import random import pytest from gi.repository import Regress as Everything from gi.repository import GObject from gi.repository import GLib from gi.repository import Gio try: from gi.repository import Gtk Gtk # pyflakes except: Gtk = None from .helper import capture_exceptions const_str = b'const \xe2\x99\xa5 utf8'.decode('UTF-8') noconst_str = 'non' + const_str class RawGList(ctypes.Structure): _fields_ = [('data', ctypes.c_void_p), ('next', ctypes.c_void_p), ('prev', ctypes.c_void_p)] @classmethod def from_wrapped(cls, obj): offset = sys.getsizeof(object()) # size of PyObject_HEAD return ctypes.POINTER(cls).from_address(id(obj) + offset) class TestInstanceTransfer(unittest.TestCase): def test_main(self): obj = Everything.TestObj() for _ in range(10): obj.instance_method_full() class TestEverything(unittest.TestCase): def test_bool(self): self.assertEqual(Everything.test_boolean(False), False) self.assertEqual(Everything.test_boolean(True), True) self.assertEqual(Everything.test_boolean('hello'), True) self.assertEqual(Everything.test_boolean(''), False) self.assertEqual(Everything.test_boolean_true(True), True) self.assertEqual(Everything.test_boolean_false(False), False) def test_int8(self): self.assertEqual(Everything.test_int8(GLib.MAXINT8), GLib.MAXINT8) self.assertEqual(Everything.test_int8(GLib.MININT8), GLib.MININT8) self.assertRaises(OverflowError, Everything.test_int8, GLib.MAXINT8 + 1) with pytest.raises( OverflowError, match="%s not in range %s to %s" % ( GLib.MAXINT8 + 1, GLib.MININT8, GLib.MAXINT8)): Everything.test_int8(GLib.MAXINT8 + 1) with pytest.raises( OverflowError, match="%s not in range %s to %s" % ( GLib.MAXUINT64 * 2, GLib.MININT8, GLib.MAXINT8)): Everything.test_int8(GLib.MAXUINT64 * 2) def test_uint8(self): self.assertEqual(Everything.test_uint8(GLib.MAXUINT8), GLib.MAXUINT8) self.assertEqual(Everything.test_uint8(0), 0) self.assertRaises(OverflowError, Everything.test_uint8, -1) self.assertRaises(OverflowError, Everything.test_uint8, GLib.MAXUINT8 + 1) with pytest.raises( OverflowError, match="%s not in range 0 to %s" % ( GLib.MAXUINT8 + 1, GLib.MAXUINT8)): Everything.test_uint8(GLib.MAXUINT8 + 1) with pytest.raises( OverflowError, match="%s not in range 0 to %s" % ( GLib.MAXUINT64 * 2, GLib.MAXUINT8)): Everything.test_uint8(GLib.MAXUINT64 * 2) def test_int16(self): self.assertEqual(Everything.test_int16(GLib.MAXINT16), GLib.MAXINT16) self.assertEqual(Everything.test_int16(GLib.MININT16), GLib.MININT16) with pytest.raises( OverflowError, match="32768 not in range -32768 to 32767"): Everything.test_int16(GLib.MAXINT16 + 1) with pytest.raises( OverflowError, match="36893488147419103230 not in range -32768 to 32767"): Everything.test_int16(GLib.MAXUINT64 * 2) def test_uint16(self): self.assertEqual(Everything.test_uint16(GLib.MAXUINT16), GLib.MAXUINT16) self.assertEqual(Everything.test_uint16(0), 0) self.assertRaises(OverflowError, Everything.test_uint16, -1) with pytest.raises( OverflowError, match="%s not in range 0 to %s" % ( GLib.MAXUINT16 + 1, GLib.MAXUINT16)): Everything.test_uint16(GLib.MAXUINT16 + 1) with pytest.raises( OverflowError, match="%s not in range 0 to %s" % ( GLib.MAXUINT64 * 2, GLib.MAXUINT16)): Everything.test_uint16(GLib.MAXUINT64 * 2) def test_int32(self): self.assertEqual(Everything.test_int32(GLib.MAXINT32), GLib.MAXINT32) self.assertEqual(Everything.test_int32(GLib.MININT32), GLib.MININT32) with pytest.raises( OverflowError, match="2147483648 not in range -2147483648 to 2147483647"): Everything.test_int32(GLib.MAXINT32 + 1) with pytest.raises( OverflowError, match="%s not in range -2147483648 to 2147483647" % ( GLib.MAXINT64 + 1,)): Everything.test_int32(GLib.MAXINT64 + 1) def test_uint32(self): self.assertEqual(Everything.test_uint32(GLib.MAXUINT32), GLib.MAXUINT32) self.assertEqual(Everything.test_uint32(0), 0) self.assertRaises(OverflowError, Everything.test_uint32, -1) with pytest.raises( OverflowError, match="%s not in range 0 to %s" % ( GLib.MAXUINT32 + 1, GLib.MAXUINT32)): Everything.test_uint32(GLib.MAXUINT32 + 1) with pytest.raises( OverflowError, match="%s not in range 0 to %s" % ( GLib.MAXUINT64 * 2, GLib.MAXUINT32)): Everything.test_uint32(GLib.MAXUINT64 * 2) def test_int64(self): self.assertEqual(Everything.test_int64(GLib.MAXINT64), GLib.MAXINT64) self.assertEqual(Everything.test_int64(GLib.MININT64), GLib.MININT64) with pytest.raises( OverflowError, match="%s not in range %s to %s" % ( GLib.MAXINT64 + 1, GLib.MININT64, GLib.MAXINT64)): Everything.test_int64(GLib.MAXINT64 + 1) with pytest.raises( OverflowError, match="%s not in range %s to %s" % ( GLib.MAXUINT64 * 2, GLib.MININT64, GLib.MAXINT64)): Everything.test_int64(GLib.MAXUINT64 * 2) def test_uint64(self): self.assertEqual(Everything.test_uint64(GLib.MAXUINT64), GLib.MAXUINT64) self.assertEqual(Everything.test_uint64(0), 0) self.assertRaises(OverflowError, Everything.test_uint64, -1) self.assertRaises(OverflowError, Everything.test_uint64, GLib.MAXUINT64 + 1) with pytest.raises( OverflowError, match="%s not in range 0 to %s" % ( GLib.MAXUINT64 + 1, GLib.MAXUINT64)): Everything.test_uint64(GLib.MAXUINT64 + 1) with pytest.raises( OverflowError, match="%s not in range 0 to %s" % ( GLib.MAXUINT64 * 2, GLib.MAXUINT64)): Everything.test_uint64(GLib.MAXUINT64 * 2) def test_int(self): self.assertEqual(Everything.test_int(GLib.MAXINT), GLib.MAXINT) self.assertEqual(Everything.test_int(GLib.MININT), GLib.MININT) with pytest.raises( OverflowError, match="%s not in range %s to %s" % ( GLib.MAXINT + 1, GLib.MININT, GLib.MAXINT)): Everything.test_int(GLib.MAXINT + 1) with pytest.raises( OverflowError, match="%s not in range %s to %s" % ( GLib.MAXUINT64 * 2, GLib.MININT, GLib.MAXINT)): Everything.test_int(GLib.MAXUINT64 * 2) def test_uint(self): self.assertEqual(Everything.test_uint(GLib.MAXUINT), GLib.MAXUINT) self.assertEqual(Everything.test_uint(0), 0) self.assertRaises(OverflowError, Everything.test_uint, -1) with pytest.raises( OverflowError, match="%s not in range 0 to %s" % ( GLib.MAXUINT + 1, GLib.MAXUINT)): Everything.test_uint(GLib.MAXUINT + 1) with pytest.raises( OverflowError, match="%s not in range 0 to %s" % ( GLib.MAXUINT64 * 2, GLib.MAXUINT)): Everything.test_uint(GLib.MAXUINT64 * 2) def test_short(self): self.assertEqual(Everything.test_short(GLib.MAXSHORT), GLib.MAXSHORT) self.assertEqual(Everything.test_short(GLib.MINSHORT), GLib.MINSHORT) with pytest.raises( OverflowError, match="%s not in range %s to %s" % ( GLib.MAXSHORT + 1, GLib.MINSHORT, GLib.MAXSHORT)): Everything.test_short(GLib.MAXSHORT + 1) with pytest.raises( OverflowError, match="%s not in range %s to %s" % ( GLib.MAXUINT64 * 2, GLib.MINSHORT, GLib.MAXSHORT)): Everything.test_short(GLib.MAXUINT64 * 2) def test_ushort(self): self.assertEqual(Everything.test_ushort(GLib.MAXUSHORT), GLib.MAXUSHORT) self.assertEqual(Everything.test_ushort(0), 0) self.assertRaises(OverflowError, Everything.test_ushort, -1) with pytest.raises( OverflowError, match="%s not in range 0 to %s" % ( GLib.MAXUSHORT + 1, GLib.MAXUSHORT)): Everything.test_ushort(GLib.MAXUSHORT + 1) with pytest.raises( OverflowError, match="%s not in range 0 to %s" % ( GLib.MAXUINT64 * 2, GLib.MAXUSHORT)): Everything.test_ushort(GLib.MAXUINT64 * 2) def test_long(self): self.assertEqual(Everything.test_long(GLib.MAXLONG), GLib.MAXLONG) self.assertEqual(Everything.test_long(GLib.MINLONG), GLib.MINLONG) self.assertRaises(OverflowError, Everything.test_long, GLib.MAXLONG + 1) with pytest.raises( OverflowError, match="%s not in range %s to %s" % ( GLib.MAXLONG + 1, GLib.MINLONG, GLib.MAXLONG)): Everything.test_long(GLib.MAXLONG + 1) with pytest.raises( OverflowError, match="%s not in range %s to %s" % ( GLib.MAXUINT64 * 2, GLib.MINLONG, GLib.MAXLONG)): Everything.test_long(GLib.MAXUINT64 * 2) def test_ulong(self): self.assertEqual(Everything.test_ulong(GLib.MAXULONG), GLib.MAXULONG) self.assertEqual(Everything.test_ulong(0), 0) self.assertRaises(OverflowError, Everything.test_ulong, -1) with pytest.raises( OverflowError, match="%s not in range 0 to %s" % ( GLib.MAXULONG + 1, GLib.MAXULONG)): Everything.test_ulong(GLib.MAXULONG + 1) with pytest.raises( OverflowError, match="%s not in range 0 to %s" % ( GLib.MAXUINT64 * 2, GLib.MAXULONG)): Everything.test_ulong(GLib.MAXUINT64 * 2) def test_ssize(self): self.assertEqual(Everything.test_ssize(GLib.MAXSSIZE), GLib.MAXSSIZE) self.assertEqual(Everything.test_ssize(GLib.MINSSIZE), GLib.MINSSIZE) self.assertRaises(OverflowError, Everything.test_ssize, GLib.MAXSSIZE + 1) with pytest.raises( OverflowError, match="%s not in range %s to %s" % ( GLib.MAXSSIZE + 1, GLib.MINSSIZE, GLib.MAXSSIZE)): Everything.test_ssize(GLib.MAXSSIZE + 1) with pytest.raises( OverflowError, match="%s not in range %s to %s" % ( GLib.MAXUINT64 * 2, GLib.MINSSIZE, GLib.MAXSSIZE)): Everything.test_ssize(GLib.MAXUINT64 * 2) def test_size(self): self.assertEqual(Everything.test_size(GLib.MAXSIZE), GLib.MAXSIZE) self.assertEqual(Everything.test_size(0), 0) self.assertRaises(OverflowError, Everything.test_size, -1) self.assertRaises(OverflowError, Everything.test_size, GLib.MAXSIZE + 1) with pytest.raises( OverflowError, match="%s not in range 0 to %s" % ( GLib.MAXSIZE + 1, GLib.MAXSIZE)): Everything.test_size(GLib.MAXSIZE + 1) with pytest.raises( OverflowError, match="%s not in range 0 to %s" % ( GLib.MAXUINT64 * 2, GLib.MAXSIZE)): Everything.test_size(GLib.MAXUINT64 * 2) def test_timet(self): self.assertEqual(Everything.test_timet(42), 42) self.assertRaises(OverflowError, Everything.test_timet, GLib.MAXUINT64 + 1) def test_unichar(self): self.assertEqual("c", Everything.test_unichar("c")) self.assertEqual(chr(sys.maxunicode), Everything.test_unichar(chr(sys.maxunicode))) self.assertEqual(u"♥", Everything.test_unichar(u"♥")) self.assertRaises(TypeError, Everything.test_unichar, "") self.assertRaises(TypeError, Everything.test_unichar, "morethanonechar") def test_float(self): self.assertEqual(Everything.test_float(GLib.MAXFLOAT), GLib.MAXFLOAT) self.assertEqual(Everything.test_float(GLib.MINFLOAT), GLib.MINFLOAT) self.assertRaises(OverflowError, Everything.test_float, GLib.MAXFLOAT * 2) with pytest.raises( OverflowError, match=re.escape("%s not in range %s to %s" % ( GLib.MAXFLOAT * 2, -GLib.MAXFLOAT, GLib.MAXFLOAT))): Everything.test_float(GLib.MAXFLOAT * 2) def test_double(self): self.assertEqual(Everything.test_double(GLib.MAXDOUBLE), GLib.MAXDOUBLE) self.assertEqual(Everything.test_double(GLib.MINDOUBLE), GLib.MINDOUBLE) (two, three) = Everything.test_multi_double_args(2.5) self.assertAlmostEqual(two, 5.0) self.assertAlmostEqual(three, 7.5) def test_value(self): self.assertEqual(Everything.test_int_value_arg(GLib.MAXINT), GLib.MAXINT) self.assertEqual(Everything.test_value_return(GLib.MAXINT), GLib.MAXINT) def test_variant(self): v = Everything.test_gvariant_i() self.assertEqual(v.get_type_string(), 'i') self.assertEqual(v.get_int32(), 1) v = Everything.test_gvariant_s() self.assertEqual(v.get_type_string(), 's') self.assertEqual(v.get_string(), 'one') v = Everything.test_gvariant_v() self.assertEqual(v.get_type_string(), 'v') vi = v.get_variant() self.assertEqual(vi.get_type_string(), 's') self.assertEqual(vi.get_string(), 'contents') v = Everything.test_gvariant_as() self.assertEqual(v.get_type_string(), 'as') self.assertEqual(v.get_strv(), ['one', 'two', 'three']) v = Everything.test_gvariant_asv() self.assertEqual(v.get_type_string(), 'a{sv}') self.assertEqual(v.lookup_value('nosuchkey', None), None) name = v.lookup_value('name', None) self.assertEqual(name.get_string(), 'foo') timeout = v.lookup_value('timeout', None) self.assertEqual(timeout.get_int32(), 10) def test_utf8_const_return(self): self.assertEqual(Everything.test_utf8_const_return(), const_str) def test_utf8_nonconst_return(self): self.assertEqual(Everything.test_utf8_nonconst_return(), noconst_str) def test_utf8_out(self): self.assertEqual(Everything.test_utf8_out(), noconst_str) def test_utf8_const_in(self): Everything.test_utf8_const_in(const_str) def test_utf8_inout(self): self.assertEqual(Everything.test_utf8_inout(const_str), noconst_str) def test_filename_return(self): if os.name != "nt": result = [os.fsdecode(b'\xc3\xa5\xc3\xa4\xc3\xb6'), '/etc/fstab'] else: result = ['åäö', '/etc/fstab'] self.assertEqual(Everything.test_filename_return(), result) def test_int_out_utf8(self): # returns g_utf8_strlen() in out argument self.assertEqual(Everything.test_int_out_utf8(''), 0) self.assertEqual(Everything.test_int_out_utf8('hello world'), 11) self.assertEqual(Everything.test_int_out_utf8('åäö'), 3) def test_utf8_out_out(self): self.assertEqual(Everything.test_utf8_out_out(), ('first', 'second')) def test_utf8_out_nonconst_return(self): self.assertEqual(Everything.test_utf8_out_nonconst_return(), ('first', 'second')) def test_enum(self): self.assertEqual(Everything.test_enum_param(Everything.TestEnum.VALUE1), 'value1') self.assertEqual(Everything.test_enum_param(Everything.TestEnum.VALUE3), 'value3') self.assertRaises(TypeError, Everything.test_enum_param, 'hello') @pytest.mark.xfail("32bit" in platform.architecture() or platform.system() == "Windows", reason="Big enum value doesn't convert to 32 bit (signed) long") def test_enum_unsigned(self): self.assertEqual(Everything.test_unsigned_enum_param(Everything.TestEnumUnsigned.VALUE1), 'value1') self.assertEqual(Everything.test_unsigned_enum_param(Everything.TestEnumUnsigned.VALUE2), 'value2') self.assertRaises(TypeError, Everything.test_unsigned_enum_param, 'hello') def test_flags(self): result = Everything.global_get_flags_out() # assert that it's not an int self.assertEqual(type(result), Everything.TestFlags) self.assertEqual(result, Everything.TestFlags.FLAG1 | Everything.TestFlags.FLAG3) def test_floating(self): e = Everything.TestFloating() self.assertEqual(e.__grefcount__, 1) e = GObject.new(Everything.TestFloating) self.assertEqual(e.__grefcount__, 1) e = Everything.TestFloating.new() self.assertEqual(e.__grefcount__, 1) def test_caller_allocates(self): struct_a = Everything.TestStructA() struct_a.some_int = 10 struct_a.some_int8 = 21 struct_a.some_double = 3.14 struct_a.some_enum = Everything.TestEnum.VALUE3 struct_a_clone = struct_a.clone() self.assertTrue(struct_a != struct_a_clone) self.assertEqual(struct_a.some_int, struct_a_clone.some_int) self.assertEqual(struct_a.some_int8, struct_a_clone.some_int8) self.assertEqual(struct_a.some_double, struct_a_clone.some_double) self.assertEqual(struct_a.some_enum, struct_a_clone.some_enum) struct_b = Everything.TestStructB() struct_b.some_int8 = 8 struct_b.nested_a.some_int = 20 struct_b.nested_a.some_int8 = 12 struct_b.nested_a.some_double = 333.3333 struct_b.nested_a.some_enum = Everything.TestEnum.VALUE2 struct_b_clone = struct_b.clone() self.assertTrue(struct_b != struct_b_clone) self.assertEqual(struct_b.some_int8, struct_b_clone.some_int8) self.assertEqual(struct_b.nested_a.some_int, struct_b_clone.nested_a.some_int) self.assertEqual(struct_b.nested_a.some_int8, struct_b_clone.nested_a.some_int8) self.assertEqual(struct_b.nested_a.some_double, struct_b_clone.nested_a.some_double) self.assertEqual(struct_b.nested_a.some_enum, struct_b_clone.nested_a.some_enum) struct_a = Everything.test_struct_a_parse('ignored') self.assertEqual(struct_a.some_int, 23) def test_wrong_type_of_arguments(self): try: Everything.test_int8() except TypeError: (e_type, e) = sys.exc_info()[:2] self.assertEqual(e.args, ("Regress.test_int8() takes exactly 1 argument (0 given)",)) def test_gtypes(self): gchararray_gtype = GObject.type_from_name('gchararray') gtype = Everything.test_gtype(str) self.assertEqual(gchararray_gtype, gtype) gtype = Everything.test_gtype('gchararray') self.assertEqual(gchararray_gtype, gtype) gobject_gtype = GObject.GObject.__gtype__ gtype = Everything.test_gtype(GObject.GObject) self.assertEqual(gobject_gtype, gtype) gtype = Everything.test_gtype('GObject') self.assertEqual(gobject_gtype, gtype) self.assertRaises(TypeError, Everything.test_gtype, 'invalidgtype') class NotARegisteredClass(object): pass self.assertRaises(TypeError, Everything.test_gtype, NotARegisteredClass) class ARegisteredClass(GObject.GObject): __gtype_name__ = 'EverythingTestsARegisteredClass' gtype = Everything.test_gtype('EverythingTestsARegisteredClass') self.assertEqual(ARegisteredClass.__gtype__, gtype) gtype = Everything.test_gtype(ARegisteredClass) self.assertEqual(ARegisteredClass.__gtype__, gtype) self.assertRaises(TypeError, Everything.test_gtype, 'ARegisteredClass') def test_dir(self): attr_list = dir(Everything) # test that typelib attributes are listed self.assertTrue('TestStructA' in attr_list) # test that class attributes and methods are listed self.assertTrue('__class__' in attr_list) self.assertTrue('__dir__' in attr_list) self.assertTrue('__repr__' in attr_list) # test that instance members are listed self.assertTrue('_namespace' in attr_list) self.assertTrue('_version' in attr_list) # test that there are no duplicates returned self.assertEqual(len(attr_list), len(set(attr_list))) def test_array_int_in_empty(self): self.assertEqual(Everything.test_array_int_in([]), 0) def test_array_int_in(self): self.assertEqual(Everything.test_array_int_in([1, 5, -2]), 4) def test_array_int_out(self): self.assertEqual(Everything.test_array_int_out(), [0, 1, 2, 3, 4]) def test_array_int_full_out(self): self.assertEqual(Everything.test_array_int_full_out(), [0, 1, 2, 3, 4]) def test_array_int_none_out(self): self.assertEqual(Everything.test_array_int_none_out(), [1, 2, 3, 4, 5]) def test_array_int_inout(self): self.assertEqual(Everything.test_array_int_inout([1, 5, 42, -8]), [6, 43, -7]) def test_array_int_inout_empty(self): self.assertEqual(Everything.test_array_int_inout([]), []) def test_array_gint8_in(self): self.assertEqual(Everything.test_array_gint8_in(b'\x01\x03\x05'), 9) self.assertEqual(Everything.test_array_gint8_in([1, 3, 5, -50]), -41) def test_array_gint16_in(self): self.assertEqual(Everything.test_array_gint16_in([256, 257, -1000, 10000]), 9513) def test_array_gint32_in(self): self.assertEqual(Everything.test_array_gint32_in([30000, 1, -2]), 29999) def test_array_gint64_in(self): self.assertEqual(Everything.test_array_gint64_in([2 ** 33, 2 ** 34]), 2 ** 33 + 2 ** 34) def test_array_gtype_in(self): self.assertEqual(Everything.test_array_gtype_in( [GObject.TYPE_STRING, GObject.TYPE_UINT64, GObject.TYPE_VARIANT]), '[gchararray,guint64,GVariant,]') def test_array_fixed_size_int_in(self): # fixed length of 5 self.assertEqual(Everything.test_array_fixed_size_int_in([1, 2, -10, 5, 3]), 1) def test_array_fixed_size_int_in_error(self): self.assertRaises(ValueError, Everything.test_array_fixed_size_int_in, [1, 2, 3, 4]) self.assertRaises(ValueError, Everything.test_array_fixed_size_int_in, [1, 2, 3, 4, 5, 6]) def test_array_fixed_size_int_out(self): self.assertEqual(Everything.test_array_fixed_size_int_out(), [0, 1, 2, 3, 4]) def test_array_fixed_size_int_return(self): self.assertEqual(Everything.test_array_fixed_size_int_return(), [0, 1, 2, 3, 4]) def test_array_of_non_utf8_strings(self): with pytest.raises(UnicodeDecodeError): Everything.test_array_of_non_utf8_strings() def test_garray_container_return(self): # GPtrArray transfer container result = Everything.test_garray_container_return() self.assertEqual(result, ['regress']) result = None def test_garray_full_return(self): # GPtrArray transfer full result = Everything.test_garray_full_return() self.assertEqual(result, ['regress']) result = None def test_strv_out(self): self.assertEqual(Everything.test_strv_out(), ['thanks', 'for', 'all', 'the', 'fish']) def test_strv_out_c(self): self.assertEqual(Everything.test_strv_out_c(), ['thanks', 'for', 'all', 'the', 'fish']) def test_strv_out_container(self): self.assertEqual(Everything.test_strv_out_container(), ['1', '2', '3']) def test_strv_outarg(self): self.assertEqual(Everything.test_strv_outarg(), ['1', '2', '3']) def test_strv_in_gvalue(self): self.assertEqual(Everything.test_strv_in_gvalue(), ['one', 'two', 'three']) def test_strv_in(self): Everything.test_strv_in(['1', '2', '3']) def test_glist(self): self.assertEqual(Everything.test_glist_nothing_return(), ['1', '2', '3']) self.assertEqual(Everything.test_glist_nothing_return2(), ['1', '2', '3']) self.assertEqual(Everything.test_glist_container_return(), ['1', '2', '3']) self.assertEqual(Everything.test_glist_everything_return(), ['1', '2', '3']) Everything.test_glist_nothing_in(['1', '2', '3']) Everything.test_glist_nothing_in2(['1', '2', '3']) @unittest.skipUnless(hasattr(Everything, 'test_glist_gtype_container_in'), 'Requires newer version of GI') def test_glist_gtype(self): Everything.test_glist_gtype_container_in( [Everything.TestObj, Everything.TestSubObj]) def test_gslist(self): self.assertEqual(Everything.test_gslist_nothing_return(), ['1', '2', '3']) self.assertEqual(Everything.test_gslist_nothing_return2(), ['1', '2', '3']) self.assertEqual(Everything.test_gslist_container_return(), ['1', '2', '3']) self.assertEqual(Everything.test_gslist_everything_return(), ['1', '2', '3']) Everything.test_gslist_nothing_in(['1', '2', '3']) Everything.test_gslist_nothing_in2(['1', '2', '3']) def test_hash_return(self): expected = {'foo': 'bar', 'baz': 'bat', 'qux': 'quux'} self.assertEqual(Everything.test_ghash_null_return(), None) self.assertEqual(Everything.test_ghash_nothing_return(), expected) self.assertEqual(Everything.test_ghash_nothing_return(), expected) self.assertEqual(Everything.test_ghash_container_return(), expected) self.assertEqual(Everything.test_ghash_everything_return(), expected) result = Everything.test_ghash_gvalue_return() self.assertEqual(result['integer'], 12) self.assertEqual(result['boolean'], True) self.assertEqual(result['string'], 'some text') self.assertEqual(result['strings'], ['first', 'second', 'third']) self.assertEqual(result['flags'], Everything.TestFlags.FLAG1 | Everything.TestFlags.FLAG3) self.assertEqual(result['enum'], Everything.TestEnum.VALUE2) result = None # FIXME: CRITICAL **: Unsupported type ghash def disabled_test_hash_return_nested(self): self.assertEqual(Everything.test_ghash_nested_everything_return(), {}) self.assertEqual(Everything.test_ghash_nested_everything_return2(), {}) def test_hash_in(self): expected = {'foo': 'bar', 'baz': 'bat', 'qux': 'quux'} Everything.test_ghash_nothing_in(expected) Everything.test_ghash_nothing_in2(expected) def test_hash_in_with_typed_strv(self): class GStrv(list): __gtype__ = GObject.TYPE_STRV data = {'integer': 12, 'boolean': True, 'string': 'some text', 'strings': GStrv(['first', 'second', 'third']), 'flags': Everything.TestFlags.FLAG1 | Everything.TestFlags.FLAG3, 'enum': Everything.TestEnum.VALUE2, } Everything.test_ghash_gvalue_in(data) data = None def test_hash_in_with_gvalue_strv(self): data = {'integer': 12, 'boolean': True, 'string': 'some text', 'strings': GObject.Value(GObject.TYPE_STRV, ['first', 'second', 'third']), 'flags': Everything.TestFlags.FLAG1 | Everything.TestFlags.FLAG3, 'enum': Everything.TestEnum.VALUE2, } Everything.test_ghash_gvalue_in(data) data = None @unittest.skipIf(platform.python_implementation() == "PyPy", "CPython only") def test_struct_gpointer(self): glist = GLib.List() raw = RawGList.from_wrapped(glist) # Note that pointer fields use 0 for NULL in PyGObject and None in ctypes self.assertEqual(glist.data, 0) self.assertEqual(raw.contents.data, None) glist.data = 123 self.assertEqual(glist.data, 123) self.assertEqual(raw.contents.data, 123) glist.data = None self.assertEqual(glist.data, 0) self.assertEqual(raw.contents.data, None) # Setting to anything other than an int should raise self.assertRaises(TypeError, setattr, glist.data, 'nan') self.assertRaises(TypeError, setattr, glist.data, object()) self.assertRaises(TypeError, setattr, glist.data, 123.321) def test_struct_opaque(self): # we should get a sensible error message try: Everything.TestBoxedPrivate() self.fail('allocating disguised struct without default constructor unexpectedly succeeded') except TypeError: (e_type, e_value, e_tb) = sys.exc_info() self.assertEqual(e_type, TypeError) self.assertTrue('TestBoxedPrivate' in str(e_value), str(e_value)) self.assertTrue('constructor' in str(e_value), str(e_value)) tb = ''.join(traceback.format_exception(e_type, e_value, e_tb)) self.assertTrue('test_everything.py", line' in tb, tb) class TestNullableArgs(unittest.TestCase): def test_in_nullable_hash(self): Everything.test_ghash_null_in(None) def test_in_nullable_list(self): Everything.test_gslist_null_in(None) Everything.test_glist_null_in(None) Everything.test_gslist_null_in([]) Everything.test_glist_null_in([]) def test_in_nullable_array(self): Everything.test_array_int_null_in(None) Everything.test_array_int_null_in([]) def test_in_nullable_string(self): Everything.test_utf8_null_in(None) def test_in_nullable_object(self): Everything.func_obj_null_in(None) def test_out_nullable_hash(self): self.assertEqual(None, Everything.test_ghash_null_out()) def test_out_nullable_list(self): self.assertEqual([], Everything.test_gslist_null_out()) self.assertEqual([], Everything.test_glist_null_out()) def test_out_nullable_array(self): self.assertEqual([], Everything.test_array_int_null_out()) def test_out_nullable_string(self): self.assertEqual(None, Everything.test_utf8_null_out()) def test_out_nullable_object(self): self.assertEqual(None, Everything.TestObj.null_out()) class TestCallbacks(unittest.TestCase): called = False main_loop = GLib.MainLoop() def test_callback(self): TestCallbacks.called = False def callback(): TestCallbacks.called = True Everything.test_simple_callback(callback) self.assertTrue(TestCallbacks.called) def test_callback_exception(self): """ This test ensures that we get errors from callbacks correctly and in particular that we do not segv when callbacks fail """ def callback(): x = 1 / 0 self.fail('unexpected surviving zero divsion:' + str(x)) # note that we do NOT expect the ZeroDivisionError to be propagated # through from the callback, as it crosses the Python<->C boundary # twice. (See GNOME #616279) with capture_exceptions() as exc: Everything.test_simple_callback(callback) self.assertTrue(exc) self.assertEqual(exc[0].type, ZeroDivisionError) def test_double_callback_exception(self): """ This test ensures that we get errors from callbacks correctly and in particular that we do not segv when callbacks fail """ def badcallback(): x = 1 / 0 self.fail('unexpected surviving zero divsion:' + str(x)) def callback(): Everything.test_boolean(True) Everything.test_boolean(False) Everything.test_simple_callback(badcallback()) # note that we do NOT expect the ZeroDivisionError to be propagated # through from the callback, as it crosses the Python<->C boundary # twice. (See GNOME #616279) with capture_exceptions() as exc: Everything.test_simple_callback(callback) self.assertTrue(exc) self.assertEqual(exc[0].type, ZeroDivisionError) def test_return_value_callback(self): TestCallbacks.called = False def callback(): TestCallbacks.called = True return 44 self.assertEqual(Everything.test_callback(callback), 44) self.assertTrue(TestCallbacks.called) def test_callback_scope_async(self): TestCallbacks.called = False ud = 'Test Value 44' def callback(user_data): self.assertEqual(user_data, ud) TestCallbacks.called = True return 44 if hasattr(sys, "getrefcount"): ud_refcount = sys.getrefcount(ud) callback_refcount = sys.getrefcount(callback) self.assertEqual(Everything.test_callback_async(callback, ud), None) # Callback should not have run and the ref count is increased by 1 self.assertEqual(TestCallbacks.called, False) if hasattr(sys, "getrefcount"): self.assertEqual(sys.getrefcount(callback), callback_refcount + 1) self.assertEqual(sys.getrefcount(ud), ud_refcount + 1) # test_callback_thaw_async will run the callback previously supplied. # references should be auto decremented after this call. self.assertEqual(Everything.test_callback_thaw_async(), 44) self.assertTrue(TestCallbacks.called) # Make sure refcounts are returned to normal if hasattr(sys, "getrefcount"): self.assertEqual(sys.getrefcount(callback), callback_refcount) self.assertEqual(sys.getrefcount(ud), ud_refcount) def test_callback_scope_call_multi(self): # This tests a callback that gets called multiple times from a # single scope call in python. TestCallbacks.called = 0 def callback(): TestCallbacks.called += 1 return TestCallbacks.called if hasattr(sys, "getrefcount"): refcount = sys.getrefcount(callback) result = Everything.test_multi_callback(callback) # first callback should give 1, second 2, and the function sums them up self.assertEqual(result, 3) self.assertEqual(TestCallbacks.called, 2) if hasattr(sys, "getrefcount"): self.assertEqual(sys.getrefcount(callback), refcount) def test_callback_scope_call_array(self): # This tests a callback that gets called multiple times from a # single scope call in python with array arguments TestCallbacks.callargs = [] # FIXME: would be cleaner without the explicit length args: # def callback(one, two): def callback(one, one_length, two, two_length): TestCallbacks.callargs.append((one, two)) return len(TestCallbacks.callargs) if hasattr(sys, "getrefcount"): refcount = sys.getrefcount(callback) result = Everything.test_array_callback(callback) # first callback should give 1, second 2, and the function sums them up self.assertEqual(result, 3) self.assertEqual(TestCallbacks.callargs, [([-1, 0, 1, 2], ['one', 'two', 'three'])] * 2) if hasattr(sys, "getrefcount"): self.assertEqual(sys.getrefcount(callback), refcount) @unittest.skipUnless(hasattr(Everything, 'test_array_inout_callback'), 'Requires newer version of GI') def test_callback_scope_call_array_inout(self): # This tests a callback that gets called multiple times from a # single scope call in python with inout array arguments TestCallbacks.callargs = [] def callback(ints, ints_length): TestCallbacks.callargs.append(ints) return ints[1:], len(ints[1:]) if hasattr(sys, "getrefcount"): refcount = sys.getrefcount(callback) result = Everything.test_array_inout_callback(callback) self.assertEqual(TestCallbacks.callargs, [[-2, -1, 0, 1, 2], [-1, 0, 1, 2]]) # first callback should give 4, second 3 self.assertEqual(result, 3) if hasattr(sys, "getrefcount"): self.assertEqual(sys.getrefcount(callback), refcount) def test_callback_userdata(self): TestCallbacks.called = 0 def callback(userdata): self.assertEqual(userdata, "Test%d" % TestCallbacks.called) TestCallbacks.called += 1 return TestCallbacks.called for i in range(100): val = Everything.test_callback_user_data(callback, "Test%d" % i) self.assertEqual(val, i + 1) self.assertEqual(TestCallbacks.called, 100) def test_callback_userdata_no_user_data(self): TestCallbacks.called = 0 def callback(): TestCallbacks.called += 1 return TestCallbacks.called for i in range(100): val = Everything.test_callback_user_data(callback) self.assertEqual(val, i + 1) self.assertEqual(TestCallbacks.called, 100) def test_callback_userdata_varargs(self): TestCallbacks.called = 0 collected_user_data = [] def callback(a, b): collected_user_data.extend([a, b]) TestCallbacks.called += 1 return TestCallbacks.called for i in range(10): val = Everything.test_callback_user_data(callback, 1, 2) self.assertEqual(val, i + 1) self.assertEqual(TestCallbacks.called, 10) self.assertSequenceEqual(collected_user_data, [1, 2] * 10) def test_callback_userdata_as_kwarg_tuple(self): TestCallbacks.called = 0 collected_user_data = [] def callback(user_data): collected_user_data.extend(user_data) TestCallbacks.called += 1 return TestCallbacks.called for i in range(10): val = Everything.test_callback_user_data(callback, user_data=(1, 2)) self.assertEqual(val, i + 1) self.assertEqual(TestCallbacks.called, 10) self.assertSequenceEqual(collected_user_data, [1, 2] * 10) def test_callback_user_data_middle_none(self): cb_info = {} def callback(userdata): cb_info['called'] = True cb_info['userdata'] = userdata return 1 (y, z, q) = Everything.test_torture_signature_2( 42, callback, None, 'some string', 3) self.assertEqual(y, 42) self.assertEqual(z, 84) self.assertEqual(q, 14) self.assertTrue(cb_info['called']) self.assertEqual(cb_info['userdata'], None) def test_callback_user_data_middle_single(self): cb_info = {} def callback(userdata): cb_info['called'] = True cb_info['userdata'] = userdata return 1 (y, z, q) = Everything.test_torture_signature_2( 42, callback, 'User Data', 'some string', 3) self.assertEqual(y, 42) self.assertEqual(z, 84) self.assertEqual(q, 14) self.assertTrue(cb_info['called']) self.assertEqual(cb_info['userdata'], 'User Data') def test_callback_user_data_middle_tuple(self): cb_info = {} def callback(userdata): cb_info['called'] = True cb_info['userdata'] = userdata return 1 (y, z, q) = Everything.test_torture_signature_2( 42, callback, (-5, 'User Data'), 'some string', 3) self.assertEqual(y, 42) self.assertEqual(z, 84) self.assertEqual(q, 14) self.assertTrue(cb_info['called']) self.assertEqual(cb_info['userdata'], (-5, 'User Data')) def test_async_ready_callback(self): TestCallbacks.called = False TestCallbacks.main_loop = GLib.MainLoop() def callback(obj, result, user_data): TestCallbacks.main_loop.quit() TestCallbacks.called = True Everything.test_async_ready_callback(callback) TestCallbacks.main_loop.run() self.assertTrue(TestCallbacks.called) def test_callback_scope_notified_with_destroy(self): TestCallbacks.called = 0 ud = 'Test scope notified data 33' def callback(user_data): self.assertEqual(user_data, ud) TestCallbacks.called += 1 return 33 if hasattr(sys, "getrefcount"): value_refcount = sys.getrefcount(ud) callback_refcount = sys.getrefcount(callback) # Callback is immediately called. for i in range(100): res = Everything.test_callback_destroy_notify(callback, ud) self.assertEqual(res, 33) self.assertEqual(TestCallbacks.called, 100) if hasattr(sys, "getrefcount"): self.assertEqual(sys.getrefcount(callback), callback_refcount + 100) self.assertEqual(sys.getrefcount(ud), value_refcount + 100) # thaw will call the callback again, this time resources should be freed self.assertEqual(Everything.test_callback_thaw_notifications(), 33 * 100) self.assertEqual(TestCallbacks.called, 200) if hasattr(sys, "getrefcount"): self.assertEqual(sys.getrefcount(callback), callback_refcount) self.assertEqual(sys.getrefcount(ud), value_refcount) def test_callback_scope_notified_with_destroy_no_user_data(self): TestCallbacks.called = 0 def callback(user_data): self.assertEqual(user_data, None) TestCallbacks.called += 1 return 34 if hasattr(sys, "getrefcount"): callback_refcount = sys.getrefcount(callback) # Run with warning as exception with warnings.catch_warnings(record=True) as w: warnings.simplefilter("error") self.assertRaises(RuntimeWarning, Everything.test_callback_destroy_notify_no_user_data, callback) self.assertEqual(TestCallbacks.called, 0) if hasattr(sys, "getrefcount"): self.assertEqual(sys.getrefcount(callback), callback_refcount) # Run with warning as warning with warnings.catch_warnings(record=True) as w: # Cause all warnings to always be triggered. warnings.simplefilter("default") # Trigger a warning. res = Everything.test_callback_destroy_notify_no_user_data(callback) # Verify some things self.assertEqual(len(w), 1) self.assertTrue(issubclass(w[-1].category, RuntimeWarning)) self.assertTrue('Callables passed to' in str(w[-1].message)) self.assertEqual(res, 34) self.assertEqual(TestCallbacks.called, 1) if hasattr(sys, "getrefcount"): self.assertEqual(sys.getrefcount(callback), callback_refcount + 1) # thaw will call the callback again, # refcount will not go down without user_data parameter self.assertEqual(Everything.test_callback_thaw_notifications(), 34) self.assertEqual(TestCallbacks.called, 2) if hasattr(sys, "getrefcount"): self.assertEqual(sys.getrefcount(callback), callback_refcount + 1) def test_callback_in_methods(self): object_ = Everything.TestObj() def callback(): TestCallbacks.called = True return 42 TestCallbacks.called = False object_.instance_method_callback(callback) self.assertTrue(TestCallbacks.called) TestCallbacks.called = False Everything.TestObj.static_method_callback(callback) self.assertTrue(TestCallbacks.called) def callbackWithUserData(user_data): TestCallbacks.called += 1 return 42 TestCallbacks.called = 0 Everything.TestObj.new_callback(callbackWithUserData, None) self.assertEqual(TestCallbacks.called, 1) # Note: using "new_callback" adds the notification to the same global # list as Everything.test_callback_destroy_notify, so thaw the list # so we don't get confusion between tests. self.assertEqual(Everything.test_callback_thaw_notifications(), 42) self.assertEqual(TestCallbacks.called, 2) def test_callback_none(self): # make sure this doesn't assert or crash Everything.test_simple_callback(None) def test_callback_gerror(self): def callback(error): self.assertEqual(error.message, 'regression test error') self.assertTrue('g-io' in error.domain) self.assertEqual(error.code, Gio.IOErrorEnum.NOT_SUPPORTED) TestCallbacks.called = True TestCallbacks.called = False Everything.test_gerror_callback(callback) self.assertTrue(TestCallbacks.called) def test_callback_null_gerror(self): def callback(error): self.assertEqual(error, None) TestCallbacks.called = True TestCallbacks.called = False Everything.test_null_gerror_callback(callback) self.assertTrue(TestCallbacks.called) def test_callback_owned_gerror(self): def callback(error): self.assertEqual(error.message, 'regression test owned error') self.assertTrue('g-io' in error.domain) self.assertEqual(error.code, Gio.IOErrorEnum.PERMISSION_DENIED) TestCallbacks.called = True TestCallbacks.called = False Everything.test_owned_gerror_callback(callback) self.assertTrue(TestCallbacks.called) def test_callback_hashtable(self): def callback(data): self.assertEqual(data, mydict) mydict['new'] = 42 TestCallbacks.called = True mydict = {'foo': 1, 'bar': 2} TestCallbacks.called = False Everything.test_hash_table_callback(mydict, callback) self.assertTrue(TestCallbacks.called) self.assertEqual(mydict, {'foo': 1, 'bar': 2, 'new': 42}) class TestClosures(unittest.TestCase): def test_no_arg(self): def callback(): self.called = True return 42 self.called = False result = Everything.test_closure(callback) self.assertTrue(self.called) self.assertEqual(result, 42) def test_int_arg(self): def callback(num): self.called = True return num + 1 self.called = False result = Everything.test_closure_one_arg(callback, 42) self.assertTrue(self.called) self.assertEqual(result, 43) def test_variant(self): def callback(variant): self.called = True if variant is None: return None self.assertEqual(variant.get_type_string(), 'i') return GLib.Variant('i', variant.get_int32() + 1) self.called = False result = Everything.test_closure_variant(callback, GLib.Variant('i', 42)) self.assertTrue(self.called) self.assertEqual(result.get_type_string(), 'i') self.assertEqual(result.get_int32(), 43) self.called = False result = Everything.test_closure_variant(callback, None) self.assertTrue(self.called) self.assertEqual(result, None) self.called = False self.assertRaises(TypeError, Everything.test_closure_variant, callback, 'foo') self.assertFalse(self.called) def test_variant_wrong_return_type(self): def callback(variant): return 'no_variant' with capture_exceptions() as exc: # this does not directly raise an exception (see # https://bugzilla.gnome.org/show_bug.cgi?id=616279) result = Everything.test_closure_variant(callback, GLib.Variant('i', 42)) # ... but the result shouldn't be a string self.assertEqual(result, None) # and the error should be shown self.assertEqual(len(exc), 1) self.assertEqual(exc[0].type, TypeError) self.assertTrue('return value' in str(exc[0].value), exc[0].value) class TestBoxed(unittest.TestCase): def test_boxed(self): object_ = Everything.TestObj() self.assertEqual(object_.props.boxed, None) boxed = Everything.TestBoxed() boxed.some_int8 = 42 object_.props.boxed = boxed self.assertTrue(isinstance(object_.props.boxed, Everything.TestBoxed)) self.assertEqual(object_.props.boxed.some_int8, 42) def test_boxed_alternative_constructor(self): boxed = Everything.TestBoxed.new_alternative_constructor1(5) self.assertEqual(boxed.some_int8, 5) boxed = Everything.TestBoxed.new_alternative_constructor2(5, 3) self.assertEqual(boxed.some_int8, 8) boxed = Everything.TestBoxed.new_alternative_constructor3("-3") self.assertEqual(boxed.some_int8, -3) def test_boxed_equality(self): boxed42 = Everything.TestBoxed.new_alternative_constructor1(42) boxed5 = Everything.TestBoxed.new_alternative_constructor1(5) boxed42_2 = Everything.TestBoxed.new_alternative_constructor2(41, 1) self.assertFalse(boxed42.equals(boxed5)) self.assertTrue(boxed42.equals(boxed42_2)) self.assertTrue(boxed42_2.equals(boxed42)) self.assertTrue(boxed42.equals(boxed42)) def test_boxed_b_constructor(self): with warnings.catch_warnings(record=True) as warn: warnings.simplefilter('always') boxed = Everything.TestBoxedB(42, 47) self.assertTrue(issubclass(warn[0].category, DeprecationWarning)) self.assertEqual(boxed.some_int8, 0) self.assertEqual(boxed.some_long, 0) def test_boxed_c_equality(self): boxed = Everything.TestBoxedC() # TestBoxedC uses refcounting, so we know that # the pointer is the same when copied copy = boxed.copy() self.assertEqual(boxed, copy) self.assertNotEqual(id(boxed), id(copy)) def test_boxed_c_wrapper(self): wrapper = Everything.TestBoxedCWrapper() obj = wrapper.get() # TestBoxedC uses refcounting, so we know that # it should be 2 at this point: # - one owned by @wrapper # - another owned by @obj self.assertEqual(obj.refcount, 2) del wrapper gc.collect() gc.collect() self.assertEqual(obj.refcount, 1) def test_boxed_c_wrapper_copy(self): wrapper = Everything.TestBoxedCWrapper() wrapper_copy = wrapper.copy() obj = wrapper.get() # TestBoxedC uses refcounting, so we know that # it should be 3 at this point: # - one owned by @wrapper # - one owned by @wrapper_copy # - another owned by @obj self.assertEqual(obj.refcount, 3) del wrapper gc.collect() gc.collect() self.assertEqual(obj.refcount, 2) del wrapper_copy gc.collect() gc.collect() self.assertEqual(obj.refcount, 1) del obj gc.collect() gc.collect() def test_array_fixed_boxed_none_out(self): arr = Everything.test_array_fixed_boxed_none_out() assert len(arr) == 2 assert arr[0].refcount == 2 assert arr[1].refcount == 2 def test_gvalue_out_boxed(self): # As corruption is random data, check several times. for i in range(10): int8 = random.randint(GLib.MININT8, GLib.MAXINT8) assert Everything.test_gvalue_out_boxed(int8).some_int8 == int8 def test_glist_boxed_none_return(self): assert len(Everything.test_glist_boxed_none_return(0)) == 0 list_ = Everything.test_glist_boxed_none_return(2) assert len(list_) == 2 assert list_[0].refcount == 2 assert list_[1].refcount == 2 def test_glist_boxed_full_return(self): assert len(Everything.test_glist_boxed_full_return(0)) == 0 list_ = Everything.test_glist_boxed_full_return(2) assert len(list_) == 2 assert list_[0].refcount == 1 assert list_[1].refcount == 1 class TestTortureProfile(unittest.TestCase): def test_torture_profile(self): total_time = 0 print("") object_ = Everything.TestObj() sys.stdout.write("\ttorture test 1 (10000 iterations): ") start_time = timeit.default_timer() for i in range(10000): (y, z, q) = object_.torture_signature_0(5000, "Torture Test 1", 12345) end_time = timeit.default_timer() delta_time = end_time - start_time total_time += delta_time print("%f secs" % delta_time) sys.stdout.write("\ttorture test 2 (10000 iterations): ") start_time = timeit.default_timer() for i in range(10000): (y, z, q) = Everything.TestObj().torture_signature_0( 5000, "Torture Test 2", 12345) end_time = timeit.default_timer() delta_time = end_time - start_time total_time += delta_time print("%f secs" % delta_time) sys.stdout.write("\ttorture test 3 (10000 iterations): ") start_time = timeit.default_timer() for i in range(10000): try: (y, z, q) = object_.torture_signature_1( 5000, "Torture Test 3", 12345) except: pass end_time = timeit.default_timer() delta_time = end_time - start_time total_time += delta_time print("%f secs" % delta_time) sys.stdout.write("\ttorture test 4 (10000 iterations): ") def callback(userdata): return 0 userdata = [1, 2, 3, 4] start_time = timeit.default_timer() for i in range(10000): (y, z, q) = Everything.test_torture_signature_2( 5000, callback, userdata, "Torture Test 4", 12345) end_time = timeit.default_timer() delta_time = end_time - start_time total_time += delta_time print("%f secs" % delta_time) print("\t====") print("\tTotal: %f sec" % total_time) class TestAdvancedInterfaces(unittest.TestCase): def test_array_objs(self): obj1, obj2 = Everything.test_array_fixed_out_objects() self.assertTrue(isinstance(obj1, Everything.TestObj)) self.assertTrue(isinstance(obj2, Everything.TestObj)) self.assertNotEqual(obj1, obj2) def test_obj_skip_return_val(self): obj = Everything.TestObj() ret = obj.skip_return_val(50, 42.0, 60, 2, 3) self.assertEqual(len(ret), 3) self.assertEqual(ret[0], 51) self.assertEqual(ret[1], 61) self.assertEqual(ret[2], 32) def test_obj_skip_return_val_no_out(self): obj = Everything.TestObj() # raises an error for 0, succeeds for any other value self.assertRaises(GLib.GError, obj.skip_return_val_no_out, 0) ret = obj.skip_return_val_no_out(1) self.assertEqual(ret, None) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/tests/test_fields.py0000664000000000000000000001236415074674453016375 0ustar00rootroot# -*- Mode: Python; py-indent-offset: 4 -*- import math import unittest from gi.repository import GLib from gi.repository import Regress from gi.repository import GIMarshallingTests class Number(object): def __init__(self, value): self.value = value def __int__(self): return int(self.value) def __float__(self): return float(self.value) class TestFields(unittest.TestCase): def test_int8(self): s = Regress.TestStructA() s.some_int8 = 21 self.assertEqual(s.some_int8, 21) s.some_int8 = b"\x42" self.assertEqual(s.some_int8, 0x42) self.assertRaises(TypeError, setattr, s, "some_int8", b"ab") self.assertRaises(TypeError, setattr, s, "some_int8", None) self.assertRaises(OverflowError, setattr, s, "some_int8", 128) self.assertRaises(OverflowError, setattr, s, "some_int8", -129) s.some_int8 = 3.6 self.assertEqual(s.some_int8, 3) s.some_int8 = Number(55) self.assertEqual(s.some_int8, 55) def test_int(self): s = Regress.TestStructA() s.some_int = GLib.MAXINT self.assertEqual(s.some_int, GLib.MAXINT) self.assertRaises(TypeError, setattr, s, "some_int", b"a") self.assertRaises(TypeError, setattr, s, "some_int", None) self.assertRaises( OverflowError, setattr, s, "some_int", GLib.MAXINT + 1) self.assertRaises( OverflowError, setattr, s, "some_int", GLib.MININT - 1) s.some_int = 3.6 self.assertEqual(s.some_int, 3) s.some_int = Number(GLib.MININT) self.assertEqual(s.some_int, GLib.MININT) def test_long(self): s = GIMarshallingTests.SimpleStruct() s.long_ = GLib.MAXLONG self.assertEqual(s.long_, GLib.MAXLONG) self.assertRaises(TypeError, setattr, s, "long_", b"a") self.assertRaises(TypeError, setattr, s, "long_", None) self.assertRaises(OverflowError, setattr, s, "long_", GLib.MAXLONG + 1) self.assertRaises(OverflowError, setattr, s, "long_", GLib.MINLONG - 1) s.long_ = 3.6 self.assertEqual(s.long_, 3) s.long_ = Number(GLib.MINLONG) self.assertEqual(s.long_, GLib.MINLONG) def test_double(self): s = Regress.TestStructA() s.some_double = GLib.MAXDOUBLE self.assertEqual(s.some_double, GLib.MAXDOUBLE) s.some_double = GLib.MINDOUBLE self.assertEqual(s.some_double, GLib.MINDOUBLE) s.some_double = float("nan") self.assertTrue(math.isnan(s.some_double)) self.assertRaises(TypeError, setattr, s, "some_double", b"a") self.assertRaises(TypeError, setattr, s, "some_double", None) def test_gtype(self): s = Regress.TestStructE() s.some_type = Regress.TestObj self.assertEqual(s.some_type, Regress.TestObj.__gtype__) self.assertRaises(TypeError, setattr, s, "some_type", 42) def test_unichar(self): # I can't find a unichar field.. pass def test_utf8(self): s = GIMarshallingTests.BoxedStruct() s.string_ = "hello" self.assertEqual(s.string_, "hello") s.string_ = u"hello" self.assertEqual(s.string_, u"hello") s.string_ = None self.assertEqual(s.string_, None) self.assertRaises(TypeError, setattr, s, "string_", 42) def test_array_of_structs(self): s = Regress.TestStructD() self.assertEqual(s.array1, []) self.assertEqual(s.array2, []) def test_interface(self): s = Regress.TestStructC() obj = Regress.TestObj() s.obj = obj self.assertTrue(s.obj is obj) s.obj = None self.assertTrue(s.obj is None) self.assertRaises(TypeError, setattr, s, "obj", object()) def test_glist(self): s = Regress.TestStructD() self.assertEqual(s.list, []) self.assertRaises(TypeError, setattr, s, "list", [object()]) def test_gpointer(self): glist = GLib.List() glist.data = 123 self.assertEqual(glist.data, 123) glist.data = None self.assertEqual(glist.data, 0) def test_gptrarray(self): s = Regress.TestStructD() self.assertEqual(s.garray, []) self.assertRaises(TypeError, setattr, s, "garray", [object()]) def test_enum(self): s = Regress.TestStructA() s.some_enum = Regress.TestEnum.VALUE3 self.assertEqual(s.some_enum, Regress.TestEnum.VALUE3) self.assertRaises(TypeError, setattr, s, "some_enum", object()) s.some_enum = 0 self.assertEqual(s.some_enum, Regress.TestEnum.VALUE1) def test_union(self): s = Regress.TestStructE() self.assertEqual(s.some_union, [None, None]) def test_struct(self): s = GIMarshallingTests.NestedStruct() # FIXME: segfaults # https://bugzilla.gnome.org/show_bug.cgi?id=747002 # s.simple_struct = None self.assertRaises(TypeError, setattr, s, "simple_struct", object()) sub = GIMarshallingTests.SimpleStruct() sub.long_ = 42 s.simple_struct = sub self.assertEqual(s.simple_struct.long_, 42) def test_ghashtable(self): obj = Regress.TestObj() self.assertTrue(obj.hash_table is None) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/tests/test_fundamental.py0000664000000000000000000001132315074674453017417 0ustar00rootrootimport gc import weakref import pytest from gi.repository import GObject, Regress try: from gi.repository import Gtk GTK4 = (Gtk._version == "4.0") except ImportError: Gtk = None GTK4 = False def test_constructor_no_data(): obj = Regress.TestFundamentalSubObject() assert isinstance(obj, Regress.TestFundamentalSubObject) assert isinstance(obj, Regress.TestFundamentalObject) assert obj.refcount == 1 assert obj.data is None def test_constructor_with_data(): with pytest.raises(TypeError): Regress.TestFundamentalSubObject(data='foo') def test_create_fundamental_new_with_data(): obj = Regress.TestFundamentalSubObject.new('foo') assert isinstance(obj, Regress.TestFundamentalSubObject) assert isinstance(obj, Regress.TestFundamentalObject) assert obj.refcount == 1 assert obj.data == 'foo' @pytest.mark.skipif(not hasattr(Regress, "TestFundamentalObjectNoGetSetFunc"), reason="Old versions do not have this type") def test_change_field(): obj = Regress.TestFundamentalObjectNoGetSetFunc.new('foo') obj.data = 'bar' assert obj.get_data() == 'bar' @pytest.mark.skipif(not hasattr(Regress, "TestFundamentalObjectNoGetSetFunc"), reason="Old versions do not have this type") def test_call_method(): obj = Regress.TestFundamentalObjectNoGetSetFunc.new('foo') assert obj.get_data() == 'foo' def test_create_fundamental_hidden_class_instance(): obj = Regress.test_create_fundamental_hidden_class_instance() assert isinstance(obj, Regress.TestFundamentalObject) def test_create_fundamental_refcount(): obj = Regress.TestFundamentalSubObject.new('foo') assert obj.refcount == 1 def test_delete_fundamental_refcount(): obj = Regress.TestFundamentalSubObject.new('foo') del obj gc.collect() def test_value_set_fundamental_object(): val = GObject.Value(Regress.TestFundamentalSubObject.__gtype__) obj = Regress.TestFundamentalSubObject() val.set_value(obj) assert val.get_value() == obj def test_value_set_wrong_value(): val = GObject.Value(Regress.TestFundamentalSubObject.__gtype__) with pytest.raises(TypeError, match="Fundamental type is required"): val.set_value(1) def test_value_set_wrong_fundamental(): val = GObject.Value(Regress.TestFundamentalSubObject.__gtype__) with pytest.raises(TypeError, match="Invalid fundamental type for assignment"): val.set_value(MyCustomFundamentalObject()) def test_array_of_fundamental_objects_in(): assert Regress.test_array_of_fundamental_objects_in([Regress.TestFundamentalSubObject()]) def test_array_of_fundamental_objects_out(): objs = Regress.test_array_of_fundamental_objects_out() assert len(objs) == 2 assert all(isinstance(o, Regress.TestFundamentalObject) for o in objs) def test_fundamental_argument_in(): obj = Regress.TestFundamentalSubObject() assert Regress.test_fundamental_argument_in(obj) def test_abstract_fundamental_type(): with pytest.raises(TypeError): Regress.TestFundamentalObject() def test_fundamental_argument_out(): obj = Regress.TestFundamentalSubObject.new("data") other = Regress.test_fundamental_argument_out(obj) assert type(obj) is type(other) assert obj is not other assert obj.data == other.data def test_multiple_objects(): obj1 = Regress.TestFundamentalSubObject() obj2 = Regress.TestFundamentalSubObject() assert obj1 != obj2 def test_fundamental_weak_ref(): obj = Regress.TestFundamentalSubObject() weak = weakref.ref(obj) assert weak() == obj del obj gc.collect() assert weak() is None def test_fundamental_primitive_object(): bitmask = Regress.Bitmask(2) assert bitmask.v == 2 def test_custom_fundamental_type_vfunc_override(capsys): obj = MyCustomFundamentalObject() del obj gc.collect() out = capsys.readouterr().out assert "MyCustomFundamentalObject.__init__" in out assert "MyCustomFundamentalObject.do_finalize" in out @pytest.mark.skipif(not GTK4, reason="requires GTK 4") def test_gtk_expression(): obj = object() con = Gtk.ConstantExpression.new_for_value(obj) assert con.get_value() is obj @pytest.mark.skipif(not GTK4, reason="requires GTK 4") def test_gtk_string_filter_fundamental_property(): expr = Gtk.ConstantExpression.new_for_value("one") filter = Gtk.StringFilter.new(expr) filter.props.expression = expr assert filter.get_expression() == expr assert filter.props.expression == expr class MyCustomFundamentalObject(Regress.TestFundamentalObject): def __init__(self): print("MyCustomFundamentalObject.__init__") super().__init__() def do_finalize(self): print("MyCustomFundamentalObject.do_finalize") ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/tests/test_gdbus.py0000664000000000000000000003346015074674453016233 0ustar00rootroot# -*- Mode: Python; py-indent-offset: 4 -*- # vim: tabstop=4 shiftwidth=4 expandtab import unittest import pytest from gi.repository import GLib from gi.repository import Gio try: Gio.bus_get_sync(Gio.BusType.SESSION, None) except GLib.Error: has_dbus = False else: has_dbus = True class TestDBusNodeInfo(unittest.TestCase): def test_new_for_xml(self): info = Gio.DBusNodeInfo.new_for_xml(""" """) interfaces = info.interfaces del info assert len(interfaces) == 1 assert interfaces[0].name == "org.freedesktop.DBus.Introspectable" methods = interfaces[0].methods del interfaces assert len(methods) == 1 assert methods[0].name == "Introspect" out_args = methods[0].out_args assert len(out_args) del methods assert out_args[0].name == "data" @unittest.skipUnless(has_dbus, "no dbus running") class TestGDBusClient(unittest.TestCase): def setUp(self): self.bus = Gio.bus_get_sync(Gio.BusType.SESSION, None) self.dbus_proxy = Gio.DBusProxy.new_sync(self.bus, Gio.DBusProxyFlags.NONE, None, 'org.freedesktop.DBus', '/org/freedesktop/DBus', 'org.freedesktop.DBus', None) def test_native_calls_sync(self): result = self.dbus_proxy.call_sync('ListNames', None, Gio.DBusCallFlags.NO_AUTO_START, 500, None) self.assertTrue(isinstance(result, GLib.Variant)) result = result.unpack()[0] # result is always a tuple self.assertTrue(len(result) > 1) self.assertTrue('org.freedesktop.DBus' in result) result = self.dbus_proxy.call_sync('GetNameOwner', GLib.Variant('(s)', ('org.freedesktop.DBus',)), Gio.DBusCallFlags.NO_AUTO_START, 500, None) self.assertTrue(isinstance(result, GLib.Variant)) self.assertEqual(type(result.unpack()[0]), type('')) def test_native_calls_sync_errors(self): # error case: invalid argument types try: self.dbus_proxy.call_sync('GetConnectionUnixProcessID', None, Gio.DBusCallFlags.NO_AUTO_START, 500, None) self.fail('call with invalid arguments should raise an exception') except Exception as e: self.assertTrue('InvalidArgs' in str(e)) # error case: invalid argument try: self.dbus_proxy.call_sync('GetConnectionUnixProcessID', GLib.Variant('(s)', (' unknown',)), Gio.DBusCallFlags.NO_AUTO_START, 500, None) self.fail('call with invalid arguments should raise an exception') except Exception as e: self.assertTrue('NameHasNoOwner' in str(e)) # error case: unknown method try: self.dbus_proxy.call_sync('UnknownMethod', None, Gio.DBusCallFlags.NO_AUTO_START, 500, None) self.fail('call for unknown method should raise an exception') except Exception as e: self.assertTrue('UnknownMethod' in str(e)) def test_native_calls_async(self): def call_done(obj, result, user_data): try: user_data['result'] = obj.call_finish(result) finally: user_data['main_loop'].quit() main_loop = GLib.MainLoop() data = {'main_loop': main_loop} self.dbus_proxy.call('ListNames', None, Gio.DBusCallFlags.NO_AUTO_START, 500, None, call_done, data) main_loop.run() self.assertTrue(isinstance(data['result'], GLib.Variant)) result = data['result'].unpack()[0] # result is always a tuple self.assertTrue(len(result) > 1) self.assertTrue('org.freedesktop.DBus' in result) def test_native_calls_async_errors(self): def call_done(obj, result, user_data): try: obj.call_finish(result) self.fail('call_finish() for unknown method should raise an exception') except Exception as e: self.assertTrue('UnknownMethod' in str(e)) finally: user_data['main_loop'].quit() main_loop = GLib.MainLoop() data = {'main_loop': main_loop} self.dbus_proxy.call('UnknownMethod', None, Gio.DBusCallFlags.NO_AUTO_START, 500, None, call_done, data) main_loop.run() def test_python_calls_sync(self): # single value return tuples get unboxed to the one element result = self.dbus_proxy.ListNames('()') self.assertTrue(isinstance(result, list)) self.assertTrue(len(result) > 1) self.assertTrue('org.freedesktop.DBus' in result) result = self.dbus_proxy.GetNameOwner('(s)', 'org.freedesktop.DBus') self.assertEqual(type(result), type('')) # empty return tuples get unboxed to None self.assertEqual(self.dbus_proxy.ReloadConfig('()'), None) # multiple return values remain a tuple; unfortunately D-BUS itself # does not have any method returning multiple results, so try talking # to notification-daemon (and don't fail the test if it does not exist) try: nd = Gio.DBusProxy.new_sync(self.bus, Gio.DBusProxyFlags.NONE, None, 'org.freedesktop.Notifications', '/org/freedesktop/Notifications', 'org.freedesktop.Notifications', None) result = nd.GetServerInformation('()') self.assertTrue(isinstance(result, tuple)) self.assertEqual(len(result), 4) for i in result: self.assertEqual(type(i), type('')) except Exception as e: if 'Error.ServiceUnknown' not in str(e): raise # test keyword argument; timeout=0 will fail immediately try: self.dbus_proxy.GetConnectionUnixProcessID('(s)', '1', timeout=0) self.fail('call with timeout=0 should raise an exception') except Exception as e: # FIXME: this is not very precise, but in some environments we # do not always get an actual timeout self.assertTrue(isinstance(e, GLib.GError), str(e)) def test_python_calls_sync_noargs(self): # methods without arguments don't need an explicit signature result = self.dbus_proxy.ListNames() self.assertTrue(isinstance(result, list)) self.assertTrue(len(result) > 1) self.assertTrue('org.freedesktop.DBus' in result) def test_python_calls_sync_errors(self): # error case: invalid argument types try: self.dbus_proxy.GetConnectionUnixProcessID('()') self.fail('call with invalid arguments should raise an exception') except Exception as e: self.assertTrue('InvalidArgs' in str(e), str(e)) try: self.dbus_proxy.GetConnectionUnixProcessID(None, 'foo') self.fail('call with None signature should raise an exception') except TypeError as e: self.assertTrue('signature' in str(e), str(e)) def test_python_calls_async(self): def call_done(obj, result, user_data): user_data['result'] = result user_data['main_loop'].quit() main_loop = GLib.MainLoop() data = {'main_loop': main_loop} self.dbus_proxy.ListNames('()', result_handler=call_done, user_data=data) main_loop.run() result = data['result'] self.assertEqual(type(result), type([])) self.assertTrue(len(result) > 1) self.assertTrue('org.freedesktop.DBus' in result) def test_python_calls_async_error_result(self): # when only specifying a result handler, this will get the error def call_done(obj, result, user_data): user_data['result'] = result user_data['main_loop'].quit() main_loop = GLib.MainLoop() data = {'main_loop': main_loop} self.dbus_proxy.ListNames('(s)', 'invalid_argument', result_handler=call_done, user_data=data) main_loop.run() self.assertTrue(isinstance(data['result'], Exception)) self.assertTrue('InvalidArgs' in str(data['result']), str(data['result'])) def test_python_calls_async_error(self): # when specifying an explicit error handler, this will get the error def call_done(obj, result, user_data): user_data['main_loop'].quit() self.fail('result handler should not be called') def call_error(obj, error, user_data): user_data['error'] = error user_data['main_loop'].quit() main_loop = GLib.MainLoop() data = {'main_loop': main_loop} self.dbus_proxy.ListNames('(s)', 'invalid_argument', result_handler=call_done, error_handler=call_error, user_data=data) main_loop.run() self.assertTrue(isinstance(data['error'], Exception)) self.assertTrue('InvalidArgs' in str(data['error']), str(data['error'])) def test_instantiate_custom_proxy(self): class SomeProxy(Gio.DBusProxy): def __init__(self): Gio.DBusProxy.__init__(self) SomeProxy() class TestDBusConnection: @unittest.skipUnless(has_dbus, "no dbus running") def test_register_object(self): object_path = "/pygobject/Test" interface_xml = """ """ interface_info = Gio.DBusNodeInfo.new_for_xml(interface_xml).interfaces[0] bus = Gio.bus_get_sync(Gio.BusType.SESSION) for args in ( (object_path, interface_info), (object_path, interface_info, None, None, None) ): reg_id = bus.register_object(*args) bus.unregister_object(reg_id) for kwargs in ( {"object_path": object_path, "interface_info": interface_info}, {"object_path": object_path, "interface_info": interface_info, "method_call_closure": None, "get_property_closure": None, "set_property_closure": None}, ): reg_id = bus.register_object(**kwargs) bus.unregister_object(reg_id) @unittest.skipUnless(has_dbus, "no dbus running") @pytest.mark.xfail() def test_connection_invocation_ref_count(self): """Invocation object should not leak a reference.""" invocation, errors = self.run_server(self.client_call) assert not errors assert invocation assert invocation.ref_count == 1 def run_server(self, client_callback): self.invocation = None self.errors = [] self.loop = GLib.MainLoop() def on_name_acquired(bus, name): client_callback(bus) self.reg_id = None bus = Gio.bus_get_sync(Gio.BusType.SESSION) owner_id = Gio.bus_own_name(Gio.BusType.SESSION, "org.pygobject.Test", Gio.BusNameOwnerFlags.NONE, self.on_bus_acquired, on_name_acquired, self.on_name_lost) try: self.loop.run() finally: Gio.bus_unown_name(owner_id) if self.reg_id: bus.unregister_object(self.reg_id) return (self.invocation, self.errors) def on_name_lost(self, _bus, name): self.errors.append(f"Name {name} lost") self.loop.quit() def on_bus_acquired(self, bus, name): interface_xml = """ """ self.reg_id = bus.register_object("/pygobject/Test", Gio.DBusNodeInfo.new_for_xml(interface_xml).interfaces[0], self.on_incoming_method_call, None, None) def on_incoming_method_call(self, bus, sender, object_path, interface_name, method_name, parameters, invocation): invocation.return_value(GLib.Variant("()", ())) self.invocation = invocation def client_call(self, bus): def call_done(obj, result): try: obj.call_finish(result) finally: self.loop.quit() bus.call("org.pygobject.Test", "/pygobject/Test", "org.pygobject.Test", "test", parameters=None, reply_type=None, flags=Gio.DBusCallFlags.NONE, timeout_msec=5000, callback=call_done) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/tests/test_generictreemodel.py0000664000000000000000000003517315074674453020447 0ustar00rootroot# -*- Mode: Python; py-indent-offset: 4 -*- # test_generictreemodel - Tests for GenericTreeModel # Copyright (C) 2013 Simon Feltman # # test_generictreemodel.py: Tests for GenericTreeModel # # 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 . # system import gc import sys import weakref import unittest import platform import warnings # pygobject from gi.repository import GObject try: from gi.repository import Gtk from pygtkcompat.generictreemodel import GenericTreeModel from pygtkcompat.generictreemodel import _get_user_data_as_pyobject has_gtk = True except ImportError: GenericTreeModel = object has_gtk = False class Node(object): """Represents a generic node with name, value, and children.""" def __init__(self, name, value, *children): self.name = name self.value = value self.children = list(children) self.parent = None self.next = None for i, child in enumerate(children): child.parent = weakref.ref(self) if i < len(children) - 1: child.next = weakref.ref(children[i + 1]) def __repr__(self): return 'Node("%s", %s)' % (self.name, self.value) class ATesterModel(GenericTreeModel): def __init__(self): with warnings.catch_warnings(record=True): super(ATesterModel, self).__init__() self.root = Node('root', 0, Node('spam', 1, Node('sushi', 2), Node('bread', 3) ), Node('eggs', 4) ) def on_get_flags(self): return 0 def on_get_n_columns(self): return 2 def on_get_column_type(self, n): return (str, int)[n] def on_get_iter(self, path): node = self.root path = list(path) idx = path.pop(0) while path: idx = path.pop(0) node = node.children[idx] return node def on_get_path(self, node): def rec_get_path(n): for i, child in enumerate(n.children): if child == node: return [i] else: res = rec_get_path(child) if res: res.insert(0, i) return rec_get_path(self.root) def on_get_value(self, node, column): if column == 0: return node.name elif column == 1: return node.value def on_iter_has_child(self, node): return bool(node.children) def on_iter_next(self, node): if node.next: return node.next() def on_iter_children(self, node): if node: return node.children[0] else: return self.root def on_iter_n_children(self, node): if node is None: return 1 return len(node.children) def on_iter_nth_child(self, node, n): if node is None: assert n == 0 return self.root return node.children[n] def on_iter_parent(self, child): if child.parent: return child.parent() @unittest.skipUnless(has_gtk, 'Gtk not available') class TestReferences(unittest.TestCase): def setUp(self): pass @unittest.skipIf(platform.python_implementation() == "PyPy", "not with PyPy") def test_c_tree_iter_user_data_as_pyobject(self): obj = object() obj_id = id(obj) ref_count = sys.getrefcount(obj) # This is essentially a stolen ref in the context of _CTreeIter.get_user_data_as_pyobject it = Gtk.TreeIter() it.user_data = obj_id obj2 = _get_user_data_as_pyobject(it) self.assertEqual(obj, obj2) self.assertEqual(sys.getrefcount(obj), ref_count + 1) def test_leak_references_on(self): model = ATesterModel() obj_ref = weakref.ref(model.root) # Initial refcount is 1 for model.root + the temporary if hasattr(sys, "getrefcount"): self.assertEqual(sys.getrefcount(model.root), 2) # Iter increases by 1 do to assignment to iter.user_data res, it = model.do_get_iter([0]) self.assertEqual(id(model.root), it.user_data) if hasattr(sys, "getrefcount"): self.assertEqual(sys.getrefcount(model.root), 3) # Verify getting a TreeIter more then once does not further increase # the ref count. res2, it2 = model.do_get_iter([0]) self.assertEqual(id(model.root), it2.user_data) if hasattr(sys, "getrefcount"): self.assertEqual(sys.getrefcount(model.root), 3) # Deleting the iter does not decrease refcount because references # leak by default (they are stored in the held_refs pool) del it gc.collect() if hasattr(sys, "getrefcount"): self.assertEqual(sys.getrefcount(model.root), 3) # Deleting a model should free all held references to user data # stored by TreeIters del model gc.collect() self.assertEqual(obj_ref(), None) def test_row_deleted_frees_refs(self): model = ATesterModel() obj_ref = weakref.ref(model.root) # Initial refcount is 1 for model.root + the temporary if hasattr(sys, "getrefcount"): self.assertEqual(sys.getrefcount(model.root), 2) # Iter increases by 1 do to assignment to iter.user_data res, it = model.do_get_iter([0]) self.assertEqual(id(model.root), it.user_data) if hasattr(sys, "getrefcount"): self.assertEqual(sys.getrefcount(model.root), 3) # Notifying the underlying model of a row_deleted should decrease the # ref count. model.row_deleted(Gtk.TreePath('0'), model.root) if hasattr(sys, "getrefcount"): self.assertEqual(sys.getrefcount(model.root), 2) # Finally deleting the actual object should collect it completely del model.root gc.collect() self.assertEqual(obj_ref(), None) def test_leak_references_off(self): model = ATesterModel() model.leak_references = False obj_ref = weakref.ref(model.root) # Initial refcount is 1 for model.root + the temporary if hasattr(sys, "getrefcount"): self.assertEqual(sys.getrefcount(model.root), 2) # Iter does not increas count by 1 when leak_references is false res, it = model.do_get_iter([0]) self.assertEqual(id(model.root), it.user_data) if hasattr(sys, "getrefcount"): self.assertEqual(sys.getrefcount(model.root), 2) # Deleting the iter does not decrease refcount because assigning user_data # eats references and does not release them. del it gc.collect() if hasattr(sys, "getrefcount"): self.assertEqual(sys.getrefcount(model.root), 2) # Deleting the model decreases the final ref, and the object is collected del model gc.collect() self.assertEqual(obj_ref(), None) def test_iteration_refs(self): # Pull iterators off the model using the wrapped C API which will # then call back into the python overrides. model = ATesterModel() nodes = [node for node in model.iter_depth_first()] values = [node.value for node in nodes] # Verify depth first ordering self.assertEqual(values, [0, 1, 2, 3, 4]) # Verify ref counts for each of the nodes. # 5 refs for each node at this point: # 1 - ref held in getrefcount function # 2 - ref held by "node" var during iteration # 3 - ref held by local "nodes" var # 4 - ref held by the root/children graph itself # 5 - ref held by the model "held_refs" instance var for node in nodes: if hasattr(sys, "getrefcount"): self.assertEqual(sys.getrefcount(node), 5) # A second iteration and storage of the nodes in a new list # should only increase refcounts by 1 even though new # iterators are created and assigned. nodes2 = [node for node in model.iter_depth_first()] for node in nodes2: if hasattr(sys, "getrefcount"): self.assertEqual(sys.getrefcount(node), 6) # Hold weak refs and start verifying ref collection. node_refs = [weakref.ref(node) for node in nodes] # First round of collection del nodes2 gc.collect() for node in nodes: if hasattr(sys, "getrefcount"): self.assertEqual(sys.getrefcount(node), 5) # Second round of collection, no more local lists of nodes. del nodes gc.collect() for ref in node_refs: node = ref() if hasattr(sys, "getrefcount"): self.assertEqual(sys.getrefcount(node), 4) # Using invalidate_iters or row_deleted(path, node) will clear out # the pooled refs held internal to the GenericTreeModel implementation. model.invalidate_iters() self.assertEqual(len(model._held_refs), 0) gc.collect() for ref in node_refs: node = ref() if hasattr(sys, "getrefcount"): self.assertEqual(sys.getrefcount(node), 3) # Deleting the root node at this point should allow all nodes to be collected # as there is no longer a way to reach the children del node # node still in locals() from last iteration del model.root gc.collect() for ref in node_refs: self.assertEqual(ref(), None) @unittest.skipUnless(has_gtk, 'Gtk not available') class TestIteration(unittest.TestCase): def test_iter_next_root(self): model = ATesterModel() it = model.get_iter([0]) self.assertEqual(it.user_data, id(model.root)) self.assertEqual(model.root.next, None) it = model.iter_next(it) self.assertEqual(it, None) def test_iter_next_multiple(self): model = ATesterModel() it = model.get_iter([0, 0]) self.assertEqual(it.user_data, id(model.root.children[0])) it = model.iter_next(it) self.assertEqual(it.user_data, id(model.root.children[1])) it = model.iter_next(it) self.assertEqual(it, None) class ErrorModel(GenericTreeModel): # All on_* methods will raise a NotImplementedError by default pass @unittest.skipUnless(has_gtk, 'Gtk not available') class ExceptHook(object): """ Temporarily installs an exception hook in a context which expects the given exc_type to be raised. This allows verification of exceptions that occur within python gi callbacks but are never bubbled through from python to C back to python. This works because exception hooks are called in PyErr_Print. """ def __init__(self, *expected_exc_types): self._expected_exc_types = expected_exc_types self._exceptions = [] def _excepthook(self, exc_type, value, traceback): self._exceptions.append((exc_type, value)) def __enter__(self): self._oldhook = sys.excepthook sys.excepthook = self._excepthook return self def __exit__(self, exc_type, exc_val, exc_tb): sys.excepthook = self._oldhook error_message = 'Expecting the following exceptions: %s, got: %s' % \ (str(self._expected_exc_types), '\n'.join([str(item) for item in self._exceptions])) assert len(self._expected_exc_types) == len(self._exceptions), error_message for expected, got in zip(self._expected_exc_types, [exc[0] for exc in self._exceptions]): assert issubclass(got, expected), error_message @unittest.skipUnless(has_gtk, 'Gtk not available') class TestReturnsAfterError(unittest.TestCase): def setUp(self): with warnings.catch_warnings(record=True): self.model = ErrorModel() def test_get_flags(self): with ExceptHook(NotImplementedError): flags = self.model.get_flags() self.assertEqual(flags, 0) def test_get_n_columns(self): with ExceptHook(NotImplementedError): count = self.model.get_n_columns() self.assertEqual(count, 0) def test_get_column_type(self): with ExceptHook(NotImplementedError, ValueError): col_type = self.model.get_column_type(0) self.assertEqual(col_type, GObject.TYPE_INVALID) def test_get_iter(self): with ExceptHook(NotImplementedError): self.assertRaises(ValueError, self.model.get_iter, Gtk.TreePath(0)) def test_get_path(self): it = self.model.create_tree_iter('foo') with ExceptHook(NotImplementedError): path = self.model.get_path(it) self.assertEqual(path, None) def test_get_value(self): it = self.model.create_tree_iter('foo') with ExceptHook(NotImplementedError): try: self.model.get_value(it, 0) except TypeError: pass # silence TypeError converting None to GValue def test_iter_has_child(self): it = self.model.create_tree_iter('foo') with ExceptHook(NotImplementedError): res = self.model.iter_has_child(it) self.assertEqual(res, False) def test_iter_next(self): it = self.model.create_tree_iter('foo') with ExceptHook(NotImplementedError): res = self.model.iter_next(it) self.assertEqual(res, None) def test_iter_children(self): with ExceptHook(NotImplementedError): res = self.model.iter_children(None) self.assertEqual(res, None) def test_iter_n_children(self): with ExceptHook(NotImplementedError): res = self.model.iter_n_children(None) self.assertEqual(res, 0) def test_iter_nth_child(self): with ExceptHook(NotImplementedError): res = self.model.iter_nth_child(None, 0) self.assertEqual(res, None) def test_iter_parent(self): child = self.model.create_tree_iter('foo') with ExceptHook(NotImplementedError): res = self.model.iter_parent(child) self.assertEqual(res, None) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/tests/test_gi.py0000664000000000000000000036705215074674453015535 0ustar00rootroot# -*- Mode: Python; py-indent-offset: 4 -*- # vim: tabstop=4 shiftwidth=4 expandtab import sys import unittest import tempfile import shutil import os import gc import weakref import warnings import pickle import platform import gi import gi.overrides from gi import PyGIWarning from gi import PyGIDeprecationWarning from gi.repository import GObject, GLib, Gio from gi.repository import GIMarshallingTests import pytest from .helper import capture_exceptions, capture_output CONSTANT_UTF8 = "const ♥ utf8" CONSTANT_UCS4 = u"const ♥ utf8" class Number(object): def __init__(self, value): self.value = value def __int__(self): return int(self.value) def __float__(self): return float(self.value) class Sequence(object): def __init__(self, sequence): self.sequence = sequence def __len__(self): return len(self.sequence) def __getitem__(self, key): return self.sequence[key] class TestConstant(unittest.TestCase): def test_constant_utf8(self): self.assertEqual(CONSTANT_UTF8, GIMarshallingTests.CONSTANT_UTF8) def test_constant_number(self): self.assertEqual(42, GIMarshallingTests.CONSTANT_NUMBER) def test_min_max_int(self): self.assertEqual(GLib.MAXINT32, 2 ** 31 - 1) self.assertEqual(GLib.MININT32, -2 ** 31) self.assertEqual(GLib.MAXUINT32, 2 ** 32 - 1) self.assertEqual(GLib.MAXINT64, 2 ** 63 - 1) self.assertEqual(GLib.MININT64, -2 ** 63) self.assertEqual(GLib.MAXUINT64, 2 ** 64 - 1) class TestBoolean(unittest.TestCase): def test_boolean_return(self): self.assertEqual(True, GIMarshallingTests.boolean_return_true()) self.assertEqual(False, GIMarshallingTests.boolean_return_false()) def test_boolean_in(self): GIMarshallingTests.boolean_in_true(True) GIMarshallingTests.boolean_in_false(False) GIMarshallingTests.boolean_in_true(1) GIMarshallingTests.boolean_in_false(0) def test_boolean_in_other_types(self): GIMarshallingTests.boolean_in_true([""]) GIMarshallingTests.boolean_in_false([]) GIMarshallingTests.boolean_in_false(None) def test_boolean_out(self): self.assertEqual(True, GIMarshallingTests.boolean_out_true()) self.assertEqual(False, GIMarshallingTests.boolean_out_false()) def test_boolean_inout(self): self.assertEqual(False, GIMarshallingTests.boolean_inout_true_false(True)) self.assertEqual(True, GIMarshallingTests.boolean_inout_false_true(False)) class TestInt8(unittest.TestCase): MAX = GLib.MAXINT8 MIN = GLib.MININT8 def test_int8_return(self): self.assertEqual(self.MAX, GIMarshallingTests.int8_return_max()) self.assertEqual(self.MIN, GIMarshallingTests.int8_return_min()) def test_int8_in(self): max = Number(self.MAX) min = Number(self.MIN) GIMarshallingTests.int8_in_max(max) GIMarshallingTests.int8_in_min(min) max.value += 1 min.value -= 1 self.assertRaises(OverflowError, GIMarshallingTests.int8_in_max, max) self.assertRaises(OverflowError, GIMarshallingTests.int8_in_min, min) self.assertRaises(TypeError, GIMarshallingTests.int8_in_max, "self.MAX") def test_int8_out(self): self.assertEqual(self.MAX, GIMarshallingTests.int8_out_max()) self.assertEqual(self.MIN, GIMarshallingTests.int8_out_min()) def test_int8_inout(self): self.assertEqual(self.MIN, GIMarshallingTests.int8_inout_max_min(Number(self.MAX))) self.assertEqual(self.MAX, GIMarshallingTests.int8_inout_min_max(Number(self.MIN))) class TestUInt8(unittest.TestCase): MAX = GLib.MAXUINT8 def test_uint8_return(self): self.assertEqual(self.MAX, GIMarshallingTests.uint8_return()) def test_uint8_in(self): number = Number(self.MAX) GIMarshallingTests.uint8_in(number) GIMarshallingTests.uint8_in(b'\xff') number.value += 1 self.assertRaises(OverflowError, GIMarshallingTests.uint8_in, number) self.assertRaises(OverflowError, GIMarshallingTests.uint8_in, Number(-1)) self.assertRaises(TypeError, GIMarshallingTests.uint8_in, "self.MAX") def test_uint8_out(self): self.assertEqual(self.MAX, GIMarshallingTests.uint8_out()) def test_uint8_inout(self): self.assertEqual(0, GIMarshallingTests.uint8_inout(Number(self.MAX))) class TestInt16(unittest.TestCase): MAX = GLib.MAXINT16 MIN = GLib.MININT16 def test_int16_return(self): self.assertEqual(self.MAX, GIMarshallingTests.int16_return_max()) self.assertEqual(self.MIN, GIMarshallingTests.int16_return_min()) def test_int16_in(self): max = Number(self.MAX) min = Number(self.MIN) GIMarshallingTests.int16_in_max(max) GIMarshallingTests.int16_in_min(min) max.value += 1 min.value -= 1 self.assertRaises(OverflowError, GIMarshallingTests.int16_in_max, max) self.assertRaises(OverflowError, GIMarshallingTests.int16_in_min, min) self.assertRaises(TypeError, GIMarshallingTests.int16_in_max, "self.MAX") def test_int16_out(self): self.assertEqual(self.MAX, GIMarshallingTests.int16_out_max()) self.assertEqual(self.MIN, GIMarshallingTests.int16_out_min()) def test_int16_inout(self): self.assertEqual(self.MIN, GIMarshallingTests.int16_inout_max_min(Number(self.MAX))) self.assertEqual(self.MAX, GIMarshallingTests.int16_inout_min_max(Number(self.MIN))) class TestUInt16(unittest.TestCase): MAX = GLib.MAXUINT16 def test_uint16_return(self): self.assertEqual(self.MAX, GIMarshallingTests.uint16_return()) def test_uint16_in(self): number = Number(self.MAX) GIMarshallingTests.uint16_in(number) number.value += 1 self.assertRaises(OverflowError, GIMarshallingTests.uint16_in, number) self.assertRaises(OverflowError, GIMarshallingTests.uint16_in, Number(-1)) self.assertRaises(TypeError, GIMarshallingTests.uint16_in, "self.MAX") def test_uint16_out(self): self.assertEqual(self.MAX, GIMarshallingTests.uint16_out()) def test_uint16_inout(self): self.assertEqual(0, GIMarshallingTests.uint16_inout(Number(self.MAX))) class TestInt32(unittest.TestCase): MAX = GLib.MAXINT32 MIN = GLib.MININT32 def test_int32_return(self): self.assertEqual(self.MAX, GIMarshallingTests.int32_return_max()) self.assertEqual(self.MIN, GIMarshallingTests.int32_return_min()) def test_int32_in(self): max = Number(self.MAX) min = Number(self.MIN) GIMarshallingTests.int32_in_max(max) GIMarshallingTests.int32_in_min(min) max.value += 1 min.value -= 1 self.assertRaises(OverflowError, GIMarshallingTests.int32_in_max, max) self.assertRaises(OverflowError, GIMarshallingTests.int32_in_min, min) self.assertRaises(TypeError, GIMarshallingTests.int32_in_max, "self.MAX") def test_int32_out(self): self.assertEqual(self.MAX, GIMarshallingTests.int32_out_max()) self.assertEqual(self.MIN, GIMarshallingTests.int32_out_min()) def test_int32_inout(self): self.assertEqual(self.MIN, GIMarshallingTests.int32_inout_max_min(Number(self.MAX))) self.assertEqual(self.MAX, GIMarshallingTests.int32_inout_min_max(Number(self.MIN))) class TestUInt32(unittest.TestCase): MAX = GLib.MAXUINT32 def test_uint32_return(self): self.assertEqual(self.MAX, GIMarshallingTests.uint32_return()) def test_uint32_in(self): number = Number(self.MAX) GIMarshallingTests.uint32_in(number) number.value += 1 self.assertRaises(OverflowError, GIMarshallingTests.uint32_in, number) self.assertRaises(OverflowError, GIMarshallingTests.uint32_in, Number(-1)) self.assertRaises(TypeError, GIMarshallingTests.uint32_in, "self.MAX") def test_uint32_out(self): self.assertEqual(self.MAX, GIMarshallingTests.uint32_out()) def test_uint32_inout(self): self.assertEqual(0, GIMarshallingTests.uint32_inout(Number(self.MAX))) class TestInt64(unittest.TestCase): MAX = 2 ** 63 - 1 MIN = - (2 ** 63) def test_int64_return(self): self.assertEqual(self.MAX, GIMarshallingTests.int64_return_max()) self.assertEqual(self.MIN, GIMarshallingTests.int64_return_min()) def test_int64_in(self): max = Number(self.MAX) min = Number(self.MIN) GIMarshallingTests.int64_in_max(max) GIMarshallingTests.int64_in_min(min) max.value += 1 min.value -= 1 self.assertRaises(OverflowError, GIMarshallingTests.int64_in_max, max) self.assertRaises(OverflowError, GIMarshallingTests.int64_in_min, min) self.assertRaises(TypeError, GIMarshallingTests.int64_in_max, "self.MAX") def test_int64_out(self): self.assertEqual(self.MAX, GIMarshallingTests.int64_out_max()) self.assertEqual(self.MIN, GIMarshallingTests.int64_out_min()) def test_int64_inout(self): self.assertEqual(self.MIN, GIMarshallingTests.int64_inout_max_min(Number(self.MAX))) self.assertEqual(self.MAX, GIMarshallingTests.int64_inout_min_max(Number(self.MIN))) class TestUInt64(unittest.TestCase): MAX = 2 ** 64 - 1 def test_uint64_return(self): self.assertEqual(self.MAX, GIMarshallingTests.uint64_return()) def test_uint64_in(self): number = Number(self.MAX) GIMarshallingTests.uint64_in(number) number.value += 1 self.assertRaises(OverflowError, GIMarshallingTests.uint64_in, number) self.assertRaises(OverflowError, GIMarshallingTests.uint64_in, Number(-1)) self.assertRaises(TypeError, GIMarshallingTests.uint64_in, "self.MAX") def test_uint64_out(self): self.assertEqual(self.MAX, GIMarshallingTests.uint64_out()) def test_uint64_inout(self): self.assertEqual(0, GIMarshallingTests.uint64_inout(Number(self.MAX))) class TestShort(unittest.TestCase): MAX = GLib.MAXSHORT MIN = GLib.MINSHORT def test_short_return(self): self.assertEqual(self.MAX, GIMarshallingTests.short_return_max()) self.assertEqual(self.MIN, GIMarshallingTests.short_return_min()) def test_short_in(self): max = Number(self.MAX) min = Number(self.MIN) GIMarshallingTests.short_in_max(max) GIMarshallingTests.short_in_min(min) max.value += 1 min.value -= 1 self.assertRaises(OverflowError, GIMarshallingTests.short_in_max, max) self.assertRaises(OverflowError, GIMarshallingTests.short_in_min, min) self.assertRaises(TypeError, GIMarshallingTests.short_in_max, "self.MAX") def test_short_out(self): self.assertEqual(self.MAX, GIMarshallingTests.short_out_max()) self.assertEqual(self.MIN, GIMarshallingTests.short_out_min()) def test_short_inout(self): self.assertEqual(self.MIN, GIMarshallingTests.short_inout_max_min(Number(self.MAX))) self.assertEqual(self.MAX, GIMarshallingTests.short_inout_min_max(Number(self.MIN))) class TestUShort(unittest.TestCase): MAX = GLib.MAXUSHORT def test_ushort_return(self): self.assertEqual(self.MAX, GIMarshallingTests.ushort_return()) def test_ushort_in(self): number = Number(self.MAX) GIMarshallingTests.ushort_in(number) number.value += 1 self.assertRaises(OverflowError, GIMarshallingTests.ushort_in, number) self.assertRaises(OverflowError, GIMarshallingTests.ushort_in, Number(-1)) self.assertRaises(TypeError, GIMarshallingTests.ushort_in, "self.MAX") def test_ushort_out(self): self.assertEqual(self.MAX, GIMarshallingTests.ushort_out()) def test_ushort_inout(self): self.assertEqual(0, GIMarshallingTests.ushort_inout(Number(self.MAX))) class TestInt(unittest.TestCase): MAX = GLib.MAXINT MIN = GLib.MININT def test_int_return(self): self.assertEqual(self.MAX, GIMarshallingTests.int_return_max()) self.assertEqual(self.MIN, GIMarshallingTests.int_return_min()) def test_int_in(self): max = Number(self.MAX) min = Number(self.MIN) GIMarshallingTests.int_in_max(max) GIMarshallingTests.int_in_min(min) max.value += 1 min.value -= 1 self.assertRaises(OverflowError, GIMarshallingTests.int_in_max, max) self.assertRaises(OverflowError, GIMarshallingTests.int_in_min, min) self.assertRaises(TypeError, GIMarshallingTests.int_in_max, "self.MAX") def test_int_out(self): self.assertEqual(self.MAX, GIMarshallingTests.int_out_max()) self.assertEqual(self.MIN, GIMarshallingTests.int_out_min()) def test_int_inout(self): self.assertEqual(self.MIN, GIMarshallingTests.int_inout_max_min(Number(self.MAX))) self.assertEqual(self.MAX, GIMarshallingTests.int_inout_min_max(Number(self.MIN))) self.assertRaises(TypeError, GIMarshallingTests.int_inout_min_max, Number(self.MIN), 42) class TestUInt(unittest.TestCase): MAX = GLib.MAXUINT def test_uint_return(self): self.assertEqual(self.MAX, GIMarshallingTests.uint_return()) def test_uint_in(self): number = Number(self.MAX) GIMarshallingTests.uint_in(number) number.value += 1 self.assertRaises(OverflowError, GIMarshallingTests.uint_in, number) self.assertRaises(OverflowError, GIMarshallingTests.uint_in, Number(-1)) self.assertRaises(TypeError, GIMarshallingTests.uint_in, "self.MAX") def test_uint_out(self): self.assertEqual(self.MAX, GIMarshallingTests.uint_out()) def test_uint_inout(self): self.assertEqual(0, GIMarshallingTests.uint_inout(Number(self.MAX))) class TestLong(unittest.TestCase): MAX = GLib.MAXLONG MIN = GLib.MINLONG def test_long_return(self): self.assertEqual(self.MAX, GIMarshallingTests.long_return_max()) self.assertEqual(self.MIN, GIMarshallingTests.long_return_min()) def test_long_in(self): max = Number(self.MAX) min = Number(self.MIN) GIMarshallingTests.long_in_max(max) GIMarshallingTests.long_in_min(min) max.value += 1 min.value -= 1 self.assertRaises(OverflowError, GIMarshallingTests.long_in_max, max) self.assertRaises(OverflowError, GIMarshallingTests.long_in_min, min) self.assertRaises(TypeError, GIMarshallingTests.long_in_max, "self.MAX") def test_long_out(self): self.assertEqual(self.MAX, GIMarshallingTests.long_out_max()) self.assertEqual(self.MIN, GIMarshallingTests.long_out_min()) def test_long_inout(self): self.assertEqual(self.MIN, GIMarshallingTests.long_inout_max_min(Number(self.MAX))) self.assertEqual(self.MAX, GIMarshallingTests.long_inout_min_max(Number(self.MIN))) class TestULong(unittest.TestCase): MAX = GLib.MAXULONG def test_ulong_return(self): self.assertEqual(self.MAX, GIMarshallingTests.ulong_return()) def test_ulong_in(self): number = Number(self.MAX) GIMarshallingTests.ulong_in(number) number.value += 1 self.assertRaises(OverflowError, GIMarshallingTests.ulong_in, number) self.assertRaises(OverflowError, GIMarshallingTests.ulong_in, Number(-1)) self.assertRaises(TypeError, GIMarshallingTests.ulong_in, "self.MAX") def test_ulong_out(self): self.assertEqual(self.MAX, GIMarshallingTests.ulong_out()) def test_ulong_inout(self): self.assertEqual(0, GIMarshallingTests.ulong_inout(Number(self.MAX))) class TestSSize(unittest.TestCase): MAX = GLib.MAXSSIZE MIN = GLib.MINSSIZE def test_ssize_return(self): self.assertEqual(self.MAX, GIMarshallingTests.ssize_return_max()) self.assertEqual(self.MIN, GIMarshallingTests.ssize_return_min()) def test_ssize_in(self): max = Number(self.MAX) min = Number(self.MIN) GIMarshallingTests.ssize_in_max(max) GIMarshallingTests.ssize_in_min(min) max.value += 1 min.value -= 1 self.assertRaises(OverflowError, GIMarshallingTests.ssize_in_max, max) self.assertRaises(OverflowError, GIMarshallingTests.ssize_in_min, min) self.assertRaises(TypeError, GIMarshallingTests.ssize_in_max, "self.MAX") def test_ssize_out(self): self.assertEqual(self.MAX, GIMarshallingTests.ssize_out_max()) self.assertEqual(self.MIN, GIMarshallingTests.ssize_out_min()) def test_ssize_inout(self): self.assertEqual(self.MIN, GIMarshallingTests.ssize_inout_max_min(Number(self.MAX))) self.assertEqual(self.MAX, GIMarshallingTests.ssize_inout_min_max(Number(self.MIN))) class TestSize(unittest.TestCase): MAX = GLib.MAXSIZE def test_size_return(self): self.assertEqual(self.MAX, GIMarshallingTests.size_return()) def test_size_in(self): number = Number(self.MAX) GIMarshallingTests.size_in(number) number.value += 1 self.assertRaises(OverflowError, GIMarshallingTests.size_in, number) self.assertRaises(OverflowError, GIMarshallingTests.size_in, Number(-1)) self.assertRaises(TypeError, GIMarshallingTests.size_in, "self.MAX") def test_size_out(self): self.assertEqual(self.MAX, GIMarshallingTests.size_out()) def test_size_inout(self): self.assertEqual(0, GIMarshallingTests.size_inout(Number(self.MAX))) class TestTimet(unittest.TestCase): def test_time_t_return(self): self.assertEqual(1234567890, GIMarshallingTests.time_t_return()) def test_time_t_in(self): GIMarshallingTests.time_t_in(1234567890) self.assertRaises(TypeError, GIMarshallingTests.time_t_in, "hello") def test_time_t_out(self): self.assertEqual(1234567890, GIMarshallingTests.time_t_out()) def test_time_t_inout(self): self.assertEqual(0, GIMarshallingTests.time_t_inout(1234567890)) class TestFloat(unittest.TestCase): MAX = GLib.MAXFLOAT MIN = GLib.MINFLOAT def test_float_return(self): self.assertAlmostEqual(self.MAX, GIMarshallingTests.float_return()) def test_float_in(self): GIMarshallingTests.float_in(Number(self.MAX)) self.assertRaises(TypeError, GIMarshallingTests.float_in, "self.MAX") def test_float_out(self): self.assertAlmostEqual(self.MAX, GIMarshallingTests.float_out()) def test_float_inout(self): self.assertAlmostEqual(self.MIN, GIMarshallingTests.float_inout(Number(self.MAX))) class TestDouble(unittest.TestCase): MAX = GLib.MAXDOUBLE MIN = GLib.MINDOUBLE def test_double_return(self): self.assertAlmostEqual(self.MAX, GIMarshallingTests.double_return()) def test_double_in(self): GIMarshallingTests.double_in(Number(self.MAX)) self.assertRaises(TypeError, GIMarshallingTests.double_in, "self.MAX") def test_double_out(self): self.assertAlmostEqual(self.MAX, GIMarshallingTests.double_out()) def test_double_inout(self): self.assertAlmostEqual(self.MIN, GIMarshallingTests.double_inout(Number(self.MAX))) class TestGType(unittest.TestCase): def test_gtype_name(self): self.assertEqual("void", GObject.TYPE_NONE.name) self.assertEqual("gchararray", GObject.TYPE_STRING.name) def check_readonly(gtype): gtype.name = "foo" errors = (AttributeError,) if platform.python_implementation() == "PyPy": # https://foss.heptapod.net/pypy/pypy/-/issues/2788 errors = (AttributeError, TypeError) self.assertRaises(errors, check_readonly, GObject.TYPE_NONE) self.assertRaises(errors, check_readonly, GObject.TYPE_STRING) def test_gtype_return(self): self.assertEqual(GObject.TYPE_NONE, GIMarshallingTests.gtype_return()) self.assertEqual(GObject.TYPE_STRING, GIMarshallingTests.gtype_string_return()) def test_gtype_in(self): GIMarshallingTests.gtype_in(GObject.TYPE_NONE) GIMarshallingTests.gtype_string_in(GObject.TYPE_STRING) self.assertRaises(TypeError, GIMarshallingTests.gtype_in, "foo") self.assertRaises(TypeError, GIMarshallingTests.gtype_string_in, "foo") def test_gtype_out(self): self.assertEqual(GObject.TYPE_NONE, GIMarshallingTests.gtype_out()) self.assertEqual(GObject.TYPE_STRING, GIMarshallingTests.gtype_string_out()) def test_gtype_inout(self): self.assertEqual(GObject.TYPE_INT, GIMarshallingTests.gtype_inout(GObject.TYPE_NONE)) class TestUtf8(unittest.TestCase): def test_utf8_as_uint8array_in(self): data = CONSTANT_UTF8 if not isinstance(data, bytes): data = data.encode("utf-8") GIMarshallingTests.utf8_as_uint8array_in(data) def test_utf8_none_return(self): self.assertEqual(CONSTANT_UTF8, GIMarshallingTests.utf8_none_return()) def test_utf8_full_return(self): self.assertEqual(CONSTANT_UTF8, GIMarshallingTests.utf8_full_return()) def test_extra_utf8_full_return_invalid(self): with pytest.raises(UnicodeDecodeError): GIMarshallingTests.extra_utf8_full_return_invalid() def test_extra_utf8_full_out_invalid(self): with pytest.raises(UnicodeDecodeError): GIMarshallingTests.extra_utf8_full_out_invalid() def test_utf8_none_in(self): GIMarshallingTests.utf8_none_in(CONSTANT_UTF8) self.assertRaises(TypeError, GIMarshallingTests.utf8_none_in, 42) self.assertRaises(TypeError, GIMarshallingTests.utf8_none_in, None) def test_utf8_none_out(self): self.assertEqual(CONSTANT_UTF8, GIMarshallingTests.utf8_none_out()) def test_utf8_full_out(self): self.assertEqual(CONSTANT_UTF8, GIMarshallingTests.utf8_full_out()) def test_utf8_dangling_out(self): GIMarshallingTests.utf8_dangling_out() def test_utf8_none_inout(self): self.assertEqual("", GIMarshallingTests.utf8_none_inout(CONSTANT_UTF8)) def test_utf8_full_inout(self): self.assertEqual("", GIMarshallingTests.utf8_full_inout(CONSTANT_UTF8)) class TestFilename(unittest.TestCase): def setUp(self): self.workdir = tempfile.mkdtemp() def tearDown(self): shutil.rmtree(self.workdir) def tests_filename_list_return(self): assert GIMarshallingTests.filename_list_return() == [] @unittest.skipIf(os.name == "nt", "fixme") def test_filename_in(self): fname = os.path.join(self.workdir, u'testäø.txt') try: os.path.exists(fname) except ValueError: # non-unicode fs encoding return self.assertRaises(GLib.GError, GLib.file_get_contents, fname) with open(fname.encode('UTF-8'), 'wb') as f: f.write(b'hello world!\n\x01\x02') (result, contents) = GLib.file_get_contents(fname) self.assertEqual(result, True) self.assertEqual(contents, b'hello world!\n\x01\x02') def test_filename_in_nullable(self): self.assertTrue(GIMarshallingTests.filename_copy(None) is None) self.assertRaises(TypeError, GIMarshallingTests.filename_exists, None) @unittest.skipIf(os.name == "nt", "fixme") def test_filename_out(self): self.assertRaises(GLib.GError, GLib.Dir.make_tmp, 'test') name = 'testäø.XXXXXX' try: os.path.exists(name) except ValueError: # non-unicode fs encoding return dirname = GLib.Dir.make_tmp(name) self.assertTrue(os.path.sep + 'testäø.' in dirname, dirname) self.assertTrue(os.path.isdir(dirname)) os.rmdir(dirname) def test_wrong_types(self): self.assertRaises(TypeError, GIMarshallingTests.filename_copy, 23) self.assertRaises(TypeError, GIMarshallingTests.filename_copy, []) def test_null(self): self.assertTrue(GIMarshallingTests.filename_copy(None) is None) self.assertRaises(TypeError, GIMarshallingTests.filename_exists, None) def test_round_trip(self): self.assertEqual(GIMarshallingTests.filename_copy(u"foo"), "foo") self.assertEqual(GIMarshallingTests.filename_copy(b"foo"), "foo") def test_contains_null(self): self.assertRaises( (ValueError, TypeError), GIMarshallingTests.filename_copy, b"foo\x00") self.assertRaises( (ValueError, TypeError), GIMarshallingTests.filename_copy, u"foo\x00") def test_win32_surrogates(self): if os.name != "nt": return copy = GIMarshallingTests.filename_copy glib_repr = GIMarshallingTests.filename_to_glib_repr self.assertEqual(copy(u"\ud83d"), u"\ud83d") self.assertEqual(copy(u"\x61\uDC00"), u"\x61\uDC00") self.assertEqual(copy(u"\uD800\uDC01"), u"\U00010001") self.assertEqual(copy(u"\uD83D\x20\uDCA9"), u"\uD83D\x20\uDCA9") self.assertEqual(glib_repr(u"\ud83d"), b"\xed\xa0\xbd") self.assertEqual(glib_repr(u"\uD800\uDC01"), b"\xf0\x90\x80\x81") self.assertEqual( glib_repr(u"\uD800\uDBFF"), b"\xED\xA0\x80\xED\xAF\xBF") self.assertEqual( glib_repr(u"\uD800\uE000"), b"\xED\xA0\x80\xEE\x80\x80") self.assertEqual( glib_repr(u"\uD7FF\uDC00"), b"\xED\x9F\xBF\xED\xB0\x80") self.assertEqual(glib_repr(u"\x61\uDC00"), b"\x61\xED\xB0\x80") self.assertEqual(glib_repr(u"\uDC00"), b"\xED\xB0\x80") def test_win32_bytes_py3(self): if not (os.name == "nt"): return values = [ b"foo", b"\xff\xff", b"\xc3\xb6\xc3\xa4\xc3\xbc", b"\xed\xa0\xbd", b"\xf0\x90\x80\x81", ] for v in values: try: uni = v.decode(sys.getfilesystemencoding(), "surrogatepass") except UnicodeDecodeError: continue self.assertEqual(GIMarshallingTests.filename_copy(v), uni) def test_unix_various(self): if os.name == "nt": return copy = GIMarshallingTests.filename_copy glib_repr = GIMarshallingTests.filename_to_glib_repr try: os.fsdecode(b"\xff\xfe") except UnicodeDecodeError: self.assertRaises(UnicodeDecodeError, copy, b"\xff\xfe") else: str_path = copy(b"\xff\xfe") self.assertTrue(isinstance(str_path, str)) self.assertEqual(str_path, os.fsdecode(b"\xff\xfe")) self.assertEqual(copy(str_path), str_path) self.assertEqual(glib_repr(b"\xff\xfe"), b"\xff\xfe") self.assertEqual(glib_repr(str_path), b"\xff\xfe") # if getfilesystemencoding is ASCII, then we should fail like # os.fsencode try: byte_path = os.fsencode(u"ä") except UnicodeEncodeError: self.assertRaises(UnicodeEncodeError, copy, u"ä") else: self.assertEqual(copy(u"ä"), u"ä") self.assertEqual(glib_repr(u"ä"), byte_path) @unittest.skip("glib can't handle non-unicode paths") def test_win32_surrogates_exists(self): if os.name != "nt": return path = os.path.join(self.workdir, u"\ud83d") with open(path, "wb"): self.assertTrue(os.path.exists(path)) self.assertTrue(GIMarshallingTests.filename_exists(path)) os.unlink(path) def test_path_exists_various_types(self): wd = self.workdir wdb = os.fsencode(wd) paths = [(wdb, b"foo-1"), (wd, u"foo-2"), (wd, u"öäü-3")] if sys.platform != "darwin": try: paths.append((wd, os.fsdecode(b"\xff\xfe-4"))) except UnicodeDecodeError: # depends on the code page pass if os.name != "nt": paths.append((wdb, b"\xff\xfe-5")) def valid_path(p): try: os.path.exists(p) except ValueError: return False return True for (d, path) in paths: if not valid_path(path): continue path = os.path.join(d, path) with open(path, "wb"): self.assertTrue(GIMarshallingTests.filename_exists(path)) class TestArray(unittest.TestCase): @unittest.skipUnless( hasattr(GIMarshallingTests, "array_bool_in"), "too old gi") def test_array_bool_in(self): GIMarshallingTests.array_bool_in([True, False, True, True]) @unittest.skipUnless( hasattr(GIMarshallingTests, "array_bool_out"), "too old gi") def test_array_bool_out(self): assert GIMarshallingTests.array_bool_out() == [True, False, True, True] @unittest.skipUnless( hasattr(GIMarshallingTests, "array_int64_in"), "too old gi") def test_array_int64_in(self): GIMarshallingTests.array_int64_in([-1, 0, 1, 2]) @unittest.skipUnless( hasattr(GIMarshallingTests, "array_uint64_in"), "too old gi") def test_array_uint64_in(self): GIMarshallingTests.array_uint64_in([GLib.MAXUINT64, 0, 1, 2]) @unittest.skipUnless( hasattr(GIMarshallingTests, "array_unichar_in"), "too old gi") def test_array_unichar_in(self): GIMarshallingTests.array_unichar_in(list(CONSTANT_UCS4)) GIMarshallingTests.array_unichar_in(CONSTANT_UCS4) @unittest.skipUnless( hasattr(GIMarshallingTests, "array_unichar_out"), "too old gi") def test_array_unichar_out(self): result = list(CONSTANT_UCS4) assert GIMarshallingTests.array_unichar_out() == result def test_array_zero_terminated_return_unichar(self): assert GIMarshallingTests.array_zero_terminated_return_unichar() == \ list(CONSTANT_UCS4) def test_array_fixed_int_return(self): self.assertEqual([-1, 0, 1, 2], GIMarshallingTests.array_fixed_int_return()) def test_array_fixed_short_return(self): self.assertEqual([-1, 0, 1, 2], GIMarshallingTests.array_fixed_short_return()) def test_array_fixed_int_in(self): GIMarshallingTests.array_fixed_int_in(Sequence([-1, 0, 1, 2])) self.assertRaises(TypeError, GIMarshallingTests.array_fixed_int_in, Sequence([-1, '0', 1, 2])) self.assertRaises(TypeError, GIMarshallingTests.array_fixed_int_in, 42) self.assertRaises(TypeError, GIMarshallingTests.array_fixed_int_in, None) def test_array_fixed_short_in(self): GIMarshallingTests.array_fixed_short_in(Sequence([-1, 0, 1, 2])) def test_array_fixed_out(self): self.assertEqual([-1, 0, 1, 2], GIMarshallingTests.array_fixed_out()) def test_array_fixed_inout(self): self.assertEqual([2, 1, 0, -1], GIMarshallingTests.array_fixed_inout([-1, 0, 1, 2])) def test_array_return(self): self.assertEqual([-1, 0, 1, 2], GIMarshallingTests.array_return()) def test_array_return_etc(self): self.assertEqual(([5, 0, 1, 9], 14), GIMarshallingTests.array_return_etc(5, 9)) def test_array_in(self): GIMarshallingTests.array_in(Sequence([-1, 0, 1, 2])) GIMarshallingTests.array_in_guint64_len(Sequence([-1, 0, 1, 2])) GIMarshallingTests.array_in_guint8_len(Sequence([-1, 0, 1, 2])) def test_array_in_len_before(self): GIMarshallingTests.array_in_len_before(Sequence([-1, 0, 1, 2])) def test_array_in_len_zero_terminated(self): GIMarshallingTests.array_in_len_zero_terminated(Sequence([-1, 0, 1, 2])) def test_array_uint8_in(self): GIMarshallingTests.array_uint8_in(Sequence([97, 98, 99, 100])) GIMarshallingTests.array_uint8_in(b"abcd") def test_array_string_in(self): GIMarshallingTests.array_string_in(['foo', 'bar']) def test_array_out(self): self.assertEqual([-1, 0, 1, 2], GIMarshallingTests.array_out()) def test_array_out_etc(self): self.assertEqual(([-5, 0, 1, 9], 4), GIMarshallingTests.array_out_etc(-5, 9)) def test_array_inout(self): self.assertEqual([-2, -1, 0, 1, 2], GIMarshallingTests.array_inout(Sequence([-1, 0, 1, 2]))) def test_array_inout_etc(self): self.assertEqual(([-5, -1, 0, 1, 9], 4), GIMarshallingTests.array_inout_etc(-5, Sequence([-1, 0, 1, 2]), 9)) def test_method_array_in(self): object_ = GIMarshallingTests.Object() object_.method_array_in(Sequence([-1, 0, 1, 2])) def test_method_array_out(self): object_ = GIMarshallingTests.Object() self.assertEqual([-1, 0, 1, 2], object_.method_array_out()) def test_method_array_inout(self): object_ = GIMarshallingTests.Object() self.assertEqual([-2, -1, 0, 1, 2], object_.method_array_inout(Sequence([-1, 0, 1, 2]))) def test_method_array_return(self): object_ = GIMarshallingTests.Object() self.assertEqual([-1, 0, 1, 2], object_.method_array_return()) def test_array_enum_in(self): GIMarshallingTests.array_enum_in([GIMarshallingTests.Enum.VALUE1, GIMarshallingTests.Enum.VALUE2, GIMarshallingTests.Enum.VALUE3]) def test_array_boxed_struct_in(self): struct1 = GIMarshallingTests.BoxedStruct() struct1.long_ = 1 struct2 = GIMarshallingTests.BoxedStruct() struct2.long_ = 2 struct3 = GIMarshallingTests.BoxedStruct() struct3.long_ = 3 GIMarshallingTests.array_struct_in([struct1, struct2, struct3]) def test_array_boxed_struct_in_item_marshal_failure(self): struct1 = GIMarshallingTests.BoxedStruct() struct1.long_ = 1 struct2 = GIMarshallingTests.BoxedStruct() struct2.long_ = 2 self.assertRaises(TypeError, GIMarshallingTests.array_struct_in, [struct1, struct2, 'not_a_struct']) def test_array_boxed_struct_value_in(self): struct1 = GIMarshallingTests.BoxedStruct() struct1.long_ = 1 struct2 = GIMarshallingTests.BoxedStruct() struct2.long_ = 2 struct3 = GIMarshallingTests.BoxedStruct() struct3.long_ = 3 GIMarshallingTests.array_struct_value_in([struct1, struct2, struct3]) def test_array_boxed_struct_value_in_item_marshal_failure(self): struct1 = GIMarshallingTests.BoxedStruct() struct1.long_ = 1 struct2 = GIMarshallingTests.BoxedStruct() struct2.long_ = 2 self.assertRaises(TypeError, GIMarshallingTests.array_struct_value_in, [struct1, struct2, 'not_a_struct']) def test_array_boxed_struct_take_in(self): struct1 = GIMarshallingTests.BoxedStruct() struct1.long_ = 1 struct2 = GIMarshallingTests.BoxedStruct() struct2.long_ = 2 struct3 = GIMarshallingTests.BoxedStruct() struct3.long_ = 3 GIMarshallingTests.array_struct_take_in([struct1, struct2, struct3]) self.assertEqual(1, struct1.long_) def test_array_boxed_struct_return(self): (struct1, struct2, struct3) = GIMarshallingTests.array_zero_terminated_return_struct() self.assertEqual(GIMarshallingTests.BoxedStruct, type(struct1)) self.assertEqual(GIMarshallingTests.BoxedStruct, type(struct2)) self.assertEqual(GIMarshallingTests.BoxedStruct, type(struct3)) self.assertEqual(42, struct1.long_) self.assertEqual(43, struct2.long_) self.assertEqual(44, struct3.long_) def test_array_simple_struct_in(self): struct1 = GIMarshallingTests.SimpleStruct() struct1.long_ = 1 struct2 = GIMarshallingTests.SimpleStruct() struct2.long_ = 2 struct3 = GIMarshallingTests.SimpleStruct() struct3.long_ = 3 GIMarshallingTests.array_simple_struct_in([struct1, struct2, struct3]) def test_array_simple_struct_in_item_marshal_failure(self): struct1 = GIMarshallingTests.SimpleStruct() struct1.long_ = 1 struct2 = GIMarshallingTests.SimpleStruct() struct2.long_ = 2 self.assertRaises(TypeError, GIMarshallingTests.array_simple_struct_in, [struct1, struct2, 'not_a_struct']) def test_array_multi_array_key_value_in(self): GIMarshallingTests.multi_array_key_value_in(["one", "two", "three"], [1, 2, 3]) def test_array_in_nonzero_nonlen(self): GIMarshallingTests.array_in_nonzero_nonlen(1, b'abcd') def test_array_fixed_out_struct(self): struct1, struct2 = GIMarshallingTests.array_fixed_out_struct() self.assertEqual(7, struct1.long_) self.assertEqual(6, struct1.int8) self.assertEqual(6, struct2.long_) self.assertEqual(7, struct2.int8) def test_array_zero_terminated_return(self): self.assertEqual(['0', '1', '2'], GIMarshallingTests.array_zero_terminated_return()) def test_array_zero_terminated_return_null(self): self.assertEqual([], GIMarshallingTests.array_zero_terminated_return_null()) def test_array_zero_terminated_in(self): GIMarshallingTests.array_zero_terminated_in(Sequence(['0', '1', '2'])) def test_array_zero_terminated_out(self): self.assertEqual(['0', '1', '2'], GIMarshallingTests.array_zero_terminated_out()) def test_array_zero_terminated_inout(self): self.assertEqual(['-1', '0', '1', '2'], GIMarshallingTests.array_zero_terminated_inout(['0', '1', '2'])) def test_init_function(self): self.assertEqual((True, []), GIMarshallingTests.init_function([])) self.assertEqual((True, []), GIMarshallingTests.init_function(['hello'])) self.assertEqual((True, ['hello']), GIMarshallingTests.init_function(['hello', 'world'])) def test_enum_array_return_type(self): self.assertEqual(GIMarshallingTests.enum_array_return_type(), [GIMarshallingTests.ExtraEnum.VALUE1, GIMarshallingTests.ExtraEnum.VALUE2, GIMarshallingTests.ExtraEnum.VALUE3]) class TestGStrv(unittest.TestCase): def test_gstrv_return(self): self.assertEqual(['0', '1', '2'], GIMarshallingTests.gstrv_return()) def test_gstrv_in(self): GIMarshallingTests.gstrv_in(Sequence(['0', '1', '2'])) def test_gstrv_out(self): self.assertEqual(['0', '1', '2'], GIMarshallingTests.gstrv_out()) def test_gstrv_inout(self): self.assertEqual(['-1', '0', '1', '2'], GIMarshallingTests.gstrv_inout(['0', '1', '2'])) class TestArrayGVariant(unittest.TestCase): def test_array_gvariant_none_in(self): v = [GLib.Variant("i", 27), GLib.Variant("s", "Hello")] returned = [GLib.Variant.unpack(r) for r in GIMarshallingTests.array_gvariant_none_in(v)] self.assertEqual([27, "Hello"], returned) def test_array_gvariant_container_in(self): v = [GLib.Variant("i", 27), GLib.Variant("s", "Hello")] returned = [GLib.Variant.unpack(r) for r in GIMarshallingTests.array_gvariant_container_in(v)] self.assertEqual([27, "Hello"], returned) def test_array_gvariant_full_in(self): v = [GLib.Variant("i", 27), GLib.Variant("s", "Hello")] returned = [GLib.Variant.unpack(r) for r in GIMarshallingTests.array_gvariant_full_in(v)] self.assertEqual([27, "Hello"], returned) def test_bytearray_gvariant(self): v = GLib.Variant.new_bytestring(b"foo") self.assertEqual(v.get_bytestring(), b"foo") class TestGArray(unittest.TestCase): @unittest.skipUnless( hasattr(GIMarshallingTests, "garray_bool_none_in"), "too old gi") def test_garray_bool_none_in(self): GIMarshallingTests.garray_bool_none_in([True, False, True, True]) @unittest.skipUnless( hasattr(GIMarshallingTests, "garray_unichar_none_in"), "too old gi") def test_garray_unichar_none_in(self): GIMarshallingTests.garray_unichar_none_in(CONSTANT_UCS4) GIMarshallingTests.garray_unichar_none_in(list(CONSTANT_UCS4)) def test_garray_int_none_return(self): self.assertEqual([-1, 0, 1, 2], GIMarshallingTests.garray_int_none_return()) def test_garray_uint64_none_return(self): self.assertEqual([0, GLib.MAXUINT64], GIMarshallingTests.garray_uint64_none_return()) def test_garray_utf8_none_return(self): self.assertEqual(['0', '1', '2'], GIMarshallingTests.garray_utf8_none_return()) def test_garray_utf8_container_return(self): self.assertEqual(['0', '1', '2'], GIMarshallingTests.garray_utf8_container_return()) def test_garray_utf8_full_return(self): self.assertEqual(['0', '1', '2'], GIMarshallingTests.garray_utf8_full_return()) def test_garray_int_none_in(self): GIMarshallingTests.garray_int_none_in(Sequence([-1, 0, 1, 2])) self.assertRaises(TypeError, GIMarshallingTests.garray_int_none_in, Sequence([-1, '0', 1, 2])) self.assertRaises(TypeError, GIMarshallingTests.garray_int_none_in, 42) self.assertRaises(TypeError, GIMarshallingTests.garray_int_none_in, None) def test_garray_uint64_none_in(self): GIMarshallingTests.garray_uint64_none_in(Sequence([0, GLib.MAXUINT64])) def test_garray_utf8_none_in(self): GIMarshallingTests.garray_utf8_none_in(Sequence(['0', '1', '2'])) def test_garray_utf8_none_out(self): self.assertEqual(['0', '1', '2'], GIMarshallingTests.garray_utf8_none_out()) def test_garray_utf8_container_out(self): self.assertEqual(['0', '1', '2'], GIMarshallingTests.garray_utf8_container_out()) def test_garray_utf8_full_out(self): self.assertEqual(['0', '1', '2'], GIMarshallingTests.garray_utf8_full_out()) def test_garray_utf8_full_out_caller_allocated(self): self.assertEqual(['0', '1', '2'], GIMarshallingTests.garray_utf8_full_out_caller_allocated()) def test_garray_utf8_none_inout(self): self.assertEqual(['-2', '-1', '0', '1'], GIMarshallingTests.garray_utf8_none_inout(Sequence(('0', '1', '2')))) def test_garray_utf8_container_inout(self): self.assertEqual(['-2', '-1', '0', '1'], GIMarshallingTests.garray_utf8_container_inout(['0', '1', '2'])) def test_garray_utf8_full_inout(self): self.assertEqual(['-2', '-1', '0', '1'], GIMarshallingTests.garray_utf8_full_inout(['0', '1', '2'])) class TestGPtrArray(unittest.TestCase): def test_gptrarray_utf8_none_return(self): self.assertEqual(['0', '1', '2'], GIMarshallingTests.gptrarray_utf8_none_return()) def test_gptrarray_utf8_container_return(self): self.assertEqual(['0', '1', '2'], GIMarshallingTests.gptrarray_utf8_container_return()) def test_gptrarray_utf8_full_return(self): self.assertEqual(['0', '1', '2'], GIMarshallingTests.gptrarray_utf8_full_return()) def test_gptrarray_utf8_none_in(self): GIMarshallingTests.gptrarray_utf8_none_in(Sequence(['0', '1', '2'])) def test_gptrarray_utf8_none_out(self): self.assertEqual(['0', '1', '2'], GIMarshallingTests.gptrarray_utf8_none_out()) def test_gptrarray_utf8_container_out(self): self.assertEqual(['0', '1', '2'], GIMarshallingTests.gptrarray_utf8_container_out()) def test_gptrarray_utf8_full_out(self): self.assertEqual(['0', '1', '2'], GIMarshallingTests.gptrarray_utf8_full_out()) def test_gptrarray_utf8_none_inout(self): self.assertEqual(['-2', '-1', '0', '1'], GIMarshallingTests.gptrarray_utf8_none_inout(Sequence(('0', '1', '2')))) def test_gptrarray_utf8_container_inout(self): self.assertEqual(['-2', '-1', '0', '1'], GIMarshallingTests.gptrarray_utf8_container_inout(['0', '1', '2'])) def test_gptrarray_utf8_full_inout(self): self.assertEqual(['-2', '-1', '0', '1'], GIMarshallingTests.gptrarray_utf8_full_inout(['0', '1', '2'])) class TestGBytes(unittest.TestCase): def test_gbytes_create(self): b = GLib.Bytes.new(b'\x00\x01\xFF') self.assertEqual(3, b.get_size()) self.assertEqual(b'\x00\x01\xFF', b.get_data()) def test_gbytes_create_take(self): b = GLib.Bytes.new_take(b'\x00\x01\xFF') self.assertEqual(3, b.get_size()) self.assertEqual(b'\x00\x01\xFF', b.get_data()) def test_gbytes_full_return(self): b = GIMarshallingTests.gbytes_full_return() self.assertEqual(4, b.get_size()) self.assertEqual(b'\x00\x31\xFF\x33', b.get_data()) def test_gbytes_none_in(self): b = GIMarshallingTests.gbytes_full_return() GIMarshallingTests.gbytes_none_in(b) def test_compare(self): a1 = GLib.Bytes.new(b'\x00\x01\xFF') a2 = GLib.Bytes.new(b'\x00\x01\xFF') b = GLib.Bytes.new(b'\x00\x01\xFE') self.assertTrue(a1.equal(a2)) self.assertTrue(a2.equal(a1)) self.assertFalse(a1.equal(b)) self.assertFalse(b.equal(a2)) self.assertEqual(0, a1.compare(a2)) self.assertLess(0, a1.compare(b)) self.assertGreater(0, b.compare(a1)) class TestGByteArray(unittest.TestCase): def test_new(self): ba = GLib.ByteArray.new() self.assertEqual(b'', ba) ba = GLib.ByteArray.new_take(b'\x01\x02\xFF') self.assertEqual(b'\x01\x02\xFF', ba) def test_bytearray_full_return(self): self.assertEqual(b'\x001\xFF3', GIMarshallingTests.bytearray_full_return()) def test_bytearray_none_in(self): b = b'\x00\x31\xFF\x33' ba = GLib.ByteArray.new_take(b) # b should always have the same value even # though the generated GByteArray is being modified GIMarshallingTests.bytearray_none_in(b) GIMarshallingTests.bytearray_none_in(b) # The GByteArray is just a bytes # thus it will not reflect any changes GIMarshallingTests.bytearray_none_in(ba) GIMarshallingTests.bytearray_none_in(ba) class TestGList(unittest.TestCase): def test_glist_int_none_return(self): self.assertEqual([-1, 0, 1, 2], GIMarshallingTests.glist_int_none_return()) def test_glist_uint32_none_return(self): self.assertEqual([0, GLib.MAXUINT32], GIMarshallingTests.glist_uint32_none_return()) def test_glist_utf8_none_return(self): self.assertEqual(['0', '1', '2'], GIMarshallingTests.glist_utf8_none_return()) def test_glist_utf8_container_return(self): self.assertEqual(['0', '1', '2'], GIMarshallingTests.glist_utf8_container_return()) def test_glist_utf8_full_return(self): self.assertEqual(['0', '1', '2'], GIMarshallingTests.glist_utf8_full_return()) def test_glist_int_none_in(self): GIMarshallingTests.glist_int_none_in(Sequence((-1, 0, 1, 2))) self.assertRaises(TypeError, GIMarshallingTests.glist_int_none_in, Sequence((-1, '0', 1, 2))) self.assertRaises(TypeError, GIMarshallingTests.glist_int_none_in, 42) self.assertRaises(TypeError, GIMarshallingTests.glist_int_none_in, None) def test_glist_int_none_in_error_getitem(self): class FailingSequence(Sequence): def __getitem__(self, key): raise Exception self.assertRaises(Exception, GIMarshallingTests.glist_int_none_in, FailingSequence((-1, 0, 1, 2))) def test_glist_uint32_none_in(self): GIMarshallingTests.glist_uint32_none_in(Sequence((0, GLib.MAXUINT32))) def test_glist_utf8_none_in(self): GIMarshallingTests.glist_utf8_none_in(Sequence(('0', '1', '2'))) def test_glist_utf8_none_out(self): self.assertEqual(['0', '1', '2'], GIMarshallingTests.glist_utf8_none_out()) def test_glist_utf8_container_out(self): self.assertEqual(['0', '1', '2'], GIMarshallingTests.glist_utf8_container_out()) def test_glist_utf8_full_out(self): self.assertEqual(['0', '1', '2'], GIMarshallingTests.glist_utf8_full_out()) def test_glist_utf8_none_inout(self): self.assertEqual(['-2', '-1', '0', '1'], GIMarshallingTests.glist_utf8_none_inout(Sequence(('0', '1', '2')))) def test_glist_utf8_container_inout(self): self.assertEqual(['-2', '-1', '0', '1'], GIMarshallingTests.glist_utf8_container_inout(('0', '1', '2'))) def test_glist_utf8_full_inout(self): self.assertEqual(['-2', '-1', '0', '1'], GIMarshallingTests.glist_utf8_full_inout(('0', '1', '2'))) class TestGSList(unittest.TestCase): def test_gslist_int_none_return(self): self.assertEqual([-1, 0, 1, 2], GIMarshallingTests.gslist_int_none_return()) def test_gslist_utf8_none_return(self): self.assertEqual(['0', '1', '2'], GIMarshallingTests.gslist_utf8_none_return()) def test_gslist_utf8_container_return(self): self.assertEqual(['0', '1', '2'], GIMarshallingTests.gslist_utf8_container_return()) def test_gslist_utf8_full_return(self): self.assertEqual(['0', '1', '2'], GIMarshallingTests.gslist_utf8_full_return()) def test_gslist_int_none_in(self): GIMarshallingTests.gslist_int_none_in(Sequence((-1, 0, 1, 2))) self.assertRaises(TypeError, GIMarshallingTests.gslist_int_none_in, Sequence((-1, '0', 1, 2))) self.assertRaises(TypeError, GIMarshallingTests.gslist_int_none_in, 42) self.assertRaises(TypeError, GIMarshallingTests.gslist_int_none_in, None) def test_gslist_int_none_in_error_getitem(self): class FailingSequence(Sequence): def __getitem__(self, key): raise Exception self.assertRaises(Exception, GIMarshallingTests.gslist_int_none_in, FailingSequence((-1, 0, 1, 2))) def test_gslist_utf8_none_in(self): GIMarshallingTests.gslist_utf8_none_in(Sequence(('0', '1', '2'))) def test_gslist_utf8_none_out(self): self.assertEqual(['0', '1', '2'], GIMarshallingTests.gslist_utf8_none_out()) def test_gslist_utf8_container_out(self): self.assertEqual(['0', '1', '2'], GIMarshallingTests.gslist_utf8_container_out()) def test_gslist_utf8_full_out(self): self.assertEqual(['0', '1', '2'], GIMarshallingTests.gslist_utf8_full_out()) def test_gslist_utf8_none_inout(self): self.assertEqual(['-2', '-1', '0', '1'], GIMarshallingTests.gslist_utf8_none_inout(Sequence(('0', '1', '2')))) def test_gslist_utf8_container_inout(self): self.assertEqual(['-2', '-1', '0', '1'], GIMarshallingTests.gslist_utf8_container_inout(('0', '1', '2'))) def test_gslist_utf8_full_inout(self): self.assertEqual(['-2', '-1', '0', '1'], GIMarshallingTests.gslist_utf8_full_inout(('0', '1', '2'))) class TestGHashTable(unittest.TestCase): @unittest.skip("broken") def test_ghashtable_double_in(self): GIMarshallingTests.ghashtable_double_in( {"-1": -0.1, "0": 0.0, "1": 0.1, "2": 0.2}) @unittest.skip("broken") def test_ghashtable_float_in(self): GIMarshallingTests.ghashtable_float_in( {"-1": -0.1, "0": 0.0, "1": 0.1, "2": 0.2}) @unittest.skip("broken") def test_ghashtable_int64_in(self): GIMarshallingTests.ghashtable_int64_in( {"-1": GLib.MAXUINT32 + 1, "0": 0, "1": 1, "2": 2}) @unittest.skip("broken") def test_ghashtable_uint64_in(self): GIMarshallingTests.ghashtable_uint64_in( {"-1": GLib.MAXUINT32 + 1, "0": 0, "1": 1, "2": 2}) def test_ghashtable_int_none_return(self): self.assertEqual({-1: 1, 0: 0, 1: -1, 2: -2}, GIMarshallingTests.ghashtable_int_none_return()) def test_ghashtable_int_none_return2(self): self.assertEqual({'-1': '1', '0': '0', '1': '-1', '2': '-2'}, GIMarshallingTests.ghashtable_utf8_none_return()) def test_ghashtable_int_container_return(self): self.assertEqual({'-1': '1', '0': '0', '1': '-1', '2': '-2'}, GIMarshallingTests.ghashtable_utf8_container_return()) def test_ghashtable_int_full_return(self): self.assertEqual({'-1': '1', '0': '0', '1': '-1', '2': '-2'}, GIMarshallingTests.ghashtable_utf8_full_return()) def test_ghashtable_int_none_in(self): GIMarshallingTests.ghashtable_int_none_in({-1: 1, 0: 0, 1: -1, 2: -2}) self.assertRaises(TypeError, GIMarshallingTests.ghashtable_int_none_in, {-1: 1, '0': 0, 1: -1, 2: -2}) self.assertRaises(TypeError, GIMarshallingTests.ghashtable_int_none_in, {-1: 1, 0: '0', 1: -1, 2: -2}) self.assertRaises(TypeError, GIMarshallingTests.ghashtable_int_none_in, '{-1: 1, 0: 0, 1: -1, 2: -2}') self.assertRaises(TypeError, GIMarshallingTests.ghashtable_int_none_in, None) def test_ghashtable_utf8_none_in(self): GIMarshallingTests.ghashtable_utf8_none_in({'-1': '1', '0': '0', '1': '-1', '2': '-2'}) def test_ghashtable_utf8_none_out(self): self.assertEqual({'-1': '1', '0': '0', '1': '-1', '2': '-2'}, GIMarshallingTests.ghashtable_utf8_none_out()) def test_ghashtable_utf8_container_out(self): self.assertEqual({'-1': '1', '0': '0', '1': '-1', '2': '-2'}, GIMarshallingTests.ghashtable_utf8_container_out()) def test_ghashtable_utf8_full_out(self): self.assertEqual({'-1': '1', '0': '0', '1': '-1', '2': '-2'}, GIMarshallingTests.ghashtable_utf8_full_out()) def test_ghashtable_utf8_none_inout(self): i = {'-1': '1', '0': '0', '1': '-1', '2': '-2'} self.assertEqual({'-1': '1', '0': '0', '1': '1'}, GIMarshallingTests.ghashtable_utf8_none_inout(i)) def test_ghashtable_utf8_container_inout(self): i = {'-1': '1', '0': '0', '1': '-1', '2': '-2'} self.assertEqual({'-1': '1', '0': '0', '1': '1'}, GIMarshallingTests.ghashtable_utf8_container_inout(i)) def test_ghashtable_utf8_full_inout(self): i = {'-1': '1', '0': '0', '1': '-1', '2': '-2'} self.assertEqual({'-1': '1', '0': '0', '1': '1'}, GIMarshallingTests.ghashtable_utf8_full_inout(i)) def test_ghashtable_enum_none_in(self): GIMarshallingTests.ghashtable_enum_none_in({1: GIMarshallingTests.ExtraEnum.VALUE1, 2: GIMarshallingTests.ExtraEnum.VALUE2, 3: GIMarshallingTests.ExtraEnum.VALUE3}) def test_ghashtable_enum_none_return(self): self.assertEqual({1: GIMarshallingTests.ExtraEnum.VALUE1, 2: GIMarshallingTests.ExtraEnum.VALUE2, 3: GIMarshallingTests.ExtraEnum.VALUE3}, GIMarshallingTests.ghashtable_enum_none_return()) class TestGValue(unittest.TestCase): def test_gvalue_return(self): self.assertEqual(42, GIMarshallingTests.gvalue_return()) def test_gvalue_in(self): GIMarshallingTests.gvalue_in(42) value = GObject.Value(GObject.TYPE_INT, 42) GIMarshallingTests.gvalue_in(value) def test_gvalue_in_with_modification(self): value = GObject.Value(GObject.TYPE_INT, 42) GIMarshallingTests.gvalue_in_with_modification(value) self.assertEqual(value.get_int(), 24) def test_gvalue_int64_in(self): value = GObject.Value(GObject.TYPE_INT64, GLib.MAXINT64) GIMarshallingTests.gvalue_int64_in(value) def test_gvalue_in_with_type(self): value = GObject.Value(GObject.TYPE_STRING, 'foo') GIMarshallingTests.gvalue_in_with_type(value, GObject.TYPE_STRING) value = GObject.Value(GIMarshallingTests.Flags.__gtype__, GIMarshallingTests.Flags.VALUE1) GIMarshallingTests.gvalue_in_with_type(value, GObject.TYPE_FLAGS) def test_gvalue_in_enum(self): value = GObject.Value(GIMarshallingTests.Enum.__gtype__, GIMarshallingTests.Enum.VALUE3) GIMarshallingTests.gvalue_in_enum(value) def test_gvalue_out(self): self.assertEqual(42, GIMarshallingTests.gvalue_out()) def test_gvalue_int64_out(self): self.assertEqual(GLib.MAXINT64, GIMarshallingTests.gvalue_int64_out()) def test_gvalue_out_caller_allocates(self): self.assertEqual(42, GIMarshallingTests.gvalue_out_caller_allocates()) def test_gvalue_inout(self): self.assertEqual('42', GIMarshallingTests.gvalue_inout(42)) value = GObject.Value(int, 42) self.assertEqual('42', GIMarshallingTests.gvalue_inout(value)) def test_gvalue_flat_array_in(self): # the function already asserts the correct values GIMarshallingTests.gvalue_flat_array([42, "42", True]) def test_gvalue_flat_array_in_item_marshal_failure(self): # Tests the failure to marshal 2^256 to a GValue mid-way through the array marshaling. self.assertRaises(OverflowError, GIMarshallingTests.gvalue_flat_array, [42, 2 ** 256, True]) self.assertRaises(OverflowError, GIMarshallingTests.gvalue_flat_array, [GLib.MAXINT + 1, "42", True]) self.assertRaises(OverflowError, GIMarshallingTests.gvalue_flat_array, [GLib.MININT - 1, "42", True]) # FIXME: https://gitlab.gnome.org/GNOME/pygobject/-/issues/582#note_1764164 exc_prefix = "Item 0: " if sys.version_info[:2] < (3, 12) else "" with pytest.raises( OverflowError, match=exc_prefix + '%d not in range %d to %d' % ( GLib.MAXINT + 1, GLib.MININT, GLib.MAXINT)): GIMarshallingTests.gvalue_flat_array([GLib.MAXINT + 1, "42", True]) min_, max_ = GLib.MININT, GLib.MAXINT with pytest.raises( OverflowError, match=exc_prefix + '%d not in range %d to %d' % ( GLib.MAXUINT64 * 2, min_, max_)): GIMarshallingTests.gvalue_flat_array([GLib.MAXUINT64 * 2, "42", True]) def test_gvalue_flat_array_out(self): values = GIMarshallingTests.return_gvalue_flat_array() self.assertEqual(values, [42, '42', True]) def test_gvalue_gobject_ref_counts_simple(self): obj = GObject.Object() grefcount = obj.__grefcount__ value = GObject.Value(GObject.TYPE_OBJECT, obj) del value gc.collect() gc.collect() assert obj.__grefcount__ == grefcount def test_gvalue_gobject_ref_counts(self): # Tests a GObject held by a GValue obj = GObject.Object() ref = weakref.ref(obj) grefcount = obj.__grefcount__ value = GObject.Value() value.init(GObject.TYPE_OBJECT) # TYPE_OBJECT will inc ref count as it should value.set_object(obj) self.assertEqual(obj.__grefcount__, grefcount + 1) # multiple set_object should not inc ref count value.set_object(obj) self.assertEqual(obj.__grefcount__, grefcount + 1) # get_object will re-use the same wrapper as obj res = value.get_object() self.assertEqual(obj, res) self.assertEqual(obj.__grefcount__, grefcount + 1) # multiple get_object should not inc ref count res = value.get_object() self.assertEqual(obj.__grefcount__, grefcount + 1) # deletion of the result and value holder should bring the # refcount back to where we started del res del value gc.collect() gc.collect() self.assertEqual(obj.__grefcount__, grefcount) del obj gc.collect() self.assertEqual(ref(), None) @unittest.skipUnless(hasattr(sys, "getrefcount"), "no sys.getrefcount") def test_gvalue_boxed_ref_counts(self): # Tests a boxed type wrapping a python object pointer (TYPE_PYOBJECT) # held by a GValue class Obj(object): pass obj = Obj() ref = weakref.ref(obj) refcount = sys.getrefcount(obj) value = GObject.Value() value.init(GObject.TYPE_PYOBJECT) # boxed TYPE_PYOBJECT will inc ref count as it should value.set_boxed(obj) self.assertEqual(sys.getrefcount(obj), refcount + 1) # multiple set_boxed should not inc ref count value.set_boxed(obj) self.assertEqual(sys.getrefcount(obj), refcount + 1) res = value.get_boxed() self.assertEqual(obj, res) self.assertEqual(sys.getrefcount(obj), refcount + 2) # multiple get_boxed should not inc ref count res = value.get_boxed() self.assertEqual(sys.getrefcount(obj), refcount + 2) # deletion of the result and value holder should bring the # refcount back to where we started del res del value gc.collect() self.assertEqual(sys.getrefcount(obj), refcount) del obj gc.collect() self.assertEqual(ref(), None) @unittest.skip("broken") def test_gvalue_flat_array_round_trip(self): self.assertEqual([42, '42', True], GIMarshallingTests.gvalue_flat_array_round_trip(42, '42', True)) class TestGClosure(unittest.TestCase): def test_in(self): GIMarshallingTests.gclosure_in(lambda: 42) def test_in_partial(self): from functools import partial called_args = [] called_kwargs = {} def callback(*args, **kwargs): called_args.extend(args) called_kwargs.update(kwargs) return 42 func = partial(callback, 1, 2, 3, foo=42) GIMarshallingTests.gclosure_in(func) assert called_args == [1, 2, 3] assert called_kwargs["foo"] == 42 def test_pass(self): # test passing a closure between two C calls closure = GIMarshallingTests.gclosure_return() GIMarshallingTests.gclosure_in(closure) def test_type_error(self): self.assertRaises(TypeError, GIMarshallingTests.gclosure_in, 42) self.assertRaises(TypeError, GIMarshallingTests.gclosure_in, None) class TestCallbacks(unittest.TestCase): def test_return_value_only(self): def cb(): return 5 self.assertEqual(GIMarshallingTests.callback_return_value_only(cb), 5) def test_one_out_arg(self): def cb(): return 5.5 self.assertAlmostEqual(GIMarshallingTests.callback_one_out_parameter(cb), 5.5) def test_multiple_out_args(self): def cb(): return (5.5, 42.0) res = GIMarshallingTests.callback_multiple_out_parameters(cb) self.assertAlmostEqual(res[0], 5.5) self.assertAlmostEqual(res[1], 42.0) def test_return_and_one_out_arg(self): def cb(): return (5, 42.0) res = GIMarshallingTests.callback_return_value_and_one_out_parameter(cb) self.assertEqual(res[0], 5) self.assertAlmostEqual(res[1], 42.0) def test_return_and_multiple_out_arg(self): def cb(): return (5, 42, -1000) self.assertEqual(GIMarshallingTests.callback_return_value_and_multiple_out_parameters(cb), (5, 42, -1000)) class TestPointer(unittest.TestCase): def test_pointer_in_return(self): self.assertEqual(GIMarshallingTests.pointer_in_return(42), 42) class TestEnum(unittest.TestCase): def test_enum(self): self.assertTrue(issubclass(GIMarshallingTests.Enum, int)) self.assertTrue(isinstance(GIMarshallingTests.Enum.VALUE1, GIMarshallingTests.Enum)) self.assertTrue(isinstance(GIMarshallingTests.Enum.VALUE2, GIMarshallingTests.Enum)) self.assertTrue(isinstance(GIMarshallingTests.Enum.VALUE3, GIMarshallingTests.Enum)) self.assertEqual(42, GIMarshallingTests.Enum.VALUE3) def test_value_nick_and_name(self): self.assertEqual(GIMarshallingTests.Enum.VALUE1.value_nick, 'value1') self.assertEqual(GIMarshallingTests.Enum.VALUE2.value_nick, 'value2') self.assertEqual(GIMarshallingTests.Enum.VALUE3.value_nick, 'value3') self.assertEqual(GIMarshallingTests.Enum.VALUE1.value_name, 'GI_MARSHALLING_TESTS_ENUM_VALUE1') self.assertEqual(GIMarshallingTests.Enum.VALUE2.value_name, 'GI_MARSHALLING_TESTS_ENUM_VALUE2') self.assertEqual(GIMarshallingTests.Enum.VALUE3.value_name, 'GI_MARSHALLING_TESTS_ENUM_VALUE3') def test_enum_in(self): GIMarshallingTests.enum_in(GIMarshallingTests.Enum.VALUE3) GIMarshallingTests.enum_in(42) self.assertRaises(TypeError, GIMarshallingTests.enum_in, 43) self.assertRaises(TypeError, GIMarshallingTests.enum_in, 'GIMarshallingTests.Enum.VALUE3') def test_enum_return(self): enum = GIMarshallingTests.enum_returnv() self.assertTrue(isinstance(enum, GIMarshallingTests.Enum)) self.assertEqual(enum, GIMarshallingTests.Enum.VALUE3) def test_enum_out(self): enum = GIMarshallingTests.enum_out() self.assertTrue(isinstance(enum, GIMarshallingTests.Enum)) self.assertEqual(enum, GIMarshallingTests.Enum.VALUE3) def test_enum_inout(self): enum = GIMarshallingTests.enum_inout(GIMarshallingTests.Enum.VALUE3) self.assertTrue(isinstance(enum, GIMarshallingTests.Enum)) self.assertEqual(enum, GIMarshallingTests.Enum.VALUE1) def test_enum_second(self): # check for the bug where different non-gtype enums share the same class self.assertNotEqual(GIMarshallingTests.Enum, GIMarshallingTests.SecondEnum) # check that values are not being shared between different enums self.assertTrue(hasattr(GIMarshallingTests.SecondEnum, "SECONDVALUE1")) self.assertRaises(AttributeError, getattr, GIMarshallingTests.Enum, "SECONDVALUE1") self.assertTrue(hasattr(GIMarshallingTests.Enum, "VALUE1")) self.assertRaises(AttributeError, getattr, GIMarshallingTests.SecondEnum, "VALUE1") def test_enum_gtype_name_is_namespaced(self): self.assertEqual(GIMarshallingTests.Enum.__gtype__.name, 'PyGIMarshallingTestsEnum') def test_enum_add_type_error(self): self.assertRaises(TypeError, gi._gi.enum_add, GIMarshallingTests.NoTypeFlags.__gtype__) def test_type_module_name(self): self.assertEqual(GIMarshallingTests.Enum.__name__, "Enum") self.assertEqual(GIMarshallingTests.Enum.__module__, "gi.repository.GIMarshallingTests") def test_hash(self): assert (hash(GIMarshallingTests.Enum.VALUE1) == hash(GIMarshallingTests.Enum(GIMarshallingTests.Enum.VALUE1))) def test_repr(self): self.assertEqual(repr(GIMarshallingTests.Enum.VALUE3), "") class TestEnumVFuncResults(unittest.TestCase): class EnumTester(GIMarshallingTests.Object): def do_vfunc_return_enum(self): return GIMarshallingTests.Enum.VALUE2 def do_vfunc_out_enum(self): return GIMarshallingTests.Enum.VALUE3 def test_vfunc_return_enum(self): tester = self.EnumTester() self.assertEqual(tester.vfunc_return_enum(), GIMarshallingTests.Enum.VALUE2) def test_vfunc_out_enum(self): tester = self.EnumTester() self.assertEqual(tester.vfunc_out_enum(), GIMarshallingTests.Enum.VALUE3) class TestGEnum(unittest.TestCase): def test_genum(self): self.assertTrue(issubclass(GIMarshallingTests.GEnum, GObject.GEnum)) self.assertTrue(isinstance(GIMarshallingTests.GEnum.VALUE1, GIMarshallingTests.GEnum)) self.assertTrue(isinstance(GIMarshallingTests.GEnum.VALUE2, GIMarshallingTests.GEnum)) self.assertTrue(isinstance(GIMarshallingTests.GEnum.VALUE3, GIMarshallingTests.GEnum)) self.assertEqual(42, GIMarshallingTests.GEnum.VALUE3) def test_pickle(self): v = GIMarshallingTests.GEnum.VALUE3 new_v = pickle.loads(pickle.dumps(v)) assert new_v == v assert isinstance(new_v, GIMarshallingTests.GEnum) def test_value_nick_and_name(self): self.assertEqual(GIMarshallingTests.GEnum.VALUE1.value_nick, 'value1') self.assertEqual(GIMarshallingTests.GEnum.VALUE2.value_nick, 'value2') self.assertEqual(GIMarshallingTests.GEnum.VALUE3.value_nick, 'value3') self.assertEqual(GIMarshallingTests.GEnum.VALUE1.value_name, 'GI_MARSHALLING_TESTS_GENUM_VALUE1') self.assertEqual(GIMarshallingTests.GEnum.VALUE2.value_name, 'GI_MARSHALLING_TESTS_GENUM_VALUE2') self.assertEqual(GIMarshallingTests.GEnum.VALUE3.value_name, 'GI_MARSHALLING_TESTS_GENUM_VALUE3') def test_genum_in(self): GIMarshallingTests.genum_in(GIMarshallingTests.GEnum.VALUE3) GIMarshallingTests.genum_in(42) GIMarshallingTests.GEnum.in_(42) self.assertRaises(TypeError, GIMarshallingTests.genum_in, 43) self.assertRaises(TypeError, GIMarshallingTests.genum_in, 'GIMarshallingTests.GEnum.VALUE3') def test_genum_return(self): genum = GIMarshallingTests.genum_returnv() self.assertTrue(isinstance(genum, GIMarshallingTests.GEnum)) self.assertEqual(genum, GIMarshallingTests.GEnum.VALUE3) def test_genum_out(self): genum = GIMarshallingTests.genum_out() genum = GIMarshallingTests.GEnum.out() self.assertTrue(isinstance(genum, GIMarshallingTests.GEnum)) self.assertEqual(genum, GIMarshallingTests.GEnum.VALUE3) def test_genum_inout(self): genum = GIMarshallingTests.genum_inout(GIMarshallingTests.GEnum.VALUE3) self.assertTrue(isinstance(genum, GIMarshallingTests.GEnum)) self.assertEqual(genum, GIMarshallingTests.GEnum.VALUE1) def test_type_module_name(self): self.assertEqual(GIMarshallingTests.GEnum.__name__, "GEnum") self.assertEqual(GIMarshallingTests.GEnum.__module__, "gi.repository.GIMarshallingTests") def test_hash(self): assert (hash(GIMarshallingTests.GEnum.VALUE3) == hash(GIMarshallingTests.GEnum(GIMarshallingTests.GEnum.VALUE3))) def test_repr(self): self.assertEqual(repr(GIMarshallingTests.GEnum.VALUE3), "") class TestGFlags(unittest.TestCase): def test_flags(self): self.assertTrue(issubclass(GIMarshallingTests.Flags, GObject.GFlags)) self.assertTrue(isinstance(GIMarshallingTests.Flags.VALUE1, GIMarshallingTests.Flags)) self.assertTrue(isinstance(GIMarshallingTests.Flags.VALUE2, GIMarshallingTests.Flags)) self.assertTrue(isinstance(GIMarshallingTests.Flags.VALUE3, GIMarshallingTests.Flags)) # __or__() operation should still return an instance, not an int. self.assertTrue(isinstance(GIMarshallingTests.Flags.VALUE1 | GIMarshallingTests.Flags.VALUE2, GIMarshallingTests.Flags)) self.assertEqual(1 << 1, GIMarshallingTests.Flags.VALUE2) def test_value_nick_and_name(self): self.assertEqual(GIMarshallingTests.Flags.VALUE1.first_value_nick, 'value1') self.assertEqual(GIMarshallingTests.Flags.VALUE2.first_value_nick, 'value2') self.assertEqual(GIMarshallingTests.Flags.VALUE3.first_value_nick, 'value3') self.assertEqual(GIMarshallingTests.Flags.VALUE1.first_value_name, 'GI_MARSHALLING_TESTS_FLAGS_VALUE1') self.assertEqual(GIMarshallingTests.Flags.VALUE2.first_value_name, 'GI_MARSHALLING_TESTS_FLAGS_VALUE2') self.assertEqual(GIMarshallingTests.Flags.VALUE3.first_value_name, 'GI_MARSHALLING_TESTS_FLAGS_VALUE3') def test_flags_in(self): GIMarshallingTests.flags_in(GIMarshallingTests.Flags.VALUE2) GIMarshallingTests.Flags.in_(GIMarshallingTests.Flags.VALUE2) # result of __or__() operation should still be valid instance, not an int. GIMarshallingTests.flags_in(GIMarshallingTests.Flags.VALUE2 | GIMarshallingTests.Flags.VALUE2) GIMarshallingTests.flags_in_zero(Number(0)) GIMarshallingTests.Flags.in_zero(Number(0)) self.assertRaises(TypeError, GIMarshallingTests.flags_in, 1 << 1) self.assertRaises(TypeError, GIMarshallingTests.flags_in, 'GIMarshallingTests.Flags.VALUE2') def test_flags_return(self): flags = GIMarshallingTests.flags_returnv() self.assertTrue(isinstance(flags, GIMarshallingTests.Flags)) self.assertEqual(flags, GIMarshallingTests.Flags.VALUE2) def test_flags_return_method(self): flags = GIMarshallingTests.Flags.returnv() self.assertTrue(isinstance(flags, GIMarshallingTests.Flags)) self.assertEqual(flags, GIMarshallingTests.Flags.VALUE2) def test_flags_out(self): flags = GIMarshallingTests.flags_out() self.assertTrue(isinstance(flags, GIMarshallingTests.Flags)) self.assertEqual(flags, GIMarshallingTests.Flags.VALUE2) def test_flags_inout(self): flags = GIMarshallingTests.flags_inout(GIMarshallingTests.Flags.VALUE2) self.assertTrue(isinstance(flags, GIMarshallingTests.Flags)) self.assertEqual(flags, GIMarshallingTests.Flags.VALUE1) def test_type_module_name(self): self.assertEqual(GIMarshallingTests.Flags.__name__, "Flags") self.assertEqual(GIMarshallingTests.Flags.__module__, "gi.repository.GIMarshallingTests") def test_repr(self): self.assertEqual(repr(GIMarshallingTests.Flags.VALUE2), "") def test_hash(self): assert (hash(GIMarshallingTests.Flags.VALUE2) == hash(GIMarshallingTests.Flags(GIMarshallingTests.Flags.VALUE2))) def test_flags_large_in(self): GIMarshallingTests.extra_flags_large_in( GIMarshallingTests.ExtraFlags.VALUE2) class TestNoTypeFlags(unittest.TestCase): def test_flags(self): self.assertTrue(issubclass(GIMarshallingTests.NoTypeFlags, GObject.GFlags)) self.assertTrue(isinstance(GIMarshallingTests.NoTypeFlags.VALUE1, GIMarshallingTests.NoTypeFlags)) self.assertTrue(isinstance(GIMarshallingTests.NoTypeFlags.VALUE2, GIMarshallingTests.NoTypeFlags)) self.assertTrue(isinstance(GIMarshallingTests.NoTypeFlags.VALUE3, GIMarshallingTests.NoTypeFlags)) # __or__() operation should still return an instance, not an int. self.assertTrue(isinstance(GIMarshallingTests.NoTypeFlags.VALUE1 | GIMarshallingTests.NoTypeFlags.VALUE2, GIMarshallingTests.NoTypeFlags)) self.assertEqual(1 << 1, GIMarshallingTests.NoTypeFlags.VALUE2) def test_value_nick_and_name(self): self.assertEqual(GIMarshallingTests.NoTypeFlags.VALUE1.first_value_nick, 'value1') self.assertEqual(GIMarshallingTests.NoTypeFlags.VALUE2.first_value_nick, 'value2') self.assertEqual(GIMarshallingTests.NoTypeFlags.VALUE3.first_value_nick, 'value3') self.assertEqual(GIMarshallingTests.NoTypeFlags.VALUE1.first_value_name, 'GI_MARSHALLING_TESTS_NO_TYPE_FLAGS_VALUE1') self.assertEqual(GIMarshallingTests.NoTypeFlags.VALUE2.first_value_name, 'GI_MARSHALLING_TESTS_NO_TYPE_FLAGS_VALUE2') self.assertEqual(GIMarshallingTests.NoTypeFlags.VALUE3.first_value_name, 'GI_MARSHALLING_TESTS_NO_TYPE_FLAGS_VALUE3') def test_flags_in(self): GIMarshallingTests.no_type_flags_in(GIMarshallingTests.NoTypeFlags.VALUE2) GIMarshallingTests.no_type_flags_in(GIMarshallingTests.NoTypeFlags.VALUE2 | GIMarshallingTests.NoTypeFlags.VALUE2) GIMarshallingTests.no_type_flags_in_zero(Number(0)) self.assertRaises(TypeError, GIMarshallingTests.no_type_flags_in, 1 << 1) self.assertRaises(TypeError, GIMarshallingTests.no_type_flags_in, 'GIMarshallingTests.NoTypeFlags.VALUE2') def test_flags_return(self): flags = GIMarshallingTests.no_type_flags_returnv() self.assertTrue(isinstance(flags, GIMarshallingTests.NoTypeFlags)) self.assertEqual(flags, GIMarshallingTests.NoTypeFlags.VALUE2) def test_flags_out(self): flags = GIMarshallingTests.no_type_flags_out() self.assertTrue(isinstance(flags, GIMarshallingTests.NoTypeFlags)) self.assertEqual(flags, GIMarshallingTests.NoTypeFlags.VALUE2) def test_flags_inout(self): flags = GIMarshallingTests.no_type_flags_inout(GIMarshallingTests.NoTypeFlags.VALUE2) self.assertTrue(isinstance(flags, GIMarshallingTests.NoTypeFlags)) self.assertEqual(flags, GIMarshallingTests.NoTypeFlags.VALUE1) def test_flags_gtype_name_is_namespaced(self): self.assertEqual(GIMarshallingTests.NoTypeFlags.__gtype__.name, 'PyGIMarshallingTestsNoTypeFlags') def test_type_module_name(self): self.assertEqual(GIMarshallingTests.NoTypeFlags.__name__, "NoTypeFlags") self.assertEqual(GIMarshallingTests.NoTypeFlags.__module__, "gi.repository.GIMarshallingTests") def test_repr(self): self.assertEqual(repr(GIMarshallingTests.NoTypeFlags.VALUE2), "") class TestStructure(unittest.TestCase): def test_simple_struct(self): self.assertTrue(issubclass(GIMarshallingTests.SimpleStruct, GObject.GPointer)) struct = GIMarshallingTests.SimpleStruct() self.assertTrue(isinstance(struct, GIMarshallingTests.SimpleStruct)) self.assertEqual(0, struct.long_) self.assertEqual(0, struct.int8) struct.long_ = 6 struct.int8 = 7 self.assertEqual(6, struct.long_) self.assertEqual(7, struct.int8) del struct def test_nested_struct(self): struct = GIMarshallingTests.NestedStruct() self.assertTrue(isinstance(struct.simple_struct, GIMarshallingTests.SimpleStruct)) struct.simple_struct.long_ = 42 self.assertEqual(42, struct.simple_struct.long_) del struct def test_not_simple_struct(self): struct = GIMarshallingTests.NotSimpleStruct() self.assertEqual(None, struct.pointer) def test_simple_struct_return(self): struct = GIMarshallingTests.simple_struct_returnv() self.assertTrue(isinstance(struct, GIMarshallingTests.SimpleStruct)) self.assertEqual(6, struct.long_) self.assertEqual(7, struct.int8) del struct def test_simple_struct_in(self): struct = GIMarshallingTests.SimpleStruct() struct.long_ = 6 struct.int8 = 7 GIMarshallingTests.SimpleStruct.inv(struct) del struct struct = GIMarshallingTests.NestedStruct() self.assertRaises(TypeError, GIMarshallingTests.SimpleStruct.inv, struct) del struct self.assertRaises(TypeError, GIMarshallingTests.SimpleStruct.inv, None) def test_simple_struct_method(self): struct = GIMarshallingTests.SimpleStruct() struct.long_ = 6 struct.int8 = 7 struct.method() del struct self.assertRaises(TypeError, GIMarshallingTests.SimpleStruct.method) def test_pointer_struct(self): self.assertTrue(issubclass(GIMarshallingTests.PointerStruct, GObject.GPointer)) struct = GIMarshallingTests.PointerStruct() self.assertTrue(isinstance(struct, GIMarshallingTests.PointerStruct)) del struct def test_pointer_struct_return(self): struct = GIMarshallingTests.pointer_struct_returnv() self.assertTrue(isinstance(struct, GIMarshallingTests.PointerStruct)) self.assertEqual(42, struct.long_) del struct def test_pointer_struct_in(self): struct = GIMarshallingTests.PointerStruct() struct.long_ = 42 struct.inv() del struct def test_boxed_struct(self): self.assertTrue(issubclass(GIMarshallingTests.BoxedStruct, GObject.GBoxed)) struct = GIMarshallingTests.BoxedStruct() self.assertTrue(isinstance(struct, GIMarshallingTests.BoxedStruct)) self.assertEqual(0, struct.long_) self.assertEqual(None, struct.string_) self.assertEqual([], struct.g_strv) del struct def test_boxed_struct_new(self): struct = GIMarshallingTests.BoxedStruct.new() self.assertTrue(isinstance(struct, GIMarshallingTests.BoxedStruct)) self.assertEqual(struct.long_, 0) self.assertEqual(struct.string_, None) del struct def test_boxed_struct_copy(self): struct = GIMarshallingTests.BoxedStruct() struct.long_ = 42 struct.string_ = 'hello' new_struct = struct.copy() self.assertTrue(isinstance(new_struct, GIMarshallingTests.BoxedStruct)) self.assertEqual(new_struct.long_, 42) self.assertEqual(new_struct.string_, 'hello') del new_struct del struct def test_boxed_struct_return(self): struct = GIMarshallingTests.boxed_struct_returnv() self.assertTrue(isinstance(struct, GIMarshallingTests.BoxedStruct)) self.assertEqual(42, struct.long_) self.assertEqual('hello', struct.string_) self.assertEqual(['0', '1', '2'], struct.g_strv) del struct def test_boxed_struct_in(self): struct = GIMarshallingTests.BoxedStruct() struct.long_ = 42 struct.inv() del struct def test_boxed_struct_out(self): struct = GIMarshallingTests.boxed_struct_out() self.assertTrue(isinstance(struct, GIMarshallingTests.BoxedStruct)) self.assertEqual(42, struct.long_) del struct def test_boxed_struct_inout(self): in_struct = GIMarshallingTests.BoxedStruct() in_struct.long_ = 42 out_struct = GIMarshallingTests.boxed_struct_inout(in_struct) self.assertTrue(isinstance(out_struct, GIMarshallingTests.BoxedStruct)) self.assertEqual(0, out_struct.long_) del in_struct del out_struct def test_struct_field_assignment(self): struct = GIMarshallingTests.BoxedStruct() struct.long_ = 42 struct.string_ = 'hello' self.assertEqual(struct.long_, 42) self.assertEqual(struct.string_, 'hello') def test_union_init(self): with warnings.catch_warnings(record=True) as warn: warnings.simplefilter('always') GIMarshallingTests.Union(42) self.assertTrue(issubclass(warn[0].category, DeprecationWarning)) with warnings.catch_warnings(record=True) as warn: warnings.simplefilter('always') GIMarshallingTests.Union(f=42) self.assertTrue(issubclass(warn[0].category, DeprecationWarning)) def test_union(self): union = GIMarshallingTests.Union() self.assertTrue(isinstance(union, GIMarshallingTests.Union)) new_union = union.copy() self.assertTrue(isinstance(new_union, GIMarshallingTests.Union)) del union del new_union def test_union_return(self): union = GIMarshallingTests.union_returnv() self.assertTrue(isinstance(union, GIMarshallingTests.Union)) self.assertEqual(42, union.long_) del union def test_union_in(self): union = GIMarshallingTests.Union() union.long_ = 42 union.inv() del union def test_union_method(self): union = GIMarshallingTests.Union() union.long_ = 42 union.method() del union self.assertRaises(TypeError, GIMarshallingTests.Union.method) def test_repr(self): self.assertRegex( repr(GIMarshallingTests.PointerStruct()), r"") self.assertRegex( repr(GIMarshallingTests.SimpleStruct()), r"") self.assertRegex( repr(GIMarshallingTests.Union()), r"") self.assertRegex( repr(GIMarshallingTests.BoxedStruct()), r"") class TestGObject(unittest.TestCase): def test_object(self): self.assertTrue(issubclass(GIMarshallingTests.Object, GObject.GObject)) object_ = GIMarshallingTests.Object() self.assertTrue(isinstance(object_, GIMarshallingTests.Object)) self.assertEqual(object_.__grefcount__, 1) def test_object_new(self): object_ = GIMarshallingTests.Object.new(42) self.assertTrue(isinstance(object_, GIMarshallingTests.Object)) self.assertEqual(object_.__grefcount__, 1) def test_object_int(self): object_ = GIMarshallingTests.Object(int=42) self.assertEqual(object_.int_, 42) # FIXME: Don't work yet. # object_.int_ = 0 # self.assertEqual(object_.int_, 0) def test_object_static_method(self): GIMarshallingTests.Object.static_method() def test_object_method(self): GIMarshallingTests.Object(int=42).method() self.assertRaises(TypeError, GIMarshallingTests.Object.method, GObject.GObject()) self.assertRaises(TypeError, GIMarshallingTests.Object.method) def test_sub_object(self): self.assertTrue(issubclass(GIMarshallingTests.SubObject, GIMarshallingTests.Object)) object_ = GIMarshallingTests.SubObject() self.assertTrue(isinstance(object_, GIMarshallingTests.SubObject)) def test_sub_object_new(self): self.assertRaises(TypeError, GIMarshallingTests.SubObject.new, 42) def test_sub_object_static_method(self): object_ = GIMarshallingTests.SubObject() object_.static_method() def test_sub_object_method(self): object_ = GIMarshallingTests.SubObject(int=42) object_.method() def test_sub_object_sub_method(self): object_ = GIMarshallingTests.SubObject() object_.sub_method() def test_sub_object_overwritten_method(self): object_ = GIMarshallingTests.SubObject() object_.overwritten_method() self.assertRaises(TypeError, GIMarshallingTests.SubObject.overwritten_method, GIMarshallingTests.Object()) def test_sub_object_int(self): object_ = GIMarshallingTests.SubObject() self.assertEqual(object_.int_, 0) # FIXME: Don't work yet. # object_.int_ = 42 # self.assertEqual(object_.int_, 42) def test_object_none_return(self): object_ = GIMarshallingTests.Object.none_return() self.assertTrue(isinstance(object_, GIMarshallingTests.Object)) self.assertEqual(object_.__grefcount__, 2) def test_object_full_return(self): object_ = GIMarshallingTests.Object.full_return() self.assertTrue(isinstance(object_, GIMarshallingTests.Object)) self.assertEqual(object_.__grefcount__, 1) def test_object_none_in(self): object_ = GIMarshallingTests.Object(int=42) GIMarshallingTests.Object.none_in(object_) self.assertEqual(object_.__grefcount__, 1) object_ = GIMarshallingTests.SubObject(int=42) GIMarshallingTests.Object.none_in(object_) object_ = GObject.GObject() self.assertRaises(TypeError, GIMarshallingTests.Object.none_in, object_) self.assertRaises(TypeError, GIMarshallingTests.Object.none_in, None) def test_object_none_out(self): object_ = GIMarshallingTests.Object.none_out() self.assertTrue(isinstance(object_, GIMarshallingTests.Object)) self.assertEqual(object_.__grefcount__, 2) new_object = GIMarshallingTests.Object.none_out() self.assertTrue(new_object is object_) def test_object_full_out(self): object_ = GIMarshallingTests.Object.full_out() self.assertTrue(isinstance(object_, GIMarshallingTests.Object)) self.assertEqual(object_.__grefcount__, 1) def test_object_none_inout(self): object_ = GIMarshallingTests.Object(int=42) new_object = GIMarshallingTests.Object.none_inout(object_) self.assertTrue(isinstance(new_object, GIMarshallingTests.Object)) self.assertFalse(object_ is new_object) self.assertEqual(object_.__grefcount__, 1) self.assertEqual(new_object.__grefcount__, 2) new_new_object = GIMarshallingTests.Object.none_inout(object_) self.assertTrue(new_new_object is new_object) GIMarshallingTests.Object.none_inout(GIMarshallingTests.SubObject(int=42)) def test_object_full_inout(self): # Using gimarshallingtests.c from GI versions > 1.38.0 will show this # test as an "unexpected success" due to reference leak fixes in that file. # TODO: remove the expectedFailure once PyGI relies on GI > 1.38.0. object_ = GIMarshallingTests.Object(int=42) new_object = GIMarshallingTests.Object.full_inout(object_) self.assertTrue(isinstance(new_object, GIMarshallingTests.Object)) self.assertFalse(object_ is new_object) self.assertEqual(object_.__grefcount__, 1) self.assertEqual(new_object.__grefcount__, 1) def test_repr(self): self.assertRegex( repr(GIMarshallingTests.Object(int=42)), r"") def test_nongir_repr(self): self.assertRegex( repr(Gio.File.new_for_path("/")), r"<__gi__.GLocalFile object at 0x[^\s]+ " r"\(GLocalFile at 0x[^\s]+\)>") # FIXME: Doesn't actually return the same object. # def test_object_inout_same(self): # object_ = GIMarshallingTests.Object() # new_object = GIMarshallingTests.object_full_inout(object_) # self.assertTrue(object_ is new_object) # self.assertEqual(object_.__grefcount__, 1) class TestPythonGObject(unittest.TestCase): class Object(GIMarshallingTests.Object): return_for_caller_allocated_out_parameter = 'test caller alloc return' def __init__(self, int): GIMarshallingTests.Object.__init__(self) self.val = None def method(self): # Don't call super, which asserts that self.int == 42. pass def do_method_int8_in(self, int8): self.val = int8 def do_method_int8_out(self): return 42 def do_method_int8_arg_and_out_caller(self, arg): return arg + 1 def do_method_int8_arg_and_out_callee(self, arg): return arg + 1 def do_method_str_arg_out_ret(self, arg): return (arg.upper(), len(arg)) def do_method_with_default_implementation(self, int8): GIMarshallingTests.Object.do_method_with_default_implementation(self, int8) self.props.int += int8 def do_vfunc_return_value_only(self): return 4242 def do_vfunc_one_out_parameter(self): return 42.42 def do_vfunc_multiple_out_parameters(self): return (42.42, 3.14) def do_vfunc_return_value_and_one_out_parameter(self): return (5, 42) def do_vfunc_return_value_and_multiple_out_parameters(self): return (5, 42, 99) def do_vfunc_caller_allocated_out_parameter(self): return self.return_for_caller_allocated_out_parameter class SubObject(GIMarshallingTests.SubObject): def __init__(self, int): GIMarshallingTests.SubObject.__init__(self) self.val = None def do_method_with_default_implementation(self, int8): self.val = int8 def do_vfunc_return_value_only(self): return 2121 class Interface3Impl(GObject.Object, GIMarshallingTests.Interface3): def __init__(self): GObject.Object.__init__(self) self.variants = None self.n_variants = None def do_test_variant_array_in(self, variants, n_variants): self.variants = variants self.n_variants = n_variants class ErrorObject(GIMarshallingTests.Object): def do_vfunc_return_value_only(self): raise ValueError('Return value should be 0') def test_object(self): self.assertTrue(issubclass(self.Object, GIMarshallingTests.Object)) object_ = self.Object(int=42) self.assertTrue(isinstance(object_, self.Object)) @unittest.skipUnless(hasattr(GIMarshallingTests.Object, 'new_fail'), 'Requires newer version of GI') def test_object_fail(self): with self.assertRaises(GLib.Error): GIMarshallingTests.Object.new_fail(int_=42) def test_object_method(self): self.Object(int=0).method() def test_object_vfuncs(self): object_ = self.Object(int=42) object_.method_int8_in(84) self.assertEqual(object_.val, 84) self.assertEqual(object_.method_int8_out(), 42) # can be dropped when bumping g-i dependencies to >= 1.35.2 if hasattr(object_, 'method_int8_arg_and_out_caller'): self.assertEqual(object_.method_int8_arg_and_out_caller(42), 43) self.assertEqual(object_.method_int8_arg_and_out_callee(42), 43) self.assertEqual(object_.method_str_arg_out_ret('hello'), ('HELLO', 5)) object_.method_with_default_implementation(42) self.assertEqual(object_.props.int, 84) self.assertEqual(object_.vfunc_return_value_only(), 4242) self.assertAlmostEqual(object_.vfunc_one_out_parameter(), 42.42, places=5) (a, b) = object_.vfunc_multiple_out_parameters() self.assertAlmostEqual(a, 42.42, places=5) self.assertAlmostEqual(b, 3.14, places=5) self.assertEqual(object_.vfunc_return_value_and_one_out_parameter(), (5, 42)) self.assertEqual(object_.vfunc_return_value_and_multiple_out_parameters(), (5, 42, 99)) self.assertEqual(object_.vfunc_caller_allocated_out_parameter(), object_.return_for_caller_allocated_out_parameter) class ObjectWithoutVFunc(GIMarshallingTests.Object): def __init__(self, int): GIMarshallingTests.Object.__init__(self) object_ = ObjectWithoutVFunc(int=42) object_.method_with_default_implementation(84) self.assertEqual(object_.props.int, 84) @unittest.skipUnless(hasattr(sys, "getrefcount"), "no sys.getrefcount") def test_vfunc_return_ref_count(self): obj = self.Object(int=42) ref_count = sys.getrefcount(obj.return_for_caller_allocated_out_parameter) ret = obj.vfunc_caller_allocated_out_parameter() gc.collect() # Make sure the return and what the vfunc returned # are equal but not the same object. self.assertEqual(ret, obj.return_for_caller_allocated_out_parameter) self.assertFalse(ret is obj.return_for_caller_allocated_out_parameter) self.assertEqual(sys.getrefcount(obj.return_for_caller_allocated_out_parameter), ref_count) def test_vfunc_return_no_ref_count(self): obj = self.Object(int=42) ret = obj.vfunc_caller_allocated_out_parameter() self.assertEqual(ret, obj.return_for_caller_allocated_out_parameter) self.assertFalse(ret is obj.return_for_caller_allocated_out_parameter) def test_subobject_parent_vfunc(self): object_ = self.SubObject(int=81) object_.method_with_default_implementation(87) self.assertEqual(object_.val, 87) def test_subobject_child_vfunc(self): object_ = self.SubObject(int=1) self.assertEqual(object_.vfunc_return_value_only(), 2121) def test_subobject_non_vfunc_do_method(self): class PythonObjectWithNonVFuncDoMethod(object): def do_not_a_vfunc(self): return 5 class ObjectOverrideNonVFuncDoMethod(GIMarshallingTests.Object, PythonObjectWithNonVFuncDoMethod): def do_not_a_vfunc(self): value = super(ObjectOverrideNonVFuncDoMethod, self).do_not_a_vfunc() return 13 + value object_ = ObjectOverrideNonVFuncDoMethod() self.assertEqual(18, object_.do_not_a_vfunc()) def test_native_function_not_set_in_subclass_dict(self): # Previously, GI was setting virtual functions on the class as well # as any *native* class that subclasses it. Here we check that it is only # set on the class that the method is originally from. self.assertTrue('do_method_with_default_implementation' in GIMarshallingTests.Object.__dict__) self.assertTrue('do_method_with_default_implementation' not in GIMarshallingTests.SubObject.__dict__) def test_subobject_with_interface_and_non_vfunc_do_method(self): # There was a bug for searching for vfuncs in interfaces. It was # triggered by having a do_* method that wasn't overriding # a native vfunc, as well as inheriting from an interface. class GObjectSubclassWithInterface(GObject.GObject, GIMarshallingTests.Interface): def do_method_not_a_vfunc(self): pass def test_subsubobject(self): class SubSubSubObject(GIMarshallingTests.SubSubObject): def do_method_deep_hierarchy(self, num): self.props.int = num * 2 sub_sub_sub_object = SubSubSubObject() GIMarshallingTests.SubSubObject.do_method_deep_hierarchy(sub_sub_sub_object, 5) self.assertEqual(sub_sub_sub_object.props.int, 5) def test_interface3impl(self): iface3 = self.Interface3Impl() variants = [GLib.Variant('i', 27), GLib.Variant('s', 'Hello')] iface3.test_variant_array_in(variants) self.assertEqual(iface3.n_variants, 2) self.assertEqual(iface3.variants[0].unpack(), 27) self.assertEqual(iface3.variants[1].unpack(), 'Hello') def test_python_subsubobject_vfunc(self): class PySubObject(GIMarshallingTests.Object): def __init__(self): GIMarshallingTests.Object.__init__(self) self.sub_method_int8_called = 0 def do_method_int8_in(self, int8): self.sub_method_int8_called += 1 class PySubSubObject(PySubObject): def __init__(self): PySubObject.__init__(self) self.subsub_method_int8_called = 0 def do_method_int8_in(self, int8): self.subsub_method_int8_called += 1 so = PySubObject() so.method_int8_in(1) self.assertEqual(so.sub_method_int8_called, 1) # it should call the method on the SubSub object only sso = PySubSubObject() sso.method_int8_in(1) self.assertEqual(sso.subsub_method_int8_called, 1) self.assertEqual(sso.sub_method_int8_called, 0) def test_callback_in_vfunc(self): class SubObject(GIMarshallingTests.Object): def __init__(self): GObject.GObject.__init__(self) self.worked = False def do_vfunc_with_callback(self, callback): self.worked = callback(42) == 42 _object = SubObject() _object.call_vfunc_with_callback() self.assertTrue(_object.worked) _object.worked = False _object.call_vfunc_with_callback() self.assertTrue(_object.worked) def test_exception_in_vfunc_return_value(self): obj = self.ErrorObject() with capture_exceptions() as exc: self.assertEqual(obj.vfunc_return_value_only(), 0) self.assertEqual(len(exc), 1) self.assertEqual(exc[0].type, ValueError) @unittest.skipUnless(hasattr(GIMarshallingTests, 'callback_owned_boxed'), 'requires newer version of GI') def test_callback_owned_box(self): def callback(box, data): self.box = box def nop_callback(box, data): pass GIMarshallingTests.callback_owned_boxed(callback, None) GIMarshallingTests.callback_owned_boxed(nop_callback, None) self.assertEqual(self.box.long_, 1) class TestMultiOutputArgs(unittest.TestCase): def test_int_out_out(self): self.assertEqual((6, 7), GIMarshallingTests.int_out_out()) def test_int_return_out(self): self.assertEqual((6, 7), GIMarshallingTests.int_return_out()) # Interface class TestInterfaces(unittest.TestCase): class TestInterfaceImpl(GObject.GObject, GIMarshallingTests.Interface): def __init__(self): GObject.GObject.__init__(self) self.val = None def do_test_int8_in(self, int8): self.val = int8 def setUp(self): self.instance = self.TestInterfaceImpl() def test_iface_impl(self): instance = GIMarshallingTests.InterfaceImpl() assert instance.get_as_interface() is instance instance.test_int8_in(42) def test_wrapper(self): self.assertTrue(issubclass(GIMarshallingTests.Interface, GObject.GInterface)) self.assertEqual(GIMarshallingTests.Interface.__gtype__.name, 'GIMarshallingTestsInterface') self.assertRaises(NotImplementedError, GIMarshallingTests.Interface) def test_implementation(self): self.assertTrue(issubclass(self.TestInterfaceImpl, GIMarshallingTests.Interface)) self.assertTrue(isinstance(self.instance, GIMarshallingTests.Interface)) def test_int8_int(self): GIMarshallingTests.test_interface_test_int8_in(self.instance, 42) self.assertEqual(self.instance.val, 42) def test_subclass(self): class TestInterfaceImplA(self.TestInterfaceImpl): pass class TestInterfaceImplB(TestInterfaceImplA): pass instance = TestInterfaceImplA() GIMarshallingTests.test_interface_test_int8_in(instance, 42) self.assertEqual(instance.val, 42) def test_subclass_override(self): class TestInterfaceImplD(TestInterfaces.TestInterfaceImpl): val2 = None def do_test_int8_in(self, int8): self.val2 = int8 instance = TestInterfaceImplD() self.assertEqual(instance.val, None) self.assertEqual(instance.val2, None) GIMarshallingTests.test_interface_test_int8_in(instance, 42) self.assertEqual(instance.val, None) self.assertEqual(instance.val2, 42) def test_type_mismatch(self): obj = GIMarshallingTests.Object() # wrong type for first argument: interface enum = Gio.File.new_for_path('.').enumerate_children( '', Gio.FileQueryInfoFlags.NONE, None) try: enum.next_file(obj) self.fail('call with wrong type argument unexpectedly succeeded') except TypeError as e: # should have argument name self.assertTrue('cancellable' in str(e), e) # should have expected type self.assertTrue('xpected Gio.Cancellable' in str(e), e) # should have actual type self.assertTrue('GIMarshallingTests.Object' in str(e), e) # wrong type for self argument: interface try: Gio.FileEnumerator.next_file(obj, None) self.fail('call with wrong type argument unexpectedly succeeded') except TypeError as e: # should have argument name self.assertTrue('self' in str(e), e) # should have expected type self.assertTrue('xpected Gio.FileEnumerator' in str(e), e) # should have actual type self.assertTrue('GIMarshallingTests.Object' in str(e), e) # wrong type for first argument: GObject var = GLib.Variant('s', 'mystring') action = Gio.SimpleAction.new('foo', var.get_type()) try: action.activate(obj) self.fail('call with wrong type argument unexpectedly succeeded') except TypeError as e: # should have argument name self.assertTrue('parameter' in str(e), e) # should have expected type self.assertTrue('xpected GLib.Variant' in str(e), e) # should have actual type self.assertTrue('GIMarshallingTests.Object' in str(e), e) # wrong type for self argument: GObject try: Gio.SimpleAction.activate(obj, obj) self.fail('call with wrong type argument unexpectedly succeeded') except TypeError as e: # should have argument name self.assertTrue('self' in str(e), e) # should have expected type self.assertTrue('xpected Gio.Action' in str(e), e) # should have actual type self.assertTrue('GIMarshallingTests.Object' in str(e), e) class TestMRO(unittest.TestCase): def test_mro(self): # check that our own MRO calculation matches what we would expect # from Python's own C3 calculations class A(object): pass class B(A): pass class C(A): pass class D(B, C): pass class E(D, GIMarshallingTests.Object): pass expected = (E, D, B, C, A, GIMarshallingTests.Object, GObject.Object, GObject.Object.__base__, gi._gi.GObject, object) self.assertEqual(expected, E.__mro__) def test_interface_collision(self): # there was a problem with Python bailing out because of # http://en.wikipedia.org/wiki/Diamond_problem with interfaces, # which shouldn't really be a problem. class TestInterfaceImpl(GObject.GObject, GIMarshallingTests.Interface): pass class TestInterfaceImpl2(GIMarshallingTests.Interface, TestInterfaceImpl): pass class TestInterfaceImpl3(TestInterfaceImpl, GIMarshallingTests.Interface2): pass def test_old_style_mixin(self): # Note: Old style classes don't exist in Python 3 class Mixin: pass with warnings.catch_warnings(record=True) as warn: warnings.simplefilter('always') # Dynamically create a new gi based class with an old # style mixin. type('GIWithOldStyleMixin', (GIMarshallingTests.Object, Mixin), {}) self.assertEqual(len(warn), 0) class TestInterfaceClash(unittest.TestCase): def test_clash(self): def create_clash(): class TestClash(GObject.GObject, GIMarshallingTests.Interface, GIMarshallingTests.Interface2): def do_test_int8_in(self, int8): pass TestClash() self.assertRaises(TypeError, create_clash) class TestOverrides(unittest.TestCase): def test_constant(self): self.assertEqual(GIMarshallingTests.OVERRIDES_CONSTANT, 7) def test_struct(self): # Test that the constructor has been overridden. struct = GIMarshallingTests.OverridesStruct(42) self.assertTrue(isinstance(struct, GIMarshallingTests.OverridesStruct)) # Test that the method has been overridden. self.assertEqual(6, struct.method()) del struct # Test that the overrides wrapper has been registered. struct = GIMarshallingTests.overrides_struct_returnv() self.assertTrue(isinstance(struct, GIMarshallingTests.OverridesStruct)) del struct def test_object(self): # Test that the constructor has been overridden. object_ = GIMarshallingTests.OverridesObject(42) self.assertTrue(isinstance(object_, GIMarshallingTests.OverridesObject)) # Test that the alternate constructor has been overridden. object_ = GIMarshallingTests.OverridesObject.new(42) self.assertTrue(isinstance(object_, GIMarshallingTests.OverridesObject)) # Test that the method has been overridden. self.assertEqual(6, object_.method()) # Test that the overrides wrapper has been registered. object_ = GIMarshallingTests.OverridesObject.returnv() self.assertTrue(isinstance(object_, GIMarshallingTests.OverridesObject)) def test_module_name(self): # overridden types self.assertEqual(GIMarshallingTests.OverridesStruct.__module__, 'gi.overrides.GIMarshallingTests') self.assertEqual(GIMarshallingTests.OverridesObject.__module__, 'gi.overrides.GIMarshallingTests') self.assertEqual(GObject.Object.__module__, 'gi.overrides.GObject') # not overridden self.assertEqual(GIMarshallingTests.SubObject.__module__, 'gi.repository.GIMarshallingTests') self.assertEqual(GObject.InitiallyUnowned.__module__, 'gi.repository.GObject') class TestDir(unittest.TestCase): def test_members_list(self): list = dir(GIMarshallingTests) self.assertTrue('OverridesStruct' in list) self.assertTrue('BoxedStruct' in list) self.assertTrue('OVERRIDES_CONSTANT' in list) self.assertTrue('GEnum' in list) self.assertTrue('int32_return_max' in list) def test_modules_list(self): import gi.repository list = dir(gi.repository) self.assertTrue('GIMarshallingTests' in list) # FIXME: test to see if a module which was not imported is in the list # we should be listing every typelib we find, not just the ones # which are imported # # to test this I recommend we compile a fake module which # our tests would never import and check to see if it is # in the list: # # self.assertTrue('DoNotImportDummyTests' in list) class TestParamSpec(unittest.TestCase): def test_param_spec_in_bool(self): ps = GObject.param_spec_boolean('mybool', 'test-bool', 'boolblurb', True, GObject.ParamFlags.READABLE) GIMarshallingTests.param_spec_in_bool(ps) def test_param_spec_return(self): obj = GIMarshallingTests.param_spec_return() self.assertEqual(obj.name, 'test-param') self.assertEqual(obj.nick, 'test') self.assertEqual(obj.value_type, GObject.TYPE_STRING) def test_param_spec_out(self): obj = GIMarshallingTests.param_spec_out() self.assertEqual(obj.name, 'test-param') self.assertEqual(obj.nick, 'test') self.assertEqual(obj.value_type, GObject.TYPE_STRING) class TestKeywordArgs(unittest.TestCase): def test_calling(self): kw_func = GIMarshallingTests.int_three_in_three_out self.assertEqual(kw_func(1, 2, 3), (1, 2, 3)) self.assertEqual(kw_func(**{'a': 4, 'b': 5, 'c': 6}), (4, 5, 6)) self.assertEqual(kw_func(1, **{'b': 7, 'c': 8}), (1, 7, 8)) self.assertEqual(kw_func(1, 7, **{'c': 8}), (1, 7, 8)) self.assertEqual(kw_func(1, c=8, **{'b': 7}), (1, 7, 8)) self.assertEqual(kw_func(2, c=4, b=3), (2, 3, 4)) self.assertEqual(kw_func(a=2, c=4, b=3), (2, 3, 4)) def assertRaisesMessage(self, exception, message, func, *args, **kwargs): try: func(*args, **kwargs) except exception: (e_type, e) = sys.exc_info()[:2] if message is not None: self.assertEqual(str(e), message) except: raise else: msg = "%s() did not raise %s" % (func.__name__, exception.__name__) raise AssertionError(msg) def test_type_errors(self): # test too few args self.assertRaisesMessage(TypeError, "GIMarshallingTests.int_three_in_three_out() takes exactly 3 arguments (0 given)", GIMarshallingTests.int_three_in_three_out) self.assertRaisesMessage(TypeError, "GIMarshallingTests.int_three_in_three_out() takes exactly 3 arguments (1 given)", GIMarshallingTests.int_three_in_three_out, 1) self.assertRaisesMessage(TypeError, "GIMarshallingTests.int_three_in_three_out() takes exactly 3 arguments (0 given)", GIMarshallingTests.int_three_in_three_out, *()) self.assertRaisesMessage(TypeError, "GIMarshallingTests.int_three_in_three_out() takes exactly 3 arguments (0 given)", GIMarshallingTests.int_three_in_three_out, *(), **{}) self.assertRaisesMessage(TypeError, "GIMarshallingTests.int_three_in_three_out() takes exactly 3 non-keyword arguments (0 given)", GIMarshallingTests.int_three_in_three_out, *(), **{'c': 4}) # test too many args self.assertRaisesMessage(TypeError, "GIMarshallingTests.int_three_in_three_out() takes exactly 3 arguments (4 given)", GIMarshallingTests.int_three_in_three_out, *(1, 2, 3, 4)) self.assertRaisesMessage(TypeError, "GIMarshallingTests.int_three_in_three_out() takes exactly 3 non-keyword arguments (4 given)", GIMarshallingTests.int_three_in_three_out, *(1, 2, 3, 4), c=6) # test too many keyword args self.assertRaisesMessage(TypeError, "GIMarshallingTests.int_three_in_three_out() got multiple values for keyword argument 'a'", GIMarshallingTests.int_three_in_three_out, 1, 2, 3, **{'a': 4, 'b': 5}) self.assertRaisesMessage(TypeError, "GIMarshallingTests.int_three_in_three_out() got an unexpected keyword argument 'd'", GIMarshallingTests.int_three_in_three_out, d=4) self.assertRaisesMessage(TypeError, "GIMarshallingTests.int_three_in_three_out() got an unexpected keyword argument 'e'", GIMarshallingTests.int_three_in_three_out, **{'e': 2}) def test_kwargs_are_not_modified(self): d = {'b': 2} d2 = d.copy() GIMarshallingTests.int_three_in_three_out(1, c=4, **d) self.assertEqual(d, d2) @unittest.skipUnless(hasattr(GIMarshallingTests, 'int_one_in_utf8_two_in_one_allows_none'), 'Requires newer GIMarshallingTests') def test_allow_none_as_default(self): GIMarshallingTests.int_two_in_utf8_two_in_with_allow_none(1, 2, '3', '4') GIMarshallingTests.int_two_in_utf8_two_in_with_allow_none(1, 2, '3') GIMarshallingTests.int_two_in_utf8_two_in_with_allow_none(1, 2) GIMarshallingTests.int_two_in_utf8_two_in_with_allow_none(1, 2, d='4') GIMarshallingTests.array_in_utf8_two_in_out_of_order('1', [-1, 0, 1, 2]) GIMarshallingTests.array_in_utf8_two_in_out_of_order('1', [-1, 0, 1, 2], '2') self.assertRaises(TypeError, GIMarshallingTests.array_in_utf8_two_in_out_of_order, [-1, 0, 1, 2], a='1') self.assertRaises(TypeError, GIMarshallingTests.array_in_utf8_two_in_out_of_order, [-1, 0, 1, 2]) GIMarshallingTests.array_in_utf8_two_in([-1, 0, 1, 2], '1', '2') GIMarshallingTests.array_in_utf8_two_in([-1, 0, 1, 2], '1') GIMarshallingTests.array_in_utf8_two_in([-1, 0, 1, 2]) GIMarshallingTests.array_in_utf8_two_in([-1, 0, 1, 2], b='2') GIMarshallingTests.int_one_in_utf8_two_in_one_allows_none(1, '2', '3') self.assertRaises(TypeError, GIMarshallingTests.int_one_in_utf8_two_in_one_allows_none, 1, '3') self.assertRaises(TypeError, GIMarshallingTests.int_one_in_utf8_two_in_one_allows_none, 1, c='3') class TestKeywords(unittest.TestCase): def test_method(self): # g_variant_print() v = GLib.Variant('i', 1) self.assertEqual(v.print_(False), '1') def test_function(self): # g_thread_yield() self.assertEqual(GLib.Thread.yield_(), None) def test_struct_method(self): # g_timer_continue() # we cannot currently instantiate GLib.Timer objects, so just ensure # the method exists self.assertTrue(callable(GLib.Timer.continue_)) def test_uppercase(self): self.assertEqual(GLib.IOCondition.IN.value_nicks, ['in']) class TestModule(unittest.TestCase): def test_path(self): path = GIMarshallingTests.__path__ assert isinstance(path, list) assert len(path) == 1 assert path[0].endswith('GIMarshallingTests-1.0.typelib') def test_str(self): self.assertTrue("'GIMarshallingTests' from '" in str(GIMarshallingTests), str(GIMarshallingTests)) def test_dir(self): _dir = dir(GIMarshallingTests) self.assertGreater(len(_dir), 10) self.assertTrue('SimpleStruct' in _dir) self.assertTrue('Interface2' in _dir) self.assertTrue('CONSTANT_GERROR_CODE' in _dir) self.assertTrue('array_zero_terminated_inout' in _dir) # assert that dir() does not contain garbage for item_name in _dir: item = getattr(GIMarshallingTests, item_name) self.assertTrue(hasattr(item, '__class__')) def test_help(self): with capture_output() as (stdout, stderr): help(GIMarshallingTests) output = stdout.getvalue() self.assertTrue('SimpleStruct' in output, output) self.assertTrue('Interface2' in output, output) self.assertTrue('method_array_inout' in output, output) class TestProjectVersion(unittest.TestCase): def test_version_str(self): self.assertGreater(gi.__version__, "3.") def test_version_info(self): self.assertEqual(len(gi.version_info), 3) self.assertGreaterEqual(gi.version_info, (3, 3, 5)) def test_check_version(self): self.assertRaises(ValueError, gi.check_version, (99, 0, 0)) self.assertRaises(ValueError, gi.check_version, "99.0.0") gi.check_version((3, 3, 5)) gi.check_version("3.3.5") class TestGIWarning(unittest.TestCase): def test_warning(self): ignored_by_default = (DeprecationWarning, PendingDeprecationWarning, ImportWarning) with warnings.catch_warnings(record=True) as warn: warnings.simplefilter('always') warnings.warn("test", PyGIWarning) self.assertTrue(issubclass(warn[0].category, Warning)) # We don't want PyGIWarning get ignored by default self.assertFalse(issubclass(warn[0].category, ignored_by_default)) class TestDeprecation(unittest.TestCase): def test_method(self): d = GLib.Date.new() with warnings.catch_warnings(record=True) as warn: warnings.simplefilter('always') d.set_time(1) self.assertTrue(issubclass(warn[0].category, DeprecationWarning)) self.assertEqual(str(warn[0].message), "GLib.Date.set_time is deprecated") def test_function(self): with warnings.catch_warnings(record=True) as warn: warnings.simplefilter('always') GLib.strcasecmp("foo", "bar") self.assertTrue(issubclass(warn[0].category, DeprecationWarning)) self.assertEqual(str(warn[0].message), "GLib.strcasecmp is deprecated") def test_deprecated_attribute_compat(self): # test if the deprecation descriptor behaves like an instance attribute # save the descriptor desc = type(GLib).__dict__["IO_STATUS_ERROR"] # the descriptor raises AttributeError for itself self.assertFalse(hasattr(type(GLib), "IO_STATUS_ERROR")) with warnings.catch_warnings(): warnings.simplefilter('ignore', PyGIDeprecationWarning) self.assertTrue(hasattr(GLib, "IO_STATUS_ERROR")) try: # check if replacing works GLib.IO_STATUS_ERROR = "foo" self.assertEqual(GLib.IO_STATUS_ERROR, "foo") finally: # restore descriptor try: del GLib.IO_STATUS_ERROR except AttributeError: pass setattr(type(GLib), "IO_STATUS_ERROR", desc) try: # check if deleting works del GLib.IO_STATUS_ERROR self.assertFalse(hasattr(GLib, "IO_STATUS_ERROR")) finally: # restore descriptor try: del GLib.IO_STATUS_ERROR except AttributeError: pass setattr(type(GLib), "IO_STATUS_ERROR", desc) def test_deprecated_attribute_warning(self): with warnings.catch_warnings(record=True) as warn: warnings.simplefilter('always') self.assertEqual(GLib.IO_STATUS_ERROR, GLib.IOStatus.ERROR) GLib.IO_STATUS_ERROR GLib.IO_STATUS_ERROR self.assertEqual(len(warn), 3) self.assertTrue( issubclass(warn[0].category, PyGIDeprecationWarning)) self.assertRegex( str(warn[0].message), ".*GLib.IO_STATUS_ERROR.*GLib.IOStatus.ERROR.*") def test_deprecated_attribute_warning_coverage(self): with warnings.catch_warnings(record=True) as warn: warnings.simplefilter('always') GObject.markup_escape_text GObject.PRIORITY_DEFAULT GObject.GError GObject.PARAM_CONSTRUCT GObject.SIGNAL_ACTION GObject.property GObject.IO_STATUS_ERROR GObject.G_MAXUINT64 GLib.IO_STATUS_ERROR GLib.SPAWN_SEARCH_PATH GLib.OPTION_FLAG_HIDDEN GLib.IO_FLAG_IS_WRITEABLE GLib.IO_FLAG_NONBLOCK GLib.USER_DIRECTORY_DESKTOP GLib.OPTION_ERROR_BAD_VALUE GLib.glib_version GLib.pyglib_version self.assertEqual(len(warn), 17) def test_deprecated_init_no_keywords(self): def init(self, **kwargs): self.assertDictEqual(kwargs, {'a': 1, 'b': 2, 'c': 3}) fn = gi.overrides.deprecated_init(init, arg_names=('a', 'b', 'c')) with warnings.catch_warnings(record=True) as warn: warnings.simplefilter('always') fn(self, 1, 2, 3) self.assertEqual(len(warn), 1) self.assertTrue(issubclass(warn[0].category, PyGIDeprecationWarning)) self.assertRegex(str(warn[0].message), '.*keyword.*a, b, c.*') def test_deprecated_init_no_keywords_out_of_order(self): def init(self, **kwargs): self.assertDictEqual(kwargs, {'a': 1, 'b': 2, 'c': 3}) fn = gi.overrides.deprecated_init(init, arg_names=('b', 'a', 'c')) with warnings.catch_warnings(record=True) as warn: warnings.simplefilter('always') fn(self, 2, 1, 3) self.assertEqual(len(warn), 1) self.assertTrue(issubclass(warn[0].category, PyGIDeprecationWarning)) self.assertRegex(str(warn[0].message), '.*keyword.*b, a, c.*') def test_deprecated_init_ignored_keyword(self): def init(self, **kwargs): self.assertDictEqual(kwargs, {'a': 1, 'c': 3}) fn = gi.overrides.deprecated_init(init, arg_names=('a', 'b', 'c'), ignore=('b',)) with warnings.catch_warnings(record=True) as warn: warnings.simplefilter('always') fn(self, 1, 2, 3) self.assertEqual(len(warn), 1) self.assertTrue(issubclass(warn[0].category, PyGIDeprecationWarning)) self.assertRegex(str(warn[0].message), '.*keyword.*a, b, c.*') def test_deprecated_init_with_aliases(self): def init(self, **kwargs): self.assertDictEqual(kwargs, {'a': 1, 'b': 2, 'c': 3}) fn = gi.overrides.deprecated_init(init, arg_names=('a', 'b', 'c'), deprecated_aliases={'b': 'bb', 'c': 'cc'}) with warnings.catch_warnings(record=True) as warn: warnings.simplefilter('always') fn(self, a=1, bb=2, cc=3) self.assertEqual(len(warn), 1) self.assertTrue(issubclass(warn[0].category, PyGIDeprecationWarning)) self.assertRegex(str(warn[0].message), '.*keyword.*"bb, cc".*deprecated.*"b, c" respectively') def test_deprecated_init_with_defaults(self): def init(self, **kwargs): self.assertDictEqual(kwargs, {'a': 1, 'b': 2, 'c': 3}) fn = gi.overrides.deprecated_init(init, arg_names=('a', 'b', 'c'), deprecated_defaults={'b': 2, 'c': 3}) with warnings.catch_warnings(record=True) as warn: warnings.simplefilter('always') fn(self, a=1) self.assertEqual(len(warn), 1) self.assertTrue(issubclass(warn[0].category, PyGIDeprecationWarning)) self.assertRegex(str(warn[0].message), '.*relying on deprecated non-standard defaults.*' 'explicitly use: b=2, c=3') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/tests/test_gio.py0000664000000000000000000005713615074674453015713 0ustar00rootroot# -*- Mode: Python; py-indent-offset: 4 -*- # vim: tabstop=4 shiftwidth=4 expandtab import contextlib import os import unittest import warnings import pytest import gi.overrides from gi import PyGIWarning, PyGIDeprecationWarning from gi.repository import GLib, Gio GioUnix = None with contextlib.suppress(ImportError): from gi.repository import GioUnix from .helper import ignore_gi_deprecation_warnings class TestGio(unittest.TestCase): def test_file_enumerator(self): self.assertEqual(Gio.FileEnumerator, gi.overrides.Gio.FileEnumerator) f = Gio.file_new_for_path("./") iter_info = [] for info in f.enumerate_children("standard::*", 0, None): iter_info.append(info.get_name()) next_info = [] enumerator = f.enumerate_children("standard::*", 0, None) while True: info = enumerator.next_file(None) if info is None: break next_info.append(info.get_name()) self.assertEqual(iter_info, next_info) def test_menu_item(self): menu = Gio.Menu() item = Gio.MenuItem() item.set_attribute([("label", "s", "Test"), ("action", "s", "app.test")]) menu.append_item(item) value = menu.get_item_attribute_value(0, "label", GLib.VariantType.new("s")) self.assertEqual("Test", value.unpack()) value = menu.get_item_attribute_value(0, "action", GLib.VariantType.new("s")) self.assertEqual("app.test", value.unpack()) def test_volume_monitor_warning(self): with warnings.catch_warnings(record=True) as warn: warnings.simplefilter('always') Gio.VolumeMonitor() self.assertEqual(len(warn), 1) self.assertTrue(issubclass(warn[0].category, PyGIWarning)) self.assertRegex( str(warn[0].message), ".*Gio\\.VolumeMonitor\\.get\\(\\).*" ) class TestGioPlatform(unittest.TestCase): desktopFileContent = f"""[Desktop Entry] Version=1.0 Type=Application Name=Some Application Exec={GLib.find_program_in_path("true")} %u Actions=act; Categories=Development;Profiling; GenericName=Test Hidden=true Keywords=test;example; NoDisplay=true OnlyShowIn=GNOME; StartupWMClass=testTest X-Bool=true [Desktop Action act] Name=Take action! Exec={GLib.find_program_in_path("true")} action """ def setUp(self): super().setUp() if (GLib.MAJOR_VERSION, GLib.MINOR_VERSION) < (2, 80): self.skipTest("Installed Gio is not new enough for this test") if GioUnix: self.key_file = GLib.KeyFile() self.key_file.load_from_data( self.desktopFileContent, len(self.desktopFileContent), GLib.KeyFileFlags.NONE, ) def assert_expected_desktop_app_info(self, app_info): # All functionality is available as ordinary methods, without # needing extraneous arguments # https://gitlab.gnome.org/GNOME/pygobject/-/issues/719 self.assertEqual(app_info.get_action_name("act"), "Take action!") self.assertEqual(app_info.get_boolean("X-Bool"), True) self.assertEqual(app_info.get_categories(), "Development;Profiling;") self.assertIsNone(app_info.get_filename()) self.assertEqual(app_info.get_generic_name(), "Test") self.assertEqual(app_info.get_is_hidden(), True) self.assertEqual(app_info.get_keywords(), ["test", "example"]) self.assertEqual(app_info.get_locale_string("Keywords"), "test;example;") self.assertEqual(app_info.get_nodisplay(), True) self.assertEqual(app_info.get_show_in("GNOME"), True) self.assertEqual(app_info.get_show_in("KDE"), False) # get_show_in() can be called without an argument, which means NULL self.assertIn(app_info.get_show_in(), [True, False]) self.assertIn(app_info.get_show_in(None), [True, False]) self.assertEqual(app_info.get_startup_wm_class(), "testTest") self.assertEqual(app_info.get_string("StartupWMClass"), "testTest") self.assertEqual(app_info.get_string_list("Keywords"), ["test", "example"]) self.assertEqual(app_info.has_key("Keywords"), True) self.assertEqual(app_info.list_actions(), ["act"]) # All functionality is also available via unbound methods: # for example Cinnamon relies on this as of October 2025 self.assertEqual( GioUnix.DesktopAppInfo.get_action_name(app_info, "act"), "Take action!" ) self.assertEqual( Gio.DesktopAppInfo.get_action_name(app_info, "act"), "Take action!" ) # Exercise methods that actually launch something app_info.launch_action("act") app_info.launch_action("act", None) self.assertTrue( app_info.launch_uris_as_manager( ["about:blank"], None, GLib.SpawnFlags.DEFAULT, None, None, None, None, ), ) self.assertTrue( app_info.launch_uris_as_manager( ["about:blank"], None, GLib.SpawnFlags.DEFAULT, ), ) self.assertTrue( app_info.launch_uris_as_manager_with_fds( ["about:blank"], None, GLib.SpawnFlags.DEFAULT, None, None, None, None, -1, -1, -1, ), ) @unittest.skipIf( GioUnix is None or "DesktopAppInfo" not in dir(GioUnix), "Not supported" ) def test_desktop_app_info_can_be_created_from_gio_unix(self): app_info = GioUnix.DesktopAppInfo.new_from_keyfile(self.key_file) self.assertIsNotNone(app_info) self.assertIsInstance(app_info, GioUnix.DesktopAppInfo) self.assertIsInstance(app_info, Gio.AppInfo) self.assert_expected_desktop_app_info(app_info) @unittest.skipIf( GioUnix is None or "DesktopAppInfo" not in dir(GioUnix), "Not supported" ) def test_desktop_app_info_can_be_created_from_gio(self): with warnings.catch_warnings(record=True) as warn: warnings.simplefilter("always") app_info = Gio.DesktopAppInfo.new_from_keyfile(self.key_file) if (GLib.MAJOR_VERSION, GLib.MINOR_VERSION) >= (2, 86): self.assertEqual(len(warn), 1) self.assertTrue(issubclass(warn[0].category, PyGIDeprecationWarning)) self.assertEqual( str(warn[0].message), "Gio.DesktopAppInfo is deprecated; " + "use GioUnix.DesktopAppInfo instead", ) self.assertIsNotNone(app_info) self.assertIsInstance(app_info, Gio.DesktopAppInfo) self.assertIsInstance(app_info, Gio.AppInfo) @unittest.skipIf( GioUnix is None or "FDMessage" not in dir(GioUnix), "Not supported" ) def test_fd_message(self): message = GioUnix.FDMessage.new() self.assertIsNotNone(message) with open("/dev/null", "r+b") as devnull: self.assertTrue(message.append_fd(devnull.fileno())) self.assertIsNotNone(message.get_fd_list()) fds = message.steal_fds() self.assertEqual(len(fds), 1) os.close(fds[0]) @unittest.skipIf( GioUnix is None or "DesktopAppInfo" not in dir(GioUnix), "Not supported" ) def test_gio_unix_desktop_app_info_provides_platform_independent_functions(self): app_info = GioUnix.DesktopAppInfo.new_from_keyfile(self.key_file) self.assertEqual(app_info.get_name(), "Some Application") @unittest.skipIf( GioUnix is None or "DesktopAppInfo" not in dir(GioUnix), "Not supported" ) @ignore_gi_deprecation_warnings def test_gio_desktop_app_info_provides_platform_independent_functions(self): app_info = Gio.DesktopAppInfo.new_from_keyfile(self.key_file) self.assertEqual(app_info.get_name(), "Some Application") @unittest.skipIf( GioUnix is None or "DesktopAppInfo" not in dir(GioUnix), "Not supported" ) def test_gio_unix_desktop_app_info_provides_unix_only_functions(self): app_info = GioUnix.DesktopAppInfo.new_from_keyfile(self.key_file) self.assertTrue(app_info.has_key("Name")) self.assertEqual(app_info.get_string("Name"), "Some Application") @unittest.skipIf( GioUnix is None or "DesktopAppInfo" not in dir(GioUnix), "Not supported" ) @ignore_gi_deprecation_warnings def test_gio_desktop_app_info_provides_unix_only_functions(self): app_info = Gio.DesktopAppInfo.new_from_keyfile(self.key_file) self.assertTrue(app_info.has_key("Name")) self.assertEqual(app_info.get_string("Name"), "Some Application") @unittest.skipIf(GioUnix is None, "Not supported") def test_deprecated_unix_function_can_be_called_from_gio(self): with warnings.catch_warnings(record=True) as warn: warnings.simplefilter("always") mount_points = Gio.unix_mount_points_get() if (GLib.MAJOR_VERSION, GLib.MINOR_VERSION) >= (2, 86): self.assertEqual(len(warn), 1) self.assertTrue(issubclass(warn[0].category, PyGIDeprecationWarning)) self.assertEqual( str(warn[0].message), "Gio.unix_mount_points_get is deprecated; " + "use GioUnix.mount_points_get instead", ) self.assertIsNotNone(mount_points) if (GLib.MAJOR_VERSION, GLib.MINOR_VERSION) >= (2, 86): self.assertEqual(GioUnix.mount_points_get, Gio.unix_mount_points_get) def assert_expected_unix_stream_type(self, stream_type): with open("/dev/null", "r+b") as devnull: stream = stream_type.new(devnull.fileno(), False) self.assertIsNotNone(stream) self.assertEqual(stream.get_close_fd(), False) stream.set_close_fd(False) self.assertNotEqual(stream.get_fd(), -1) @unittest.skipIf(GioUnix is None, "Not supported") def test_deprecated_unix_type_can_be_used_if_equal_exists_in_gio(self): with warnings.catch_warnings(record=True) as warn: warnings.simplefilter("always") input_stream = Gio.UnixInputStream if (GLib.MAJOR_VERSION, GLib.MINOR_VERSION) >= (2, 86): self.assertEqual(len(warn), 1) self.assertTrue(issubclass(warn[0].category, PyGIDeprecationWarning)) self.assertEqual( str(warn[0].message), "Gio.UnixInputStream is deprecated; " + "use GioUnix.InputStream instead", ) self.assertIsNotNone(input_stream) self.assertEqual(Gio.UnixInputStream, GioUnix.InputStream) self.assertNotEqual(Gio.InputStream, GioUnix.InputStream) self.assert_expected_unix_stream_type(Gio.UnixInputStream) self.assert_expected_unix_stream_type(GioUnix.InputStream) self.assert_expected_unix_stream_type(Gio.UnixOutputStream) self.assert_expected_unix_stream_type(GioUnix.OutputStream) @unittest.skipIf(GioUnix is None, "Not supported") def test_deprecated_unix_class_can_be_used_from_gio(self): with warnings.catch_warnings(record=True) as warn: warnings.simplefilter("always") monitor = Gio.UnixMountMonitor.get() if (GLib.MAJOR_VERSION, GLib.MINOR_VERSION) >= (2, 86): self.assertEqual(len(warn), 1) self.assertTrue(issubclass(warn[0].category, PyGIDeprecationWarning)) self.assertEqual( str(warn[0].message), "Gio.UnixMountMonitor is deprecated; " + "use GioUnix.MountMonitor instead", ) self.assertIsNotNone(monitor) self.assertEqual(Gio.UnixMountMonitor.get, GioUnix.MountMonitor.get) @unittest.skipIf(GioUnix is None, "Not supported") def test_deprecated_unix_gobject_class_can_be_used_from_gio(self): with warnings.catch_warnings(record=True) as warn: warnings.simplefilter("always") input_stream_class = Gio.UnixInputStreamClass if (GLib.MAJOR_VERSION, GLib.MINOR_VERSION) >= (2, 86): self.assertEqual(len(warn), 1) self.assertTrue(issubclass(warn[0].category, PyGIDeprecationWarning)) self.assertEqual( str(warn[0].message), "Gio.UnixInputStreamClass is deprecated; " + "use GioUnix.InputStreamClass instead", ) self.assertIsNotNone(input_stream_class) if (GLib.MAJOR_VERSION, GLib.MINOR_VERSION) >= (2, 86): self.assertEqual(Gio.UnixInputStreamClass, GioUnix.InputStreamClass) self.assertNotEqual(Gio.InputStreamClass, GioUnix.InputStreamClass) class TestGSettings(unittest.TestCase): def setUp(self): self.settings = Gio.Settings.new('org.gnome.test') # we change the values in the tests, so set them to predictable start # value self.settings.reset('test-string') self.settings.reset('test-array') self.settings.reset('test-boolean') self.settings.reset('test-enum') def test_iter(self): assert set(list(self.settings)) == set([ 'test-tuple', 'test-array', 'test-boolean', 'test-string', 'test-enum', 'test-range']) def test_get_set(self): for key in self.settings: old_value = self.settings[key] self.settings[key] = old_value assert self.settings[key] == old_value def test_native(self): self.assertTrue('test-array' in self.settings.list_keys()) # get various types v = self.settings.get_value('test-boolean') self.assertEqual(v.get_boolean(), True) self.assertEqual(self.settings.get_boolean('test-boolean'), True) v = self.settings.get_value('test-string') self.assertEqual(v.get_string(), 'Hello') self.assertEqual(self.settings.get_string('test-string'), 'Hello') v = self.settings.get_value('test-array') self.assertEqual(v.unpack(), [1, 2]) v = self.settings.get_value('test-tuple') self.assertEqual(v.unpack(), (1, 2)) v = self.settings.get_value('test-range') assert v.unpack() == 123 # set a value self.settings.set_string('test-string', 'World') self.assertEqual(self.settings.get_string('test-string'), 'World') self.settings.set_value('test-string', GLib.Variant('s', 'Goodbye')) self.assertEqual(self.settings.get_string('test-string'), 'Goodbye') def test_constructor(self): # default constructor uses path from schema self.assertEqual(self.settings.get_property('path'), '/tests/') # optional constructor arguments with_path = Gio.Settings.new_with_path('org.gnome.nopathtest', '/mypath/') self.assertEqual(with_path.get_property('path'), '/mypath/') self.assertEqual(with_path['np-int'], 42) def test_dictionary_api(self): self.assertEqual(len(self.settings), 6) self.assertTrue('test-array' in self.settings) self.assertTrue('test-array' in self.settings.keys()) self.assertFalse('nonexisting' in self.settings) self.assertFalse(4 in self.settings) self.assertEqual(bool(self.settings), True) def test_get(self): self.assertEqual(self.settings['test-boolean'], True) self.assertEqual(self.settings['test-string'], 'Hello') self.assertEqual(self.settings['test-enum'], 'banana') self.assertEqual(self.settings['test-array'], [1, 2]) self.assertEqual(self.settings['test-tuple'], (1, 2)) self.assertRaises(KeyError, self.settings.__getitem__, 'unknown') self.assertRaises(KeyError, self.settings.__getitem__, 2) def test_set(self): self.settings['test-boolean'] = False self.assertEqual(self.settings['test-boolean'], False) self.settings['test-string'] = 'Goodbye' self.assertEqual(self.settings['test-string'], 'Goodbye') self.settings['test-array'] = [3, 4, 5] self.assertEqual(self.settings['test-array'], [3, 4, 5]) self.settings['test-enum'] = 'pear' self.assertEqual(self.settings['test-enum'], 'pear') self.assertRaises(TypeError, self.settings.__setitem__, 'test-string', 1) self.assertRaises(ValueError, self.settings.__setitem__, 'test-enum', 'plum') self.assertRaises(KeyError, self.settings.__setitem__, 'unknown', 'moo') def test_set_range(self): self.settings['test-range'] = 7 assert self.settings['test-range'] == 7 self.settings['test-range'] = 65535 assert self.settings['test-range'] == 65535 with pytest.raises(ValueError, match=".*7 - 65535.*"): self.settings['test-range'] = 7 - 1 with pytest.raises(ValueError, match=".*7 - 65535.*"): self.settings['test-range'] = 65535 + 1 def test_empty(self): empty = Gio.Settings.new_with_path('org.gnome.empty', '/tests/') self.assertEqual(len(empty), 0) self.assertEqual(bool(empty), True) self.assertEqual(empty.keys(), []) @ignore_gi_deprecation_warnings def test_change_event(self): changed_log = [] change_event_log = [] def on_changed(settings, key): changed_log.append((settings, key)) def on_change_event(settings, keys, n_keys): change_event_log.append((settings, keys, n_keys)) self.settings.connect('changed', on_changed) self.settings.connect('change-event', on_change_event) self.settings['test-string'] = 'Moo' self.assertEqual(changed_log, [(self.settings, 'test-string')]) self.assertEqual(change_event_log, [(self.settings, [GLib.quark_from_static_string('test-string')], 1)]) @unittest.skipIf(os.name == "nt", "FIXME") class TestGFile(unittest.TestCase): def setUp(self): self.file, self.io_stream = Gio.File.new_tmp('TestGFile.XXXXXX') def tearDown(self): try: self.file.delete(None) # test_delete and test_delete_async already remove it except GLib.GError: pass def test_replace_contents(self): content = b'hello\0world\x7F!' succ, etag = self.file.replace_contents(content, None, False, Gio.FileCreateFlags.NONE, None) new_succ, new_content, new_etag = self.file.load_contents(None) self.assertTrue(succ) self.assertTrue(new_succ) self.assertEqual(etag, new_etag) self.assertEqual(content, new_content) # https://bugzilla.gnome.org/show_bug.cgi?id=690525 def disabled_test_replace_contents_async(self): content = b''.join(bytes(chr(i), 'utf-8') for i in range(128)) def callback(f, result, d): # Quit so in case of failed assertations loop doesn't keep running. main_loop.quit() succ, etag = self.file.replace_contents_finish(result) new_succ, new_content, new_etag = self.file.load_contents(None) d['succ'], d['etag'] = self.file.replace_contents_finish(result) load = self.file.load_contents(None) d['new_succ'], d['new_content'], d['new_etag'] = load data = {} self.file.replace_contents_async(content, None, False, Gio.FileCreateFlags.NONE, None, callback, data) main_loop = GLib.MainLoop() main_loop.run() self.assertTrue(data['succ']) self.assertTrue(data['new_succ']) self.assertEqual(data['etag'], data['new_etag']) self.assertEqual(content, data['new_content']) def test_tmp_exists(self): # A simple test to check if Gio.File.new_tmp is working correctly. self.assertTrue(self.file.query_exists(None)) def test_delete(self): self.file.delete(None) self.assertFalse(self.file.query_exists(None)) def test_delete_async(self): def callback(f, result, data): main_loop.quit() self.file.delete_async(0, None, callback, None) main_loop = GLib.MainLoop() main_loop.run() self.assertFalse(self.file.query_exists(None)) @unittest.skipIf(os.name == "nt", "crashes on Windows") class TestGApplication(unittest.TestCase): def test_command_line(self): class App(Gio.Application): args = None def __init__(self): super(App, self).__init__(flags=Gio.ApplicationFlags.HANDLES_COMMAND_LINE) def do_command_line(self, cmdline): self.args = cmdline.get_arguments() return 42 app = App() res = app.run(['spam', 'eggs']) self.assertEqual(res, 42) self.assertSequenceEqual(app.args, ['spam', 'eggs']) def test_local_command_line(self): class App(Gio.Application): local_args = None def __init__(self): super(App, self).__init__(flags=Gio.ApplicationFlags.HANDLES_COMMAND_LINE) def do_local_command_line(self, args): self.local_args = args[:] # copy args.remove('eggs') # True skips do_command_line being called. return True, args, 42 app = App() res = app.run(['spam', 'eggs']) self.assertEqual(res, 42) self.assertSequenceEqual(app.local_args, ['spam', 'eggs']) def test_local_and_remote_command_line(self): class App(Gio.Application): args = None local_args = None def __init__(self): super(App, self).__init__(flags=Gio.ApplicationFlags.HANDLES_COMMAND_LINE) def do_command_line(self, cmdline): self.args = cmdline.get_arguments() return 42 def do_local_command_line(self, args): self.local_args = args[:] # copy args.remove('eggs') # False causes do_command_line to be called with args. return False, args, 0 app = App() res = app.run(['spam', 'eggs']) self.assertEqual(res, 42) self.assertSequenceEqual(app.args, ['spam']) self.assertSequenceEqual(app.local_args, ['spam', 'eggs']) @unittest.skipUnless(hasattr(Gio.Application, 'add_main_option'), 'Requires newer version of GLib') def test_add_main_option(self): stored_options = [] def on_handle_local_options(app, options): stored_options.append(options) return 0 # Return 0 if options have been handled def on_activate(app): pass app = Gio.Application() app.add_main_option(long_name='string', short_name=b's', flags=0, arg=GLib.OptionArg.STRING, description='some string') app.connect('activate', on_activate) app.connect('handle-local-options', on_handle_local_options) app.run(['app', '-s', 'test string']) self.assertEqual(len(stored_options), 1) options = stored_options[0] self.assertTrue(options.contains('string')) self.assertEqual(options.lookup_value('string').unpack(), 'test string') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/tests/test_glib.py0000664000000000000000000002520415074674453016041 0ustar00rootroot# -*- Mode: Python -*- import os import sys import unittest import os.path import warnings import subprocess import pytest from gi.repository import GLib from gi import PyGIDeprecationWarning class TestGLib(unittest.TestCase): @pytest.mark.xfail() def test_pytest_capture_error_in_closure(self): # this test is supposed to fail ml = GLib.MainLoop() def callback(): ml.quit() raise Exception("expected") GLib.idle_add(callback) ml.run() @unittest.skipIf(os.name == "nt", "no bash on Windows") def test_find_program_in_path(self): bash_path = GLib.find_program_in_path('bash') self.assertTrue(bash_path.endswith(os.path.sep + 'bash')) self.assertTrue(os.path.exists(bash_path)) self.assertEqual(GLib.find_program_in_path('non existing'), None) def test_markup_escape_text(self): self.assertEqual(GLib.markup_escape_text(u'a&bä'), 'a&bä') self.assertEqual(GLib.markup_escape_text(b'a&b\x05'), 'a&b') # with explicit length argument self.assertEqual(GLib.markup_escape_text(b'a\x05\x01\x02', 2), 'a') def test_progname(self): GLib.set_prgname('moo') self.assertEqual(GLib.get_prgname(), 'moo') def test_appname(self): GLib.set_application_name('moo') self.assertEqual(GLib.get_application_name(), 'moo') def test_xdg_dirs(self): d = GLib.get_user_data_dir() self.assertTrue(os.path.sep in d, d) d = GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_DESKTOP) self.assertTrue(os.path.sep in d, d) with warnings.catch_warnings(): warnings.simplefilter('ignore', PyGIDeprecationWarning) # also works with backwards compatible enum names self.assertEqual(GLib.get_user_special_dir(GLib.UserDirectory.DIRECTORY_MUSIC), GLib.get_user_special_dir(GLib.USER_DIRECTORY_MUSIC)) for d in GLib.get_system_config_dirs(): self.assertTrue(os.path.sep in d, d) for d in GLib.get_system_data_dirs(): self.assertTrue(isinstance(d, str), d) def test_main_depth(self): self.assertEqual(GLib.main_depth(), 0) def test_filenames(self): self.assertEqual(GLib.filename_display_name('foo'), 'foo') self.assertEqual(GLib.filename_display_basename('bar/foo'), 'foo') def glibfsencode(f): # the annotations of filename_from_utf8() was changed in # https://bugzilla.gnome.org/show_bug.cgi?id=756128 if isinstance(f, bytes): return f if os.name == "nt": return f.encode("utf-8", "surrogatepass") else: return os.fsencode(f) # this is locale dependent, so we cannot completely verify the result res = GLib.filename_from_utf8(u'aäb') res = glibfsencode(res) self.assertTrue(isinstance(res, bytes)) self.assertGreaterEqual(len(res), 3) # with explicit length argument res = GLib.filename_from_utf8(u'aäb', 1) res = glibfsencode(res) self.assertEqual(res, b'a') def test_uri_extract(self): res = GLib.uri_list_extract_uris('''# some comment http://example.com https://my.org/q?x=1&y=2 http://gnome.org/new''') self.assertEqual(res, ['http://example.com', 'https://my.org/q?x=1&y=2', 'http://gnome.org/new']) def test_current_time(self): with warnings.catch_warnings(record=True) as warn: warnings.simplefilter('always') tm = GLib.get_current_time() self.assertTrue(issubclass(warn[0].category, PyGIDeprecationWarning)) self.assertTrue(isinstance(tm, float)) self.assertGreater(tm, 1350000000.0) @unittest.skipIf(sys.platform == "darwin", "fails on OSX") def test_main_loop(self): # note we do not test run() here, as we use this in countless other # tests ml = GLib.MainLoop() self.assertFalse(ml.is_running()) context = ml.get_context() self.assertEqual(context, GLib.MainContext.default()) self.assertTrue(context.is_owner() in [True, False]) self.assertTrue(context.pending() in [True, False]) self.assertFalse(context.iteration(False)) def test_main_loop_with_context(self): context = GLib.MainContext() ml = GLib.MainLoop(context) self.assertFalse(ml.is_running()) self.assertEqual(ml.get_context(), context) def test_main_context(self): # constructor context = GLib.MainContext() self.assertTrue(context.is_owner() in [True, False]) self.assertFalse(context.pending()) self.assertFalse(context.iteration(False)) # GLib API context = GLib.MainContext.default() self.assertTrue(context.is_owner() in [True, False]) self.assertTrue(context.pending() in [True, False]) self.assertTrue(context.iteration(False) in [True, False]) # backwards compatible API context = GLib.main_context_default() self.assertTrue(context.is_owner() in [True, False]) self.assertTrue(context.pending() in [True, False]) self.assertTrue(context.iteration(False) in [True, False]) @unittest.skipIf(os.name == "nt", "hangs") def test_io_add_watch_no_data(self): (r, w) = os.pipe() call_data = [] def cb(fd, condition): call_data.append((fd, condition, os.read(fd, 1))) if len(call_data) == 2: ml.quit() return True # io_add_watch() takes an IOChannel, calling with an fd is deprecated with warnings.catch_warnings(record=True) as warn: warnings.simplefilter('always') GLib.io_add_watch(r, GLib.IOCondition.IN, cb, priority=GLib.PRIORITY_HIGH) self.assertTrue(issubclass(warn[0].category, PyGIDeprecationWarning)) def write(): os.write(w, b'a') GLib.idle_add(lambda: os.write(w, b'b') and False) ml = GLib.MainLoop() GLib.idle_add(write) GLib.timeout_add(2000, ml.quit) ml.run() self.assertEqual(call_data, [(r, GLib.IOCondition.IN, b'a'), (r, GLib.IOCondition.IN, b'b')]) @unittest.skipIf(os.name == "nt", "hangs") def test_io_add_watch_with_data(self): (r, w) = os.pipe() call_data = [] def cb(fd, condition, data): call_data.append((fd, condition, os.read(fd, 1), data)) if len(call_data) == 2: ml.quit() return True # io_add_watch() takes an IOChannel, calling with an fd is deprecated with warnings.catch_warnings(record=True) as warn: warnings.simplefilter('always') GLib.io_add_watch(r, GLib.IOCondition.IN, cb, 'moo', priority=GLib.PRIORITY_HIGH) self.assertTrue(issubclass(warn[0].category, PyGIDeprecationWarning)) def write(): os.write(w, b'a') GLib.idle_add(lambda: os.write(w, b'b') and False) ml = GLib.MainLoop() GLib.idle_add(write) GLib.timeout_add(2000, ml.quit) ml.run() self.assertEqual(call_data, [(r, GLib.IOCondition.IN, b'a', 'moo'), (r, GLib.IOCondition.IN, b'b', 'moo')]) @unittest.skipIf(os.name == "nt", "hangs") def test_io_add_watch_with_multiple_data(self): (r, w) = os.pipe() call_data = [] def cb(fd, condition, *user_data): call_data.append((fd, condition, os.read(fd, 1), user_data)) ml.quit() return True # io_add_watch() takes an IOChannel, calling with an fd is deprecated with warnings.catch_warnings(record=True) as warn: warnings.simplefilter('always') GLib.io_add_watch(r, GLib.IOCondition.IN, cb, 'moo', 'foo') self.assertTrue(issubclass(warn[0].category, PyGIDeprecationWarning)) ml = GLib.MainLoop() GLib.idle_add(lambda: os.write(w, b'a') and False) GLib.timeout_add(2000, ml.quit) ml.run() self.assertEqual(call_data, [(r, GLib.IOCondition.IN, b'a', ('moo', 'foo'))]) @unittest.skipIf(sys.platform == "darwin", "fails") @unittest.skipIf(os.name == "nt", "no shell on Windows") def test_io_add_watch_pyfile(self): call_data = [] cmd = subprocess.Popen('echo hello; echo world', shell=True, bufsize=0, stdout=subprocess.PIPE) def cb(file, condition): call_data.append((file, condition, file.readline())) if len(call_data) == 2: # avoid having to wait for the full timeout ml.quit() return True # io_add_watch() takes an IOChannel, calling with a Python file is deprecated with warnings.catch_warnings(record=True) as warn: warnings.simplefilter('always') GLib.io_add_watch(cmd.stdout, GLib.IOCondition.IN, cb) self.assertTrue(issubclass(warn[0].category, PyGIDeprecationWarning)) ml = GLib.MainLoop() GLib.timeout_add(2000, ml.quit) ml.run() cmd.wait() self.assertEqual(call_data, [(cmd.stdout, GLib.IOCondition.IN, b'hello\n'), (cmd.stdout, GLib.IOCondition.IN, b'world\n')]) def test_glib_version(self): with warnings.catch_warnings(): warnings.simplefilter('ignore', PyGIDeprecationWarning) (major, minor, micro) = GLib.glib_version self.assertGreaterEqual(major, 2) self.assertGreaterEqual(minor, 0) self.assertGreaterEqual(micro, 0) def test_pyglib_version(self): with warnings.catch_warnings(): warnings.simplefilter('ignore', PyGIDeprecationWarning) (major, minor, micro) = GLib.pyglib_version self.assertGreaterEqual(major, 3) self.assertGreaterEqual(minor, 0) self.assertGreaterEqual(micro, 0) def test_timezone_constructor(self): with warnings.catch_warnings(): warnings.simplefilter('ignore', DeprecationWarning) timezone = GLib.TimeZone("+05:21") self.assertEqual(timezone.get_offset(0), ((5 * 60) + 21) * 60) def test_source_attach_implicit_context(self): context = GLib.MainContext.default() source = GLib.Idle() source_id = source.attach() self.assertEqual(context, source.get_context()) self.assertTrue(GLib.Source.remove(source_id)) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/tests/test_gobject.py0000664000000000000000000010166315074674453016545 0ustar00rootroot# -*- Mode: Python -*- import sys import gc import unittest import warnings import weakref import platform import pytest from gi.repository import GObject, GLib, Gio from gi import PyGIDeprecationWarning from gi.module import get_introspection_module from gi import _gi import testhelper from .helper import capture_glib_deprecation_warnings @pytest.mark.skipif(platform.python_implementation() == "PyPy", reason="crashes") def test_gobject_weak_ref(): called = [] def callback(*args): called.extend(args) # object gets finalized obj = GObject.Object() obj.weak_ref(callback, 1) del obj gc.collect() gc.collect() assert called == [1] del called[:] # wrapper gets finalized first obj = GObject.Object() pyref = weakref.ref(obj, lambda x: callback(-2)) value = GObject.Value(GObject.Object, obj) ref = obj.weak_ref(callback, 2) del obj gc.collect() assert called == [-2] del pyref value.unset() gc.collect() assert called == [-2, 2] del called[:] # weakref gets unregistered first obj = GObject.Object() ref = obj.weak_ref(callback, 3) ref.unref() del obj gc.collect() assert not called # weakref gets GCed obj = GObject.Object() obj.weak_ref(callback, 4) gc.collect() del obj assert called == [4] class TestGObjectAPI(unittest.TestCase): def test_run_dispose(self): class TestObject(GObject.GObject): int_prop = GObject.Property(default=0, type=int) obj = TestObject() called = [] def on_notify(*args): called.append(args) obj.connect('notify::int-prop', on_notify) obj.notify("int-prop") obj.notify("int-prop") # after this everything should be disconnected obj.run_dispose() obj.notify("int-prop") obj.notify("int-prop") assert len(called) == 2 def test_call_method_uninitialized_instance(self): obj = GObject.Object.__new__(GObject.Object) with self.assertRaisesRegex(RuntimeError, '.*is not initialized'): obj.notify("foo") def test_gobject_inheritance(self): # GObject.Object is a class hierarchy as follows: # overrides.Object -> introspection.Object -> static.GObject GIObjectModule = get_introspection_module('GObject') self.assertTrue(issubclass(GObject.Object, GIObjectModule.Object)) self.assertTrue(issubclass(GIObjectModule.Object, _gi.GObject)) self.assertEqual(_gi.GObject.__gtype__, GObject.TYPE_OBJECT) self.assertEqual(GIObjectModule.Object.__gtype__, GObject.TYPE_OBJECT) self.assertEqual(GObject.Object.__gtype__, GObject.TYPE_OBJECT) # The pytype wrapper should hold the outer most Object class from overrides. self.assertEqual(GObject.TYPE_OBJECT.pytype, GObject.Object) def test_gobject_unsupported_overrides(self): obj = GObject.Object() with self.assertRaisesRegex(RuntimeError, 'Data access methods are unsupported.*'): obj.get_data() with self.assertRaisesRegex(RuntimeError, 'This method is currently unsupported.*'): obj.force_floating() def test_compat_api(self): with warnings.catch_warnings(record=True) as w: warnings.simplefilter('always') # GObject formerly exposed a lot of GLib's functions self.assertEqual(GObject.markup_escape_text('foo'), 'foo') ml = GObject.MainLoop() self.assertFalse(ml.is_running()) context = GObject.main_context_default() self.assertTrue(context.pending() in [False, True]) context = GObject.MainContext() self.assertFalse(context.pending()) self.assertTrue(issubclass(w[0].category, PyGIDeprecationWarning)) self.assertTrue('GLib.markup_escape_text' in str(w[0]), str(w[0])) self.assertLess(GObject.PRIORITY_HIGH, GObject.PRIORITY_DEFAULT) def test_min_max_int(self): with warnings.catch_warnings(): warnings.simplefilter('ignore', PyGIDeprecationWarning) self.assertEqual(GObject.G_MAXINT16, 2 ** 15 - 1) self.assertEqual(GObject.G_MININT16, -2 ** 15) self.assertEqual(GObject.G_MAXUINT16, 2 ** 16 - 1) self.assertEqual(GObject.G_MAXINT32, 2 ** 31 - 1) self.assertEqual(GObject.G_MININT32, -2 ** 31) self.assertEqual(GObject.G_MAXUINT32, 2 ** 32 - 1) self.assertEqual(GObject.G_MAXINT64, 2 ** 63 - 1) self.assertEqual(GObject.G_MININT64, -2 ** 63) self.assertEqual(GObject.G_MAXUINT64, 2 ** 64 - 1) class TestReferenceCounting(unittest.TestCase): def test_regular_object(self): obj = GObject.GObject() self.assertEqual(obj.__grefcount__, 1) obj = GObject.new(GObject.GObject) self.assertEqual(obj.__grefcount__, 1) def test_floating(self): obj = testhelper.Floating() self.assertEqual(obj.__grefcount__, 1) obj = GObject.new(testhelper.Floating) self.assertEqual(obj.__grefcount__, 1) def test_owned_by_library(self): # Upon creation, the refcount of the object should be 2: # - someone already has a reference on the new object. # - the python wrapper should hold its own reference. obj = testhelper.OwnedByLibrary() self.assertEqual(obj.__grefcount__, 2) # We ask the library to release its reference, so the only # remaining ref should be our wrapper's. Once the wrapper # will run out of scope, the object will get finalized. obj.release() self.assertEqual(obj.__grefcount__, 1) def test_owned_by_library_out_of_scope(self): obj = testhelper.OwnedByLibrary() self.assertEqual(obj.__grefcount__, 2) # We are manually taking the object out of scope. This means # that our wrapper has been freed, and its reference dropped. We # cannot check it but the refcount should now be 1 (the ref held # by the library is still there, we didn't call release() obj = None # When we get the object back from the lib, the wrapper is # re-created, so our refcount will be 2 once again. obj = testhelper.owned_by_library_get_instance_list()[0] self.assertEqual(obj.__grefcount__, 2) obj.release() self.assertEqual(obj.__grefcount__, 1) def test_owned_by_library_using_gobject_new(self): # Upon creation, the refcount of the object should be 2: # - someone already has a reference on the new object. # - the python wrapper should hold its own reference. obj = GObject.new(testhelper.OwnedByLibrary) self.assertEqual(obj.__grefcount__, 2) # We ask the library to release its reference, so the only # remaining ref should be our wrapper's. Once the wrapper # will run out of scope, the object will get finalized. obj.release() self.assertEqual(obj.__grefcount__, 1) def test_owned_by_library_out_of_scope_using_gobject_new(self): obj = GObject.new(testhelper.OwnedByLibrary) self.assertEqual(obj.__grefcount__, 2) # We are manually taking the object out of scope. This means # that our wrapper has been freed, and its reference dropped. We # cannot check it but the refcount should now be 1 (the ref held # by the library is still there, we didn't call release() obj = None # When we get the object back from the lib, the wrapper is # re-created, so our refcount will be 2 once again. obj = testhelper.owned_by_library_get_instance_list()[0] self.assertEqual(obj.__grefcount__, 2) obj.release() self.assertEqual(obj.__grefcount__, 1) def test_floating_and_sunk(self): # Upon creation, the refcount of the object should be 2: # - someone already has a reference on the new object. # - the python wrapper should hold its own reference. obj = testhelper.FloatingAndSunk() self.assertEqual(obj.__grefcount__, 2) # We ask the library to release its reference, so the only # remaining ref should be our wrapper's. Once the wrapper # will run out of scope, the object will get finalized. obj.release() self.assertEqual(obj.__grefcount__, 1) def test_floating_and_sunk_out_of_scope(self): obj = testhelper.FloatingAndSunk() self.assertEqual(obj.__grefcount__, 2) # We are manually taking the object out of scope. This means # that our wrapper has been freed, and its reference dropped. We # cannot check it but the refcount should now be 1 (the ref held # by the library is still there, we didn't call release() obj = None # When we get the object back from the lib, the wrapper is # re-created, so our refcount will be 2 once again. obj = testhelper.floating_and_sunk_get_instance_list()[0] self.assertEqual(obj.__grefcount__, 2) obj.release() self.assertEqual(obj.__grefcount__, 1) def test_floating_and_sunk_using_gobject_new(self): # Upon creation, the refcount of the object should be 2: # - someone already has a reference on the new object. # - the python wrapper should hold its own reference. obj = GObject.new(testhelper.FloatingAndSunk) self.assertEqual(obj.__grefcount__, 2) # We ask the library to release its reference, so the only # remaining ref should be our wrapper's. Once the wrapper # will run out of scope, the object will get finalized. obj.release() self.assertEqual(obj.__grefcount__, 1) def test_floating_and_sunk_out_of_scope_using_gobject_new(self): obj = GObject.new(testhelper.FloatingAndSunk) self.assertEqual(obj.__grefcount__, 2) # We are manually taking the object out of scope. This means # that our wrapper has been freed, and its reference dropped. We # cannot check it but the refcount should now be 1 (the ref held # by the library is still there, we didn't call release() obj = None # When we get the object back from the lib, the wrapper is # re-created, so our refcount will be 2 once again. obj = testhelper.floating_and_sunk_get_instance_list()[0] self.assertEqual(obj.__grefcount__, 2) obj.release() self.assertEqual(obj.__grefcount__, 1) def test_uninitialized_object(self): class Obj(GObject.GObject): def __init__(self): x = self.__grefcount__ super(Obj, self).__init__() assert x >= 0 # quiesce pyflakes # Accessing __grefcount__ before the object is initialized is wrong. # Ensure we get a proper exception instead of a crash. self.assertRaises(TypeError, Obj) class A(GObject.GObject): def __init__(self): super(A, self).__init__() class TestPythonReferenceCounting(unittest.TestCase): # Newly created instances should alwayshave two references: one for # the GC, and one for the bound variable in the local scope. def test_new_instance_has_two_refs(self): obj = GObject.GObject() if hasattr(sys, "getrefcount"): self.assertEqual(sys.getrefcount(obj), 2) def test_new_instance_has_two_refs_using_gobject_new(self): obj = GObject.new(GObject.GObject) if hasattr(sys, "getrefcount"): self.assertEqual(sys.getrefcount(obj), 2) def test_new_subclass_instance_has_two_refs(self): obj = A() if hasattr(sys, "getrefcount"): self.assertEqual(sys.getrefcount(obj), 2) def test_new_subclass_instance_has_two_refs_using_gobject_new(self): obj = GObject.new(A) if hasattr(sys, "getrefcount"): self.assertEqual(sys.getrefcount(obj), 2) class TestContextManagers(unittest.TestCase): class ContextTestObject(GObject.GObject): prop = GObject.Property(default=0, type=int) def on_prop_set(self, obj, prop): # Handler which tracks property changed notifications. self.tracking.append(obj.get_property(prop.name)) def setUp(self): self.tracking = [] self.obj = self.ContextTestObject() self.handler = self.obj.connect('notify::prop', self.on_prop_set) def test_freeze_notify_context(self): # Verify prop tracking list self.assertEqual(self.tracking, []) self.obj.props.prop = 1 self.assertEqual(self.tracking, [1]) self.obj.props.prop = 2 self.assertEqual(self.tracking, [1, 2]) self.assertEqual(self.obj.__grefcount__, 1) if hasattr(sys, "getrefcount"): pyref_count = sys.getrefcount(self.obj) # Using the context manager the tracking list should not be affected. # The GObject reference count should stay the same and the python # object ref-count should go up. with self.obj.freeze_notify(): self.assertEqual(self.obj.__grefcount__, 1) if hasattr(sys, "getrefcount"): self.assertEqual(sys.getrefcount(self.obj), pyref_count + 1) self.obj.props.prop = 3 self.assertEqual(self.obj.props.prop, 3) self.assertEqual(self.tracking, [1, 2]) # After the context manager, the prop should have been modified, # the tracking list will be modified, and the python object ref # count goes back down. gc.collect() self.assertEqual(self.obj.props.prop, 3) self.assertEqual(self.tracking, [1, 2, 3]) self.assertEqual(self.obj.__grefcount__, 1) if hasattr(sys, "getrefcount"): self.assertEqual(sys.getrefcount(self.obj), pyref_count) def test_handler_block_context(self): # Verify prop tracking list self.assertEqual(self.tracking, []) self.obj.props.prop = 1 self.assertEqual(self.tracking, [1]) self.obj.props.prop = 2 self.assertEqual(self.tracking, [1, 2]) self.assertEqual(self.obj.__grefcount__, 1) if hasattr(sys, "getrefcount"): pyref_count = sys.getrefcount(self.obj) # Using the context manager the tracking list should not be affected. # The GObject reference count should stay the same and the python # object ref-count should go up. with self.obj.handler_block(self.handler): self.assertEqual(self.obj.__grefcount__, 1) if hasattr(sys, "getrefcount"): self.assertEqual(sys.getrefcount(self.obj), pyref_count + 1) self.obj.props.prop = 3 self.assertEqual(self.obj.props.prop, 3) self.assertEqual(self.tracking, [1, 2]) # After the context manager, the prop should have been modified # the tracking list should have stayed the same and the GObject ref # count goes back down. gc.collect() self.assertEqual(self.obj.props.prop, 3) self.assertEqual(self.tracking, [1, 2]) self.assertEqual(self.obj.__grefcount__, 1) if hasattr(sys, "getrefcount"): self.assertEqual(sys.getrefcount(self.obj), pyref_count) def test_freeze_notify_context_nested(self): self.assertEqual(self.tracking, []) with self.obj.freeze_notify(): self.obj.props.prop = 1 self.assertEqual(self.tracking, []) with self.obj.freeze_notify(): self.obj.props.prop = 2 self.assertEqual(self.tracking, []) with self.obj.freeze_notify(): self.obj.props.prop = 3 self.assertEqual(self.tracking, []) self.assertEqual(self.tracking, []) self.assertEqual(self.tracking, []) # Finally after last context, the notifications should have collapsed # and the last one sent. self.assertEqual(self.tracking, [3]) def test_handler_block_context_nested(self): self.assertEqual(self.tracking, []) with self.obj.handler_block(self.handler): self.obj.props.prop = 1 self.assertEqual(self.tracking, []) with self.obj.handler_block(self.handler): self.obj.props.prop = 2 self.assertEqual(self.tracking, []) with self.obj.handler_block(self.handler): self.obj.props.prop = 3 self.assertEqual(self.tracking, []) self.assertEqual(self.tracking, []) self.assertEqual(self.tracking, []) # Finally after last context, the notifications should have collapsed # and the last one sent. self.assertEqual(self.obj.props.prop, 3) self.assertEqual(self.tracking, []) def test_freeze_notify_normal_usage_ref_counts(self): # Ensure ref counts without using methods as context managers # maintain the same count. self.assertEqual(self.obj.__grefcount__, 1) self.obj.freeze_notify() self.assertEqual(self.obj.__grefcount__, 1) self.obj.thaw_notify() self.assertEqual(self.obj.__grefcount__, 1) def test_handler_block_normal_usage_ref_counts(self): self.assertEqual(self.obj.__grefcount__, 1) self.obj.handler_block(self.handler) self.assertEqual(self.obj.__grefcount__, 1) self.obj.handler_unblock(self.handler) self.assertEqual(self.obj.__grefcount__, 1) def test_freeze_notify_context_error(self): # Test an exception occurring within a freeze context exits the context try: with self.obj.freeze_notify(): self.obj.props.prop = 1 self.assertEqual(self.tracking, []) raise ValueError('Simulation') except ValueError: pass # Verify the property set within the context called notify. self.assertEqual(self.obj.props.prop, 1) self.assertEqual(self.tracking, [1]) # Verify we are still not in a frozen context. self.obj.props.prop = 2 self.assertEqual(self.tracking, [1, 2]) def test_handler_block_context_error(self): # Test an exception occurring within a handler block exits the context try: with self.obj.handler_block(self.handler): self.obj.props.prop = 1 self.assertEqual(self.tracking, []) raise ValueError('Simulation') except ValueError: pass # Verify the property set within the context didn't call notify. self.assertEqual(self.obj.props.prop, 1) self.assertEqual(self.tracking, []) # Verify we are still not in a handler block context. self.obj.props.prop = 2 self.assertEqual(self.tracking, [2]) @unittest.skipUnless(hasattr(GObject.Binding, 'unbind'), 'Requires newer GLib which has g_binding_unbind') class TestPropertyBindings(unittest.TestCase): class TestObject(GObject.GObject): int_prop = GObject.Property(default=0, type=int) def setUp(self): self.source = self.TestObject() self.target = self.TestObject() def test_default_binding(self): binding = self.source.bind_property('int_prop', self.target, 'int_prop', GObject.BindingFlags.DEFAULT) binding = binding # PyFlakes # Test setting value on source gets pushed to target self.source.int_prop = 1 self.assertEqual(self.source.int_prop, 1) self.assertEqual(self.target.int_prop, 1) # Test setting value on target does not change source self.target.props.int_prop = 2 self.assertEqual(self.source.int_prop, 1) self.assertEqual(self.target.int_prop, 2) def test_call_binding(self): binding = self.source.bind_property('int_prop', self.target, 'int_prop', GObject.BindingFlags.DEFAULT) with capture_glib_deprecation_warnings() as warn: result = binding() assert len(warn) assert result is binding def test_bidirectional_binding(self): binding = self.source.bind_property('int_prop', self.target, 'int_prop', GObject.BindingFlags.BIDIRECTIONAL) binding = binding # PyFlakes # Test setting value on source gets pushed to target self.source.int_prop = 1 self.assertEqual(self.source.int_prop, 1) self.assertEqual(self.target.int_prop, 1) # Test setting value on target also changes source self.target.props.int_prop = 2 self.assertEqual(self.source.int_prop, 2) self.assertEqual(self.target.int_prop, 2) def test_transform_to_only(self): def transform_to(binding, value, user_data=None): self.assertEqual(user_data, 'test-data') return value * 2 binding = self.source.bind_property('int_prop', self.target, 'int_prop', GObject.BindingFlags.DEFAULT, transform_to, user_data='test-data') binding = binding # PyFlakes self.source.int_prop = 1 self.assertEqual(self.source.int_prop, 1) self.assertEqual(self.target.int_prop, 2) self.target.props.int_prop = 1 self.assertEqual(self.source.int_prop, 1) self.assertEqual(self.target.int_prop, 1) def test_transform_from_only(self): def transform_from(binding, value, user_data=None): self.assertEqual(user_data, None) return value * 2 binding = self.source.bind_property('int_prop', self.target, 'int_prop', GObject.BindingFlags.BIDIRECTIONAL, transform_from=transform_from) binding = binding # PyFlakes self.source.int_prop = 1 self.assertEqual(self.source.int_prop, 1) self.assertEqual(self.target.int_prop, 1) self.target.props.int_prop = 1 self.assertEqual(self.source.int_prop, 2) self.assertEqual(self.target.int_prop, 1) def test_transform_bidirectional(self): test_data = object() def transform_to(binding, value, user_data=None): self.assertEqual(user_data, test_data) return value * 2 def transform_from(binding, value, user_data=None): self.assertEqual(user_data, test_data) return value // 2 if hasattr(sys, "getrefcount"): test_data_ref_count = sys.getrefcount(test_data) transform_to_ref_count = sys.getrefcount(transform_to) transform_from_ref_count = sys.getrefcount(transform_from) # bidirectional bindings binding = self.source.bind_property('int_prop', self.target, 'int_prop', GObject.BindingFlags.BIDIRECTIONAL, transform_to, transform_from, test_data) binding = binding # PyFlakes if hasattr(sys, "getrefcount"): binding_ref_count = sys.getrefcount(binding) binding_gref_count = binding.__grefcount__ self.source.int_prop = 1 self.assertEqual(self.source.int_prop, 1) self.assertEqual(self.target.int_prop, 2) self.target.props.int_prop = 4 self.assertEqual(self.source.int_prop, 2) self.assertEqual(self.target.int_prop, 4) if hasattr(sys, "getrefcount"): self.assertEqual(sys.getrefcount(binding), binding_ref_count) self.assertEqual(binding.__grefcount__, binding_gref_count) # test_data ref count increases by 2, once for each callback. if hasattr(sys, "getrefcount"): self.assertEqual(sys.getrefcount(test_data), test_data_ref_count + 2) self.assertEqual(sys.getrefcount(transform_to), transform_to_ref_count + 1) self.assertEqual(sys.getrefcount(transform_from), transform_from_ref_count + 1) # Unbind should clear out the binding and its transforms binding.unbind() # Setting source or target should not change the other. self.target.int_prop = 3 self.source.int_prop = 5 self.assertEqual(self.target.int_prop, 3) self.assertEqual(self.source.int_prop, 5) if hasattr(sys, "getrefcount"): self.assertEqual(sys.getrefcount(test_data), test_data_ref_count) self.assertEqual(sys.getrefcount(transform_to), transform_to_ref_count) self.assertEqual(sys.getrefcount(transform_from), transform_from_ref_count) def test_explicit_unbind_clears_connection(self): self.assertEqual(self.source.int_prop, 0) self.assertEqual(self.target.int_prop, 0) # Test deleting binding reference removes binding. binding = self.source.bind_property('int_prop', self.target, 'int_prop') self.source.int_prop = 1 self.assertEqual(self.source.int_prop, 1) self.assertEqual(self.target.int_prop, 1) # unbind should clear out the bindings self reference binding.unbind() self.assertEqual(binding.__grefcount__, 1) self.source.int_prop = 10 self.assertEqual(self.source.int_prop, 10) self.assertEqual(self.target.int_prop, 1) glib_version = (GLib.MAJOR_VERSION, GLib.MINOR_VERSION, GLib.MICRO_VERSION) # calling unbind() on an already unbound binding if glib_version >= (2, 57, 3): # Fixed in newer glib: # https://gitlab.gnome.org/GNOME/glib/merge_requests/244 for i in range(10): binding.unbind() else: self.assertRaises(ValueError, binding.unbind) def test_reference_counts(self): self.assertEqual(self.source.__grefcount__, 1) self.assertEqual(self.target.__grefcount__, 1) # Binding ref count will be 2 do to the initial ref implicitly held by # the act of binding and the ref incurred by using __call__ to generate # a wrapper from the weak binding ref within python. binding = self.source.bind_property('int_prop', self.target, 'int_prop') self.assertEqual(binding.__grefcount__, 2) # Creating a binding does not inc refs on source and target (they are weak # on the binding object itself) self.assertEqual(self.source.__grefcount__, 1) self.assertEqual(self.target.__grefcount__, 1) # Use GObject.get_property because the "props" accessor leaks. # Note property names are canonicalized. self.assertEqual(binding.get_property('source'), self.source) self.assertEqual(binding.get_property('source_property'), 'int-prop') self.assertEqual(binding.get_property('target'), self.target) self.assertEqual(binding.get_property('target_property'), 'int-prop') self.assertEqual(binding.get_property('flags'), GObject.BindingFlags.DEFAULT) # Delete reference to source or target and the binding will remove its own # "self reference". ref = self.source.weak_ref() del self.source gc.collect() self.assertEqual(ref(), None) self.assertEqual(binding.__grefcount__, 1) # Finally clear out the last ref held by the python wrapper ref = binding.weak_ref() del binding gc.collect() self.assertEqual(ref(), None) class TestGValue(unittest.TestCase): def test_type_constant(self): self.assertEqual(GObject.TYPE_VALUE, GObject.Value.__gtype__) self.assertEqual(GObject.type_name(GObject.TYPE_VALUE), 'GValue') def test_no_type(self): value = GObject.Value() self.assertEqual(value.g_type, GObject.TYPE_INVALID) self.assertRaises(TypeError, value.set_value, 23) self.assertEqual(value.get_value(), None) def test_int(self): value = GObject.Value(GObject.TYPE_UINT) self.assertEqual(value.g_type, GObject.TYPE_UINT) value.set_value(23) self.assertEqual(value.get_value(), 23) value.set_value(42.0) self.assertEqual(value.get_value(), 42) def test_string(self): value = GObject.Value(str, 'foo_bar') self.assertEqual(value.g_type, GObject.TYPE_STRING) self.assertEqual(value.get_value(), 'foo_bar') def test_float(self): # python float is G_TYPE_DOUBLE value = GObject.Value(float, 23.4) self.assertEqual(value.g_type, GObject.TYPE_DOUBLE) value.set_value(1e50) self.assertAlmostEqual(value.get_value(), 1e50) value = GObject.Value(GObject.TYPE_FLOAT, 23.4) self.assertEqual(value.g_type, GObject.TYPE_FLOAT) self.assertRaises(TypeError, value.set_value, 'string') self.assertRaises(OverflowError, value.set_value, 1e50) def test_float_inf_nan(self): nan = float('nan') for type_ in [GObject.TYPE_FLOAT, GObject.TYPE_DOUBLE]: for x in [float('inf'), float('-inf'), nan]: value = GObject.Value(type_, x) # assertEqual() is False for (nan, nan) if x is nan: self.assertEqual(str(value.get_value()), 'nan') else: self.assertEqual(value.get_value(), x) def test_enum(self): value = GObject.Value(GLib.FileError, GLib.FileError.FAILED) self.assertEqual(value.get_value(), GLib.FileError.FAILED) def test_flags(self): value = GObject.Value(GLib.IOFlags, GLib.IOFlags.IS_READABLE) self.assertEqual(value.get_value(), GLib.IOFlags.IS_READABLE) def test_object(self): class TestObject(GObject.Object): pass obj = TestObject() value = GObject.Value(GObject.TYPE_OBJECT, obj) self.assertEqual(value.get_value(), obj) def test_value_array(self): value = GObject.Value(GObject.ValueArray) self.assertEqual(value.g_type, GObject.type_from_name('GValueArray')) value.set_value([32, 'foo_bar', 0.3]) self.assertEqual(value.get_value(), [32, 'foo_bar', 0.3]) def test_value_array_from_gvalue_list(self): value = GObject.Value(GObject.ValueArray, [ GObject.Value(GObject.TYPE_UINT, 0xffffffff), GObject.Value(GObject.TYPE_STRING, 'foo_bar')]) self.assertEqual(value.g_type, GObject.type_from_name('GValueArray')) self.assertEqual(value.get_value(), [0xffffffff, 'foo_bar']) self.assertEqual(testhelper.value_array_get_nth_type(value, 0), GObject.TYPE_UINT) self.assertEqual(testhelper.value_array_get_nth_type(value, 1), GObject.TYPE_STRING) def test_value_array_append_gvalue(self): with warnings.catch_warnings(): warnings.simplefilter('ignore', DeprecationWarning) arr = GObject.ValueArray.new(0) arr.append(GObject.Value(GObject.TYPE_UINT, 0xffffffff)) arr.append(GObject.Value(GObject.TYPE_STRING, 'foo_bar')) self.assertEqual(arr.get_nth(0), 0xffffffff) self.assertEqual(arr.get_nth(1), 'foo_bar') self.assertEqual(testhelper.value_array_get_nth_type(arr, 0), GObject.TYPE_UINT) self.assertEqual(testhelper.value_array_get_nth_type(arr, 1), GObject.TYPE_STRING) def test_gerror_boxing(self): error = GLib.Error('test message', domain='mydomain', code=42) value = GObject.Value(GLib.Error, error) self.assertEqual(value.g_type, GObject.type_from_name('GError')) unboxed = value.get_value() self.assertEqual(unboxed.message, error.message) self.assertEqual(unboxed.domain, error.domain) self.assertEqual(unboxed.code, error.code) def test_gerror_novalue(self): GLib.Error('test message', domain='mydomain', code=42) value = GObject.Value(GLib.Error) self.assertEqual(value.g_type, GObject.type_from_name('GError')) self.assertEqual(value.get_value(), None) def test_list_properties(): def find_param(props, name): for param in props: if param.name == name: return param return list_props = GObject.list_properties props = list_props(Gio.Action) param = find_param(props, "enabled") assert param assert param.value_type == GObject.TYPE_BOOLEAN assert list_props("GAction") == list_props(Gio.Action) assert list_props(Gio.Action.__gtype__) == list_props(Gio.Action) props = list_props(Gio.SimpleAction) assert find_param(props, "enabled") def names(props): return [p.name for p in props] assert (set(names(list_props(Gio.Action))) <= set(names(list_props(Gio.SimpleAction)))) props = list_props(Gio.FileIcon) param = find_param(props, "file") assert param assert param.value_type == Gio.File.__gtype__ assert list_props("GFileIcon") == list_props(Gio.FileIcon) assert list_props(Gio.FileIcon.__gtype__) == list_props(Gio.FileIcon) assert list_props(Gio.FileIcon( file=Gio.File.new_for_path('.'))) == list_props(Gio.FileIcon) for obj in [Gio.ActionEntry, Gio.DBusError, 0, object()]: with pytest.raises(TypeError): list_props(obj) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/tests/test_gtk_template.py0000664000000000000000000004541015074674453017605 0ustar00rootrootimport tempfile import os import pytest Gtk = pytest.importorskip("gi.repository.Gtk") GLib = pytest.importorskip("gi.repository.GLib") GObject = pytest.importorskip("gi.repository.GObject") Gio = pytest.importorskip("gi.repository.Gio") from .helper import capture_exceptions GTK4 = (Gtk._version == "4.0") def new_gtype_name(_count=[0]): _count[0] += 1 return "GtkTemplateTest%d" % _count[0] def ensure_resource_registered(): resource_path = "/org/gnome/pygobject/test/a.ui" def is_registered(path): try: Gio.resources_get_info(path, Gio.ResourceLookupFlags.NONE) except GLib.Error: return False return True if is_registered(resource_path): return resource_path gresource_data = ( b'GVariant\x00\x00\x00\x00\x00\x00\x00\x00\x18\x00\x00\x00' b'\xc8\x00\x00\x00\x00\x00\x00(\x06\x00\x00\x00\x00\x00\x00\x00' b'\x00\x00\x00\x00\x01\x00\x00\x00\x04\x00\x00\x00\x05\x00\x00\x00' b'\x06\x00\x00\x00KP\x90\x0b\x03\x00\x00\x00\xc8\x00\x00\x00' b'\x04\x00L\x00\xcc\x00\x00\x00\xd0\x00\x00\x00\xb0\xb7$0' b'\x00\x00\x00\x00\xd0\x00\x00\x00\x06\x00L\x00\xd8\x00\x00\x00' b'\xdc\x00\x00\x00f\xc30\xd1\x01\x00\x00\x00\xdc\x00\x00\x00' b'\n\x00L\x00\xe8\x00\x00\x00\xec\x00\x00\x00\xd4\xb5\x02\x00' b'\xff\xff\xff\xff\xec\x00\x00\x00\x01\x00L\x00\xf0\x00\x00\x00' b'\xf4\x00\x00\x005H}\xe3\x02\x00\x00\x00\xf4\x00\x00\x00' b'\x05\x00L\x00\xfc\x00\x00\x00\x00\x01\x00\x00\xa2^\xd6t' b'\x04\x00\x00\x00\x00\x01\x00\x00\x04\x00v\x00\x08\x01\x00\x00' b'\xa5\x01\x00\x00org/\x01\x00\x00\x00gnome/\x00\x00\x02\x00\x00\x00' b'pygobject/\x00\x00\x04\x00\x00\x00/\x00\x00\x00\x00\x00\x00\x00' b'test/\x00\x00\x00\x05\x00\x00\x00a.ui\x00\x00\x00\x00' b'\x8d\x00\x00\x00\x00\x00\x00\x00\n \n\n\x00\x00(uuay)' ) resource = Gio.Resource.new_from_data(GLib.Bytes.new(gresource_data)) Gio.resources_register(resource) assert is_registered(resource_path) return resource_path def test_allow_init_template_call(): type_name = new_gtype_name() xml = """\ """.format(type_name) @Gtk.Template.from_string(xml) class Foo(Gtk.Box): __gtype_name__ = type_name def __init__(self): super(Foo, self).__init__() self.init_template() # Stop current pygobject from handling the initialisation del Foo.__dontuse_ginstance_init__ Foo() def test_init_template_second_instance(): type_name = new_gtype_name() xml = """\ """.format(type_name) @Gtk.Template.from_string(xml) class Foo(Gtk.Box): __gtype_name__ = type_name label = Gtk.Template.Child("label") def __init__(self): super(Foo, self).__init__() self.init_template() # Stop current pygobject from handling the initialisation del Foo.__dontuse_ginstance_init__ foo = Foo() assert isinstance(foo.label, Gtk.Label) foo2 = Foo() assert isinstance(foo2.label, Gtk.Label) def test_main_example(): type_name = new_gtype_name() example_xml = """\ """.format(type_name) @Gtk.Template.from_string(example_xml) class Foo(Gtk.Box): __gtype_name__ = type_name def __init__(self): super(Foo, self).__init__() self.callback_hello = [] self.callback_hello_after = [] self.callback_goodbye = [] self.callback_goodbye_after = [] @Gtk.Template.Callback("hello_button_clicked") def _hello_button_clicked(self, *args): self.callback_hello.append(args) @Gtk.Template.Callback("hello_button_clicked_after") def _hello_after(self, *args): self.callback_hello_after.append(args) _hello_button = Gtk.Template.Child("hello_button") goodbye_button = Gtk.Template.Child() @Gtk.Template.Callback("goodbye_button_clicked") def _goodbye_button_clicked(self, *args): self.callback_goodbye.append(args) @Gtk.Template.Callback("goodbye_button_clicked_after") def _goodbye_after(self, *args): self.callback_goodbye_after.append(args) w = Foo() assert w.__gtype__.name == type_name assert w.props.orientation == Gtk.Orientation.HORIZONTAL assert w.props.spacing == 4 assert isinstance(w._hello_button, Gtk.Button) assert w._hello_button.props.label == "Hello World" assert isinstance(w.goodbye_button, Gtk.Button) assert w.goodbye_button.props.label == "Goodbye World" assert w.callback_hello == [] w._hello_button.emit("clicked") assert w.callback_hello == [(w,)] assert w.callback_hello_after == [(w,)] assert w.callback_goodbye == [] w.goodbye_button.emit("clicked") assert w.callback_goodbye == [(w.goodbye_button,)] assert w.callback_goodbye_after == [(w.goodbye_button,)] def test_duplicate_handler(): type_name = new_gtype_name() xml = """\ """.format(type_name) class Foo(Gtk.Box): __gtype_name__ = type_name @Gtk.Template.Callback("hello_button_clicked") def _hello_button_clicked(self, *args): pass @Gtk.Template.Callback() def hello_button_clicked(self, *args): pass with pytest.raises(RuntimeError, match=".*hello_button_clicked.*"): Gtk.Template.from_string(xml)(Foo) def test_duplicate_child(): type_name = new_gtype_name() xml = """\ """.format(type_name) class Foo(Gtk.Box): __gtype_name__ = type_name foo = Gtk.Template.Child("hello_button") hello_button = Gtk.Template.Child() with pytest.raises(RuntimeError, match=".*hello_button.*"): Gtk.Template.from_string(xml)(Foo) def test_nonexist_handler(): type_name = new_gtype_name() xml = """\ """.format(type_name) @Gtk.Template.from_string(xml) class Foo(Gtk.Box): __gtype_name__ = type_name @Gtk.Template.Callback("nonexit") def foo(self, *args): pass with capture_exceptions() as exc_info: Foo() assert "nonexit" in str(exc_info[0].value) assert exc_info[0].type is RuntimeError def test_missing_handler_callback(): type_name = new_gtype_name() xml = """\ """.format(type_name) class Foo(Gtk.Box): __gtype_name__ = type_name Gtk.Template.from_string(xml)(Foo)() def test_handler_swapped_not_supported(): type_name = new_gtype_name() xml = """\ """.format(type_name) @Gtk.Template.from_string(xml) class Foo(Gtk.Box): __gtype_name__ = type_name hello_button = Gtk.Template.Child() @Gtk.Template.Callback("hello_button_clicked") def foo(self, *args): pass with capture_exceptions() as exc_info: Foo() assert "G_CONNECT_SWAPPED" in str(exc_info[0].value) def test_handler_class_staticmethod(): type_name = new_gtype_name() xml = """\ """.format(type_name) signal_args_class = [] signal_args_static = [] @Gtk.Template.from_string(xml) class Foo(Gtk.Box): __gtype_name__ = type_name hello_button = Gtk.Template.Child() @Gtk.Template.Callback("clicked_class") @classmethod def cb1(*args): signal_args_class.append(args) @Gtk.Template.Callback("clicked_static") @staticmethod def cb2(*args): signal_args_static.append(args) foo = Foo() foo.hello_button.emit("clicked") assert signal_args_class == [(Foo, foo.hello_button)] assert signal_args_static == [(foo.hello_button,)] @pytest.mark.skipif(Gtk._version == "4.0", reason="errors out first with gtk4") def test_check_decorated_class(): NonWidget = type("Foo", (object,), {}) with pytest.raises(TypeError, match=".*on Widgets.*"): Gtk.Template.from_string("")(NonWidget) Widget = type("Foo", (Gtk.Widget,), {"__gtype_name__": new_gtype_name()}) with pytest.raises(TypeError, match=".*Cannot nest.*"): Gtk.Template.from_string("")(Gtk.Template.from_string("")(Widget)) Widget = type("Foo", (Gtk.Widget,), {}) with pytest.raises(TypeError, match=".*__gtype_name__.*"): Gtk.Template.from_string("")(Widget) with pytest.raises(TypeError, match=".*on Widgets.*"): Gtk.Template.from_string("")(object()) @pytest.mark.skipif(Gtk._version == "4.0", reason="errors out first with gtk4") def test_subclass_fail(): @Gtk.Template.from_string("") class Base(Gtk.Widget): __gtype_name__ = new_gtype_name() with capture_exceptions() as exc_info: type("Sub", (Base,), {})() assert "not allowed at this time" in str(exc_info[0].value) assert exc_info[0].type is TypeError def test_from_file(): fd, name = tempfile.mkstemp() try: os.close(fd) type_name = new_gtype_name() with open(name, "wb") as h: h.write(u"""\ """.format(type_name).encode()) @Gtk.Template.from_file(name) class Foo(Gtk.Box): __gtype_name__ = type_name foo = Foo() assert foo.props.spacing == 42 finally: os.remove(name) def test_property_override(): type_name = new_gtype_name() xml = """\ """.format(type_name) @Gtk.Template.from_string(xml) class Foo(Gtk.Box): __gtype_name__ = type_name foo = Foo() assert foo.props.spacing == 42 foo = Foo(spacing=124) assert foo.props.spacing == 124 def test_from_file_non_exist(): dirname = tempfile.mkdtemp() try: path = os.path.join(dirname, "noexist") Widget = type( "Foo", (Gtk.Widget,), {"__gtype_name__": new_gtype_name()}) with pytest.raises(GLib.Error, match=".*No such file.*"): Gtk.Template.from_file(path)(Widget) finally: os.rmdir(dirname) def test_from_string_bytes(): type_name = new_gtype_name() xml = u"""\ """.format(type_name).encode() @Gtk.Template.from_string(xml) class Foo(Gtk.Box): __gtype_name__ = type_name foo = Foo() assert foo.props.spacing == 42 def test_from_resource(): resource_path = ensure_resource_registered() @Gtk.Template.from_resource(resource_path) class Foo(Gtk.Box): __gtype_name__ = "GtkTemplateTestResource" foo = Foo() assert foo.props.spacing == 42 def test_from_resource_non_exit(): Widget = type("Foo", (Gtk.Widget,), {"__gtype_name__": new_gtype_name()}) with pytest.raises(GLib.Error, match=".*/or/gnome/pygobject/noexit.*"): Gtk.Template.from_resource("/or/gnome/pygobject/noexit")(Widget) def test_constructors(): with pytest.raises(TypeError): Gtk.Template() with pytest.raises(TypeError): Gtk.Template(foo=1) Gtk.Template(filename="foo") Gtk.Template(resource_path="foo") Gtk.Template(string="foo") with pytest.raises(TypeError): Gtk.Template(filename="foo", resource_path="bar") with pytest.raises(TypeError): Gtk.Template(filename="foo", nope="bar") Gtk.Template.from_string("bla") Gtk.Template.from_resource("foo") Gtk.Template.from_file("foo") def test_child_construct(): Gtk.Template.Child() Gtk.Template.Child("name") with pytest.raises(TypeError): Gtk.Template.Child("name", True) Gtk.Template.Child("name", internal=True) with pytest.raises(TypeError): Gtk.Template.Child("name", internal=True, something=False) def test_internal_child(): main_type_name = new_gtype_name() xml = """\ """.format(main_type_name) @Gtk.Template.from_string(xml) class MainThing(Gtk.Box): __gtype_name__ = main_type_name somechild = Gtk.Template.Child(internal=True) thing = MainThing() assert thing.somechild.props.margin_top == 42 other_type_name = new_gtype_name() xml = """\ """.format(other_type_name, main_type_name) @Gtk.Template.from_string(xml) class OtherThing(Gtk.Box): __gtype_name__ = other_type_name other = OtherThing() if not GTK4: child = other.get_children()[0] else: child = other.get_first_child() assert isinstance(child, MainThing) if not GTK4: child = child.get_children()[0] else: child = child.get_first_child() assert isinstance(child, Gtk.Box) assert child.props.margin_top == 24 if not GTK4: child = child.get_children()[0] else: child = child.get_first_child() assert isinstance(child, Gtk.Label) assert child.props.label == "foo" def test_template_hierarchy(): testlabel = """ """ @Gtk.Template(string=testlabel) class TestLabel(Gtk.Label): __gtype_name__ = "TestLabel" def __init__(self): super().__init__() self.props.label = "TestLabel" testbox = """ """ @Gtk.Template(string=testbox) class TestBox(Gtk.Box): __gtype_name__ = "TestBox" _testlabel = Gtk.Template.Child() def __init__(self): super().__init__() assert isinstance(self._testlabel, TestLabel) window = """ """ @Gtk.Template(string=window) class MyWindow(Gtk.Window): __gtype_name__ = "MyWindow" _testbox = Gtk.Template.Child() _testlabel = Gtk.Template.Child() def __init__(self): super().__init__() assert isinstance(self._testbox, TestBox) assert isinstance(self._testlabel, TestLabel) if not GTK4: children = self._testbox.get_children() else: children = list(self._testbox) assert len(children) == 2 win = MyWindow() assert isinstance(win, MyWindow) def test_multiple_init_template_calls(): xml = """ """ @Gtk.Template(string=xml) class MyBox(Gtk.Box): __gtype_name__ = "MyBox" _label = Gtk.Template.Child() def __init__(self): super().__init__() self._label.props.label = "awesome label" my_box = MyBox() assert isinstance(my_box, MyBox) if not GTK4: children = my_box.get_children() else: children = list(my_box) assert len(children) == 1 my_box.init_template() assert isinstance(my_box, MyBox) if not GTK4: children = my_box.get_children() else: children = list(my_box) assert len(children) == 1 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/tests/test_gtype.py0000664000000000000000000001052215074674453016251 0ustar00rootrootimport unittest from gi.repository import GObject from gi.repository import GIMarshallingTests class CustomBase(GObject.GObject): pass class CustomChild(CustomBase, GIMarshallingTests.Interface): pass class TestTypeModuleLevelFunctions(unittest.TestCase): def test_type_name(self): self.assertEqual(GObject.type_name(GObject.TYPE_NONE), 'void') self.assertEqual(GObject.type_name(GObject.TYPE_OBJECT), 'GObject') self.assertEqual(GObject.type_name(GObject.TYPE_PYOBJECT), 'PyObject') def test_type_from_name(self): # A complete test is not needed here since the TYPE_* defines are created # using this method. self.assertRaises(RuntimeError, GObject.type_from_name, '!NOT_A_REAL_TYPE!') self.assertEqual(GObject.type_from_name('GObject'), GObject.TYPE_OBJECT) self.assertEqual(GObject.type_from_name('GObject'), GObject.GObject.__gtype__) def test_type_is_a(self): self.assertTrue(GObject.type_is_a(CustomBase, GObject.TYPE_OBJECT)) self.assertTrue(GObject.type_is_a(CustomChild, CustomBase)) self.assertTrue(GObject.type_is_a(CustomBase, GObject.GObject)) self.assertTrue(GObject.type_is_a(CustomBase.__gtype__, GObject.TYPE_OBJECT)) self.assertFalse(GObject.type_is_a(GObject.TYPE_OBJECT, CustomBase)) self.assertFalse(GObject.type_is_a(CustomBase, int)) # invalid type self.assertRaises(TypeError, GObject.type_is_a, CustomBase, 1) self.assertRaises(TypeError, GObject.type_is_a, 2, GObject.TYPE_OBJECT) self.assertRaises(TypeError, GObject.type_is_a, 1, 2) def test_type_children(self): self.assertEqual(GObject.type_children(CustomBase), [CustomChild.__gtype__]) self.assertEqual(len(GObject.type_children(CustomChild)), 0) def test_type_interfaces(self): self.assertEqual(len(GObject.type_interfaces(CustomBase)), 0) self.assertEqual(len(GObject.type_interfaces(CustomChild)), 1) self.assertEqual(GObject.type_interfaces(CustomChild), [GIMarshallingTests.Interface.__gtype__]) def test_type_parent(self): self.assertEqual(GObject.type_parent(CustomChild), CustomBase.__gtype__) self.assertEqual(GObject.type_parent(CustomBase), GObject.TYPE_OBJECT) self.assertRaises(RuntimeError, GObject.type_parent, GObject.GObject) def test_gtype_has_value_table(): assert CustomBase.__gtype__.has_value_table() assert not GIMarshallingTests.Interface.__gtype__.has_value_table() assert CustomChild.__gtype__.has_value_table() def test_gtype_is_abstract(): assert not CustomBase.__gtype__.is_abstract() assert not GIMarshallingTests.Interface.__gtype__.is_abstract() assert not CustomChild.__gtype__.is_abstract() def test_gtype_is_classed(): assert CustomBase.__gtype__.is_classed() assert not GIMarshallingTests.Interface.__gtype__.is_classed() assert CustomChild.__gtype__.is_classed() def test_gtype_is_deep_derivable(): assert CustomBase.__gtype__.is_deep_derivable() assert not GIMarshallingTests.Interface.__gtype__.is_deep_derivable() assert CustomChild.__gtype__.is_deep_derivable() def test_gtype_is_derivable(): assert CustomBase.__gtype__.is_derivable() assert GIMarshallingTests.Interface.__gtype__.is_derivable() assert CustomChild.__gtype__.is_derivable() def test_gtype_is_value_abstract(): assert not CustomBase.__gtype__.is_value_abstract() assert not GIMarshallingTests.Interface.__gtype__.is_value_abstract() assert not CustomChild.__gtype__.is_value_abstract() def test_gtype_is_value_type(): assert CustomBase.__gtype__.is_value_type() assert not GIMarshallingTests.Interface.__gtype__.is_value_type() assert CustomChild.__gtype__.is_value_type() def test_gtype_children(): assert CustomBase.__gtype__.children == [CustomChild.__gtype__] assert GIMarshallingTests.Interface.__gtype__.children == [] assert CustomChild.__gtype__.children == [] def test_gtype_depth(): assert CustomBase.__gtype__.depth == 2 assert GIMarshallingTests.Interface.__gtype__.depth == 2 assert CustomChild.__gtype__.depth == 3 def test_gtype_interfaces(): assert CustomBase.__gtype__.interfaces == [] assert GIMarshallingTests.Interface.__gtype__.interfaces == [] assert CustomChild.__gtype__.interfaces == \ [GIMarshallingTests.Interface.__gtype__] ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/tests/test_import_machinery.py0000664000000000000000000001245415074674453020500 0ustar00rootroot# -*- Mode: Python; py-indent-offset: 4 -*- # vim: tabstop=4 shiftwidth=4 expandtab import sys import unittest import gi.overrides import gi.module import gi.importer from gi.repository import Regress class TestOverrides(unittest.TestCase): def test_non_gi(self): class MyClass: pass try: gi.overrides.override(MyClass) self.fail('unexpected success of overriding non-GI class') except TypeError as e: self.assertTrue('Can not override a type MyClass' in str(e)) def test_separate_path(self): # Regress override is in tests/gi/overrides, separate from gi/overrides # https://bugzilla.gnome.org/show_bug.cgi?id=680913 self.assertEqual(Regress.REGRESS_OVERRIDE, 42) def test_load_overrides(self): mod = gi.module.get_introspection_module('GIMarshallingTests') mod_override = gi.overrides.load_overrides(mod) self.assertTrue(mod_override is not mod) self.assertTrue(mod_override._introspection_module is mod) self.assertEqual(mod_override.OVERRIDES_CONSTANT, 7) self.assertEqual(mod.OVERRIDES_CONSTANT, 42) def test_load_no_overrides(self): mod_key = "gi.overrides.GIMarshallingTests" had_mod = mod_key in sys.modules old_mod = sys.modules.get(mod_key) try: # this makes override import fail sys.modules[mod_key] = None mod = gi.module.get_introspection_module('GIMarshallingTests') mod_override = gi.overrides.load_overrides(mod) self.assertTrue(mod_override is mod) finally: del sys.modules[mod_key] if had_mod: sys.modules[mod_key] = old_mod class TestModule(unittest.TestCase): # Tests for gi.module def test_get_introspection_module_caching(self): # This test attempts to minimize side effects by # using a DynamicModule directly instead of going though: # from gi.repository import Foo # Clear out introspection module cache before running this test. old_modules = gi.module._introspection_modules gi.module._introspection_modules = {} mod_name = 'GIMarshallingTests' mod1 = gi.module.get_introspection_module(mod_name) mod2 = gi.module.get_introspection_module(mod_name) self.assertTrue(mod1 is mod2) # Restore the previous cache gi.module._introspection_modules = old_modules def test_module_dependency_loading(self): # Difficult to because this generally need to run in isolation to make # sure GIMarshallingTests has not yet been loaded. But we can do this with: # make check TEST_NAMES=test_import_machinery.TestModule.test_module_dependency_loading if 'gi.repository.Gio' in sys.modules: return from gi.repository import GIMarshallingTests GIMarshallingTests # PyFlakes self.assertIn('gi.repository.Gio', sys.modules) self.assertIn('gi.repository.GIMarshallingTests', sys.modules) def test_static_binding_protection(self): # Importing old static bindings once gi has been imported should not # crash but instead give back a dummy module which produces RuntimeErrors # on access. with self.assertRaises(AttributeError): import gobject gobject.anything with self.assertRaises(AttributeError): import glib glib.anything with self.assertRaises(AttributeError): import gio gio.anything with self.assertRaises(AttributeError): import gtk gtk.anything with self.assertRaises(AttributeError): import gtk.gdk gtk.gdk.anything class TestImporter(unittest.TestCase): def test_invalid_repository_module_name(self): with self.assertRaises(ImportError) as context: from gi.repository import InvalidGObjectRepositoryModuleName InvalidGObjectRepositoryModuleName # pyflakes exception_string = str(context.exception) self.assertTrue('InvalidGObjectRepositoryModuleName' in exception_string) self.assertTrue('introspection typelib' in exception_string) def test_require_version_warning(self): check = gi.importer._check_require_version # make sure it doesn't fail at least with check("GLib", 1): from gi.repository import GLib GLib # make sure the exception propagates with self.assertRaises(ImportError): with check("InvalidGObjectRepositoryModuleName", 1): from gi.repository import InvalidGObjectRepositoryModuleName InvalidGObjectRepositoryModuleName def test_require_version_versiontype(self): import gi with self.assertRaises(ValueError): gi.require_version('GLib', 2.0) with self.assertRaises(ValueError): gi.require_version('GLib', b'2.0') def test_require_versions(self): import gi gi.require_versions({'GLib': '2.0', 'Gio': '2.0', 'GObject': '2.0'}) from gi.repository import GLib GLib def test_get_import_stacklevel(self): gi.importer.get_import_stacklevel(import_hook=True) gi.importer.get_import_stacklevel(import_hook=False) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/tests/test_interface.py0000664000000000000000000000206515074674453017064 0ustar00rootroot# -*- Mode: Python -*- import unittest from gi.repository import GObject import testhelper GUnknown = GObject.type_from_name("TestUnknown") Unknown = GUnknown.pytype class MyUnknown(Unknown, testhelper.Interface): some_property = GObject.Property(type=str) def __init__(self): Unknown.__init__(self) self.called = False def do_iface_method(self): self.called = True Unknown.do_iface_method(self) GObject.type_register(MyUnknown) class MyObject(GObject.GObject, testhelper.Interface): some_property = GObject.Property(type=str) def __init__(self): GObject.GObject.__init__(self) self.called = False def do_iface_method(self): self.called = True GObject.type_register(MyObject) class TestIfaceImpl(unittest.TestCase): def test_reimplement_interface(self): m = MyUnknown() m.iface_method() self.assertEqual(m.called, True) def test_implement_interface(self): m = MyObject() m.iface_method() self.assertEqual(m.called, True) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/tests/test_internal_api.py0000664000000000000000000000776415074674453017604 0ustar00rootroot# -*- Mode: Python -*- import unittest import pytest from gi.repository import GLib, GObject import testhelper class PyGObject(GObject.GObject): __gtype_name__ = 'PyGObject' __gproperties__ = { 'label': (GObject.TYPE_STRING, 'label property', 'the label of the object', 'default', GObject.ParamFlags.READABLE | GObject.ParamFlags.WRITABLE), } def __init__(self): self._props = {} GObject.GObject.__init__(self) self.set_property('label', 'hello') def do_set_property(self, name, value): self._props[name] = value def do_get_property(self, name): return self._props[name] def test_parse_constructor_args(): assert testhelper.test_parse_constructor_args("foo") == 1 class TestObject(unittest.TestCase): def test_create_ctor(self): o = PyGObject() self.assertTrue(isinstance(o, GObject.Object)) self.assertTrue(isinstance(o, PyGObject)) # has expected property self.assertEqual(o.props.label, 'hello') o.props.label = 'goodbye' self.assertEqual(o.props.label, 'goodbye') self.assertRaises(AttributeError, getattr, o.props, 'nosuchprop') def test_pyobject_new_test_type(self): o = testhelper.create_test_type() self.assertTrue(isinstance(o, PyGObject)) # has expected property self.assertEqual(o.props.label, 'hello') o.props.label = 'goodbye' self.assertEqual(o.props.label, 'goodbye') self.assertRaises(AttributeError, getattr, o.props, 'nosuchprop') def test_new_refcount(self): # TODO: justify why this should be 2 self.assertEqual(testhelper.test_g_object_new(), 2) class TestGValueConversion(unittest.TestCase): def test_int(self): self.assertEqual(testhelper.test_value(0), 0) self.assertEqual(testhelper.test_value(5), 5) self.assertEqual(testhelper.test_value(-5), -5) self.assertEqual(testhelper.test_value(GLib.MAXINT32), GLib.MAXINT32) self.assertEqual(testhelper.test_value(GLib.MININT32), GLib.MININT32) def test_str(self): self.assertEqual(testhelper.test_value('hello'), 'hello') def test_int_array(self): self.assertEqual(testhelper.test_value_array([]), []) self.assertEqual(testhelper.test_value_array([0]), [0]) ar = list(range(100)) self.assertEqual(testhelper.test_value_array(ar), ar) def test_str_array(self): self.assertEqual(testhelper.test_value_array([]), []) self.assertEqual(testhelper.test_value_array(['a']), ['a']) ar = ('aa ' * 1000).split() self.assertEqual(testhelper.test_value_array(ar), ar) class TestErrors(unittest.TestCase): def test_gerror(self): callable_ = lambda: GLib.file_get_contents('/nonexisting ') self.assertRaises(GLib.GError, testhelper.test_gerror_exception, callable_) def test_no_gerror(self): callable_ = lambda: GLib.file_get_contents(__file__) self.assertEqual(testhelper.test_gerror_exception(callable_), None) def test_to_unichar_conv(): assert testhelper.test_to_unichar_conv(u"A") == 65 assert testhelper.test_to_unichar_conv(u"Ä") == 196 with pytest.raises(TypeError): assert testhelper.test_to_unichar_conv(b"\x65") with pytest.raises(TypeError): testhelper.test_to_unichar_conv(object()) with pytest.raises(TypeError): testhelper.test_to_unichar_conv(u"AA") def test_constant_strip_prefix(): assert testhelper.constant_strip_prefix("foo", "bar") == "foo" assert testhelper.constant_strip_prefix("foo", "f") == "oo" assert testhelper.constant_strip_prefix("foo", "f") == "oo" assert testhelper.constant_strip_prefix("ha2foo", "ha") == "a2foo" assert testhelper.constant_strip_prefix("2foo", "ha") == "2foo" assert testhelper.constant_strip_prefix("bla_foo", "bla") == "_foo" def test_state_ensure_release(): testhelper.test_state_ensure_release() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/tests/test_iochannel.py0000664000000000000000000003722715074674453017074 0ustar00rootroot# -*- Mode: Python -*- import os import unittest import tempfile import os.path import shutil import warnings try: import fcntl except ImportError: fcntl = None from gi.repository import GLib from gi import PyGIDeprecationWarning class IOChannel(unittest.TestCase): def setUp(self): self.workdir = tempfile.mkdtemp() self.testutf8 = os.path.join(self.workdir, 'testutf8.txt') with open(self.testutf8, 'wb') as f: f.write(u'''hello ♥ world second line À demain!'''.encode('UTF-8')) self.testlatin1 = os.path.join(self.workdir, 'testlatin1.txt') with open(self.testlatin1, 'wb') as f: f.write(b'''hell\xf8 world second line \xc0 demain!''') self.testout = os.path.join(self.workdir, 'testout.txt') def tearDown(self): shutil.rmtree(self.workdir) def test_file_readline_utf8(self): ch = GLib.IOChannel(filename=self.testutf8) self.assertEqual(ch.get_encoding(), 'UTF-8') self.assertTrue(ch.get_close_on_unref()) self.assertEqual(ch.readline(), 'hello ♥ world\n') self.assertEqual(ch.get_buffer_condition(), GLib.IOCondition.IN) self.assertEqual(ch.readline(), 'second line\n') self.assertEqual(ch.readline(), '\n') self.assertEqual(ch.readline(), 'À demain!') self.assertEqual(ch.get_buffer_condition(), 0) self.assertEqual(ch.readline(), '') ch.shutdown(True) def test_file_readline_latin1(self): ch = GLib.IOChannel(filename=self.testlatin1, mode='r') ch.set_encoding('latin1') self.assertEqual(ch.get_encoding(), 'latin1') self.assertEqual(ch.readline(), 'hellø world\n') self.assertEqual(ch.readline(), 'second line\n') self.assertEqual(ch.readline(), '\n') self.assertEqual(ch.readline(), 'À demain!') ch.shutdown(True) def test_file_iter(self): items = [] ch = GLib.IOChannel(filename=self.testutf8) for item in ch: items.append(item) self.assertEqual(len(items), 4) self.assertEqual(items[0], 'hello ♥ world\n') ch.shutdown(True) def test_file_readlines(self): ch = GLib.IOChannel(filename=self.testutf8) lines = ch.readlines() # Note, this really ought to be 4, but the static bindings add an extra # empty one self.assertGreaterEqual(len(lines), 4) self.assertLessEqual(len(lines), 5) self.assertEqual(lines[0], 'hello ♥ world\n') self.assertEqual(lines[3], 'À demain!') if len(lines) == 4: self.assertEqual(lines[4], '') def test_file_read(self): ch = GLib.IOChannel(filename=self.testutf8) with open(self.testutf8, 'rb') as f: self.assertEqual(ch.read(), f.read()) ch = GLib.IOChannel(filename=self.testutf8) with open(self.testutf8, 'rb') as f: self.assertEqual(ch.read(10), f.read(10)) ch = GLib.IOChannel(filename=self.testutf8) with open(self.testutf8, 'rb') as f: self.assertEqual(ch.read(max_count=15), f.read(15)) def test_seek(self): ch = GLib.IOChannel(filename=self.testutf8) ch.seek(2) self.assertEqual(ch.read(3), b'llo') ch.seek(2, 0) # SEEK_SET self.assertEqual(ch.read(3), b'llo') ch.seek(1, 1) # SEEK_CUR, skip the space self.assertEqual(ch.read(3), b'\xe2\x99\xa5') ch.seek(2, 2) # SEEK_END # FIXME: does not work currently # self.assertEqual(ch.read(2), b'n!') # invalid whence value self.assertRaises(ValueError, ch.seek, 0, 3) ch.shutdown(True) def test_file_write(self): ch = GLib.IOChannel(filename=self.testout, mode='w') ch.set_encoding('latin1') ch.write('hellø world\n') ch.shutdown(True) ch = GLib.IOChannel(filename=self.testout, mode='a') ch.set_encoding('latin1') ch.write('À demain!') ch.shutdown(True) with open(self.testout, 'rb') as f: self.assertEqual(f.read().decode('latin1'), u'hellø world\nÀ demain!') def test_file_writelines(self): ch = GLib.IOChannel(filename=self.testout, mode='w') ch.writelines(['foo', 'bar\n', 'baz\n', 'end']) ch.shutdown(True) with open(self.testout, 'r') as f: self.assertEqual(f.read(), 'foobar\nbaz\nend') def test_buffering(self): writer = GLib.IOChannel(filename=self.testout, mode='w') writer.set_encoding(None) self.assertTrue(writer.get_buffered()) self.assertGreater(writer.get_buffer_size(), 10) reader = GLib.IOChannel(filename=self.testout, mode='r') # does not get written immediately on buffering writer.write('abc') self.assertEqual(reader.read(), b'') writer.flush() self.assertEqual(reader.read(), b'abc') # does get written immediately without buffering writer.set_buffered(False) writer.write('def') self.assertEqual(reader.read(), b'def') # writes after buffer overflow writer.set_buffer_size(10) writer.write('0123456789012') self.assertTrue(reader.read().startswith(b'012')) writer.flush() reader.read() # ignore bits written after flushing # closing flushes writer.set_buffered(True) writer.write('ghi') writer.shutdown(True) self.assertEqual(reader.read(), b'ghi') reader.shutdown(True) @unittest.skipIf(os.name == "nt", "NONBLOCK not implemented on Windows") def test_fd_read(self): (r, w) = os.pipe() ch = GLib.IOChannel(filedes=r) ch.set_encoding(None) ch.set_flags(ch.get_flags() | GLib.IOFlags.NONBLOCK) self.assertNotEqual(ch.get_flags() | GLib.IOFlags.NONBLOCK, 0) self.assertEqual(ch.read(), b'') os.write(w, b'\x01\x02') self.assertEqual(ch.read(), b'\x01\x02') # now test blocking case, after closing the write end ch.set_flags(GLib.IOFlags(ch.get_flags() & ~GLib.IOFlags.NONBLOCK)) os.write(w, b'\x03\x04') os.close(w) self.assertEqual(ch.read(), b'\x03\x04') ch.shutdown(True) @unittest.skipUnless(fcntl, "no fcntl") def test_fd_write(self): (r, w) = os.pipe() fcntl.fcntl(r, fcntl.F_SETFL, fcntl.fcntl(r, fcntl.F_GETFL) | os.O_NONBLOCK) ch = GLib.IOChannel(filedes=w, mode='w') ch.set_encoding(None) ch.set_buffered(False) ch.write(b'\x01\x02') self.assertEqual(os.read(r, 10), b'\x01\x02') # now test blocking case, after closing the write end fcntl.fcntl(r, fcntl.F_SETFL, fcntl.fcntl(r, fcntl.F_GETFL) & ~os.O_NONBLOCK) ch.write(b'\x03\x04') ch.shutdown(True) self.assertEqual(os.read(r, 10), b'\x03\x04') os.close(r) @unittest.skipIf(os.name == "nt", "NONBLOCK not implemented on Windows") def test_deprecated_method_add_watch_no_data(self): (r, w) = os.pipe() ch = GLib.IOChannel(filedes=r) ch.set_encoding(None) ch.set_flags(ch.get_flags() | GLib.IOFlags.NONBLOCK) cb_reads = [] def cb(channel, condition): self.assertEqual(channel, ch) self.assertEqual(condition, GLib.IOCondition.IN) cb_reads.append(channel.read()) if len(cb_reads) == 2: ml.quit() return True # io_add_watch() method is deprecated, use GLib.io_add_watch with warnings.catch_warnings(record=True) as warn: warnings.simplefilter('always') ch.add_watch(GLib.IOCondition.IN, cb, priority=GLib.PRIORITY_HIGH) self.assertTrue(issubclass(warn[0].category, PyGIDeprecationWarning)) def write(): os.write(w, b'a') GLib.idle_add(lambda: os.write(w, b'b') and False) ml = GLib.MainLoop() GLib.idle_add(write) GLib.timeout_add(2000, ml.quit) ml.run() self.assertEqual(cb_reads, [b'a', b'b']) @unittest.skipIf(os.name == "nt", "NONBLOCK not implemented on Windows") def test_deprecated_method_add_watch_data_priority(self): (r, w) = os.pipe() ch = GLib.IOChannel(filedes=r) ch.set_encoding(None) ch.set_flags(ch.get_flags() | GLib.IOFlags.NONBLOCK) cb_reads = [] def cb(channel, condition, data): self.assertEqual(channel, ch) self.assertEqual(condition, GLib.IOCondition.IN) self.assertEqual(data, 'hello') cb_reads.append(channel.read()) if len(cb_reads) == 2: ml.quit() return True ml = GLib.MainLoop() # io_add_watch() method is deprecated, use GLib.io_add_watch with warnings.catch_warnings(record=True) as warn: warnings.simplefilter('always') id = ch.add_watch(GLib.IOCondition.IN, cb, 'hello', priority=GLib.PRIORITY_HIGH) self.assertTrue(issubclass(warn[0].category, PyGIDeprecationWarning)) self.assertEqual(ml.get_context().find_source_by_id(id).priority, GLib.PRIORITY_HIGH) def write(): os.write(w, b'a') GLib.idle_add(lambda: os.write(w, b'b') and False) GLib.idle_add(write) GLib.timeout_add(2000, ml.quit) ml.run() self.assertEqual(cb_reads, [b'a', b'b']) @unittest.skipIf(os.name == "nt", "NONBLOCK not implemented on Windows") def test_add_watch_no_data(self): (r, w) = os.pipe() ch = GLib.IOChannel(filedes=r) ch.set_encoding(None) ch.set_flags(ch.get_flags() | GLib.IOFlags.NONBLOCK) cb_reads = [] def cb(channel, condition): self.assertEqual(channel, ch) self.assertEqual(condition, GLib.IOCondition.IN) cb_reads.append(channel.read()) if len(cb_reads) == 2: ml.quit() return True id = GLib.io_add_watch(ch, GLib.PRIORITY_HIGH, GLib.IOCondition.IN, cb) ml = GLib.MainLoop() self.assertEqual(ml.get_context().find_source_by_id(id).priority, GLib.PRIORITY_HIGH) def write(): os.write(w, b'a') GLib.idle_add(lambda: os.write(w, b'b') and False) GLib.idle_add(write) GLib.timeout_add(2000, ml.quit) ml.run() self.assertEqual(cb_reads, [b'a', b'b']) @unittest.skipIf(os.name == "nt", "NONBLOCK not implemented on Windows") def test_add_watch_with_data(self): (r, w) = os.pipe() ch = GLib.IOChannel(filedes=r) ch.set_encoding(None) ch.set_flags(ch.get_flags() | GLib.IOFlags.NONBLOCK) cb_reads = [] def cb(channel, condition, data): self.assertEqual(channel, ch) self.assertEqual(condition, GLib.IOCondition.IN) self.assertEqual(data, 'hello') cb_reads.append(channel.read()) if len(cb_reads) == 2: ml.quit() return True id = GLib.io_add_watch(ch, GLib.PRIORITY_HIGH, GLib.IOCondition.IN, cb, 'hello') ml = GLib.MainLoop() self.assertEqual(ml.get_context().find_source_by_id(id).priority, GLib.PRIORITY_HIGH) def write(): os.write(w, b'a') GLib.idle_add(lambda: os.write(w, b'b') and False) GLib.idle_add(write) GLib.timeout_add(2000, ml.quit) ml.run() self.assertEqual(cb_reads, [b'a', b'b']) @unittest.skipIf(os.name == "nt", "NONBLOCK not implemented on Windows") def test_add_watch_with_multi_data(self): (r, w) = os.pipe() ch = GLib.IOChannel(filedes=r) ch.set_encoding(None) ch.set_flags(ch.get_flags() | GLib.IOFlags.NONBLOCK) cb_reads = [] def cb(channel, condition, data1, data2, data3): self.assertEqual(channel, ch) self.assertEqual(condition, GLib.IOCondition.IN) self.assertEqual(data1, 'a') self.assertEqual(data2, 'b') self.assertEqual(data3, 'c') cb_reads.append(channel.read()) if len(cb_reads) == 2: ml.quit() return True id = GLib.io_add_watch(ch, GLib.PRIORITY_HIGH, GLib.IOCondition.IN, cb, 'a', 'b', 'c') ml = GLib.MainLoop() self.assertEqual(ml.get_context().find_source_by_id(id).priority, GLib.PRIORITY_HIGH) def write(): os.write(w, b'a') GLib.idle_add(lambda: os.write(w, b'b') and False) GLib.idle_add(write) GLib.timeout_add(2000, ml.quit) ml.run() self.assertEqual(cb_reads, [b'a', b'b']) @unittest.skipIf(os.name == "nt", "NONBLOCK not implemented on Windows") def test_deprecated_add_watch_no_data(self): (r, w) = os.pipe() ch = GLib.IOChannel(filedes=r) ch.set_encoding(None) ch.set_flags(ch.get_flags() | GLib.IOFlags.NONBLOCK) cb_reads = [] def cb(channel, condition): self.assertEqual(channel, ch) self.assertEqual(condition, GLib.IOCondition.IN) cb_reads.append(channel.read()) if len(cb_reads) == 2: ml.quit() return True with warnings.catch_warnings(record=True) as warn: warnings.simplefilter('always') id = GLib.io_add_watch(ch, GLib.IOCondition.IN, cb, priority=GLib.PRIORITY_HIGH) self.assertTrue(issubclass(warn[0].category, PyGIDeprecationWarning)) ml = GLib.MainLoop() self.assertEqual(ml.get_context().find_source_by_id(id).priority, GLib.PRIORITY_HIGH) def write(): os.write(w, b'a') GLib.idle_add(lambda: os.write(w, b'b') and False) GLib.idle_add(write) GLib.timeout_add(2000, ml.quit) ml.run() self.assertEqual(cb_reads, [b'a', b'b']) @unittest.skipIf(os.name == "nt", "NONBLOCK not implemented on Windows") def test_deprecated_add_watch_with_data(self): (r, w) = os.pipe() ch = GLib.IOChannel(filedes=r) ch.set_encoding(None) ch.set_flags(ch.get_flags() | GLib.IOFlags.NONBLOCK) cb_reads = [] def cb(channel, condition, data): self.assertEqual(channel, ch) self.assertEqual(condition, GLib.IOCondition.IN) self.assertEqual(data, 'hello') cb_reads.append(channel.read()) if len(cb_reads) == 2: ml.quit() return True with warnings.catch_warnings(record=True) as warn: warnings.simplefilter('always') id = GLib.io_add_watch(ch, GLib.IOCondition.IN, cb, 'hello', priority=GLib.PRIORITY_HIGH) self.assertTrue(issubclass(warn[0].category, PyGIDeprecationWarning)) ml = GLib.MainLoop() self.assertEqual(ml.get_context().find_source_by_id(id).priority, GLib.PRIORITY_HIGH) def write(): os.write(w, b'a') GLib.idle_add(lambda: os.write(w, b'b') and False) GLib.idle_add(write) GLib.timeout_add(2000, ml.quit) ml.run() self.assertEqual(cb_reads, [b'a', b'b']) def test_backwards_compat_flags(self): with warnings.catch_warnings(): warnings.simplefilter('ignore', PyGIDeprecationWarning) self.assertEqual(GLib.IOCondition.IN, GLib.IO_IN) self.assertEqual(GLib.IOFlags.NONBLOCK, GLib.IO_FLAG_NONBLOCK) self.assertEqual(GLib.IOFlags.IS_SEEKABLE, GLib.IO_FLAG_IS_SEEKABLE) self.assertEqual(GLib.IOStatus.NORMAL, GLib.IO_STATUS_NORMAL) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/tests/test_mainloop.py0000664000000000000000000000346115074674453016743 0ustar00rootroot# -*- Mode: Python -*- import os import select import signal import unittest from gi.repository import GLib from .helper import capture_exceptions class TestMainLoop(unittest.TestCase): @unittest.skipUnless(hasattr(os, "fork"), "no os.fork available") def test_exception_handling(self): pipe_r, pipe_w = os.pipe() pid = os.fork() if pid == 0: os.close(pipe_w) select.select([pipe_r], [], []) os.close(pipe_r) os._exit(1) def child_died(pid, status, loop): loop.quit() raise Exception("deadbabe") loop = GLib.MainLoop() GLib.child_watch_add(GLib.PRIORITY_DEFAULT, pid, child_died, loop) os.close(pipe_r) os.write(pipe_w, b"Y") os.close(pipe_w) with capture_exceptions() as exc: loop.run() assert len(exc) == 1 assert exc[0].type is Exception assert exc[0].value.args[0] == "deadbabe" @unittest.skipUnless(hasattr(os, "fork"), "no os.fork available") @unittest.skipIf(os.environ.get("PYGI_TEST_GDB"), "SIGINT stops gdb") def test_sigint(self): r, w = os.pipe() pid = os.fork() if pid == 0: # wait for the parent process loop to start os.read(r, 1) os.close(r) os.kill(os.getppid(), signal.SIGINT) os._exit(0) def notify_child(): # tell the child that it can kill the parent os.write(w, b"X") os.close(w) GLib.idle_add(notify_child) loop = GLib.MainLoop() try: loop.run() self.fail('expected KeyboardInterrupt exception') except KeyboardInterrupt: pass self.assertFalse(loop.is_running()) os.waitpid(pid, 0) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/tests/test_object_marshaling.py0000664000000000000000000005533215074674453020604 0ustar00rootroot# -*- Mode: Python; py-indent-offset: 4 -*- # vim: tabstop=4 shiftwidth=4 expandtab import unittest import weakref import gc import sys import warnings from gi.repository import GObject from gi.repository import GIMarshallingTests try: from gi.repository import Regress except ImportError: Regress = None class StrongRef(object): # A class that behaves like weakref.ref but holds a strong reference. # This allows re-use of the VFuncsBase by swapping out the ObjectRef # class var with either weakref.ref or StrongRef. def __init__(self, obj): self.obj = obj def __call__(self): return self.obj class VFuncsBase(GIMarshallingTests.Object): # Class which generically implements the vfuncs used for reference counting tests # in a way that can be easily sub-classed and modified. #: Object type used by this class for testing #: This can be GObject.Object or GObject.InitiallyUnowned Object = GObject.Object #: Reference type used by this class for holding refs to in/out objects. #: This can be set to weakref.ref or StrongRef ObjectRef = weakref.ref def __init__(self): super(VFuncsBase, self).__init__() #: Hold ref of input or output python wrappers self.object_ref = None #: store grefcount of input object self.in_object_grefcount = None self.in_object_is_floating = None def do_vfunc_return_object_transfer_none(self): # Return an object but keep a python reference to it. obj = self.Object() self.object_ref = self.ObjectRef(obj) return obj def do_vfunc_return_object_transfer_full(self): # Return an object and hand off the reference to the caller. obj = self.Object() self.object_ref = self.ObjectRef(obj) return obj def do_vfunc_out_object_transfer_none(self): # Same as do_vfunc_return_object_transfer_none but the pygi # internals convert the return here into an out arg. obj = self.Object() self.object_ref = self.ObjectRef(obj) return obj def do_vfunc_out_object_transfer_full(self): # Same as do_vfunc_return_object_transfer_full but the pygi # internals convert the return here into an out arg. obj = self.Object() self.object_ref = self.ObjectRef(obj) return obj def do_vfunc_in_object_transfer_none(self, obj): # 'obj' will have a python wrapper as well as still held # by the caller. self.object_ref = self.ObjectRef(obj) self.in_object_grefcount = obj.__grefcount__ self.in_object_is_floating = obj.is_floating() def do_vfunc_in_object_transfer_full(self, obj): # 'obj' will now be owned by the Python GObject wrapper. # When obj goes out of scope and is collected, the GObject # should also be fully released. self.object_ref = self.ObjectRef(obj) self.in_object_grefcount = obj.__grefcount__ self.in_object_is_floating = obj.is_floating() class TestVFuncsWithObjectArg(unittest.TestCase): # Basic set of tests which work on non-floating objects which python does # not keep an additional reference of. class VFuncs(VFuncsBase): # Object for testing non-floating objects without holding any refs. Object = GObject.Object ObjectRef = weakref.ref def test_vfunc_self_arg_ref_count(self): # Check to make sure vfunc "self" arguments don't leak. vfuncs = self.VFuncs() vfuncs_ref = weakref.ref(vfuncs) vfuncs.get_ref_info_for_vfunc_return_object_transfer_full() # Use any vfunc to test this. gc.collect() if hasattr(sys, "getrefcount"): self.assertEqual(sys.getrefcount(vfuncs), 2) self.assertEqual(vfuncs.__grefcount__, 1) del vfuncs gc.collect() self.assertTrue(vfuncs_ref() is None) def test_vfunc_return_object_transfer_none(self): # This tests a problem case where the vfunc returns a GObject owned solely by Python # but the argument is marked as transfer-none. # In this case pygobject marshaling adds an additional ref and gives a warning # of a potential leak. If this occures it is really a bug in the underlying library # but pygobject tries to react to this in a reasonable way. vfuncs = self.VFuncs() with warnings.catch_warnings(record=True) as warn: warnings.simplefilter('always') ref_count, is_floating = vfuncs.get_ref_info_for_vfunc_out_object_transfer_none() if hasattr(sys, "getrefcount"): self.assertTrue(issubclass(warn[0].category, RuntimeWarning)) # The ref count of the GObject returned to the caller (get_ref_info_for_vfunc_return_object_transfer_none) # should be a single floating ref if hasattr(sys, "getrefcount"): self.assertEqual(ref_count, 1) self.assertFalse(is_floating) gc.collect() self.assertTrue(vfuncs.object_ref() is None) def test_vfunc_out_object_transfer_none(self): # Same as above except uses out arg instead of return vfuncs = self.VFuncs() with warnings.catch_warnings(record=True) as warn: warnings.simplefilter('always') ref_count, is_floating = vfuncs.get_ref_info_for_vfunc_out_object_transfer_none() if hasattr(sys, "getrefcount"): self.assertTrue(issubclass(warn[0].category, RuntimeWarning)) if hasattr(sys, "getrefcount"): self.assertEqual(ref_count, 1) self.assertFalse(is_floating) gc.collect() self.assertTrue(vfuncs.object_ref() is None) def test_vfunc_return_object_transfer_full(self): vfuncs = self.VFuncs() ref_count, is_floating = vfuncs.get_ref_info_for_vfunc_return_object_transfer_full() # The vfunc caller receives full ownership of a single ref which should not # be floating. if hasattr(sys, "getrefcount"): self.assertEqual(ref_count, 1) self.assertFalse(is_floating) gc.collect() self.assertTrue(vfuncs.object_ref() is None) def test_vfunc_out_object_transfer_full(self): # Same as above except uses out arg instead of return vfuncs = self.VFuncs() ref_count, is_floating = vfuncs.get_ref_info_for_vfunc_out_object_transfer_full() if hasattr(sys, "getrefcount"): self.assertEqual(ref_count, 1) self.assertFalse(is_floating) gc.collect() self.assertTrue(vfuncs.object_ref() is None) def test_vfunc_in_object_transfer_none(self): vfuncs = self.VFuncs() ref_count, is_floating = vfuncs.get_ref_info_for_vfunc_in_object_transfer_none(self.VFuncs.Object) gc.collect() self.assertEqual(vfuncs.in_object_grefcount, 2) # initial + python wrapper self.assertFalse(vfuncs.in_object_is_floating) if hasattr(sys, "getrefcount"): self.assertEqual(ref_count, 1) # ensure python wrapper released self.assertFalse(is_floating) gc.collect() gc.collect() self.assertTrue(vfuncs.object_ref() is None) def test_vfunc_in_object_transfer_full(self): vfuncs = self.VFuncs() ref_count, is_floating = vfuncs.get_ref_info_for_vfunc_in_object_transfer_full(self.VFuncs.Object) gc.collect() # python wrapper should take sole ownership of the gobject self.assertEqual(vfuncs.in_object_grefcount, 1) self.assertFalse(vfuncs.in_object_is_floating) # ensure python wrapper took ownership and released, after vfunc was complete if hasattr(sys, "getrefcount"): self.assertEqual(ref_count, 0) self.assertFalse(is_floating) gc.collect() gc.collect() self.assertTrue(vfuncs.object_ref() is None) class TestVFuncsWithFloatingArg(unittest.TestCase): # All tests here work with a floating object by using InitiallyUnowned as the argument class VFuncs(VFuncsBase): # Object for testing non-floating objects without holding any refs. Object = GObject.InitiallyUnowned ObjectRef = weakref.ref @unittest.skipUnless(hasattr(sys, "getrefcount"), "refcount specific") def test_vfunc_return_object_transfer_none_with_floating(self): # Python is expected to return a single floating reference without warning. vfuncs = self.VFuncs() ref_count, is_floating = vfuncs.get_ref_info_for_vfunc_return_object_transfer_none() # The ref count of the GObject returned to the caller (get_ref_info_for_vfunc_return_object_transfer_none) # should be a single floating ref self.assertEqual(ref_count, 1) self.assertTrue(is_floating) gc.collect() self.assertTrue(vfuncs.object_ref() is None) @unittest.skipUnless(hasattr(sys, "getrefcount"), "refcount specific") def test_vfunc_out_object_transfer_none_with_floating(self): # Same as above except uses out arg instead of return vfuncs = self.VFuncs() ref_count, is_floating = vfuncs.get_ref_info_for_vfunc_out_object_transfer_none() self.assertEqual(ref_count, 1) self.assertTrue(is_floating) gc.collect() self.assertTrue(vfuncs.object_ref() is None) def test_vfunc_return_object_transfer_full_with_floating(self): vfuncs = self.VFuncs() ref_count, is_floating = vfuncs.get_ref_info_for_vfunc_return_object_transfer_full() # The vfunc caller receives full ownership of a single ref. if hasattr(sys, "getrefcount"): self.assertEqual(ref_count, 1) self.assertFalse(is_floating) gc.collect() self.assertTrue(vfuncs.object_ref() is None) def test_vfunc_out_object_transfer_full_with_floating(self): # Same as above except uses out arg instead of return vfuncs = self.VFuncs() ref_count, is_floating = vfuncs.get_ref_info_for_vfunc_out_object_transfer_full() if hasattr(sys, "getrefcount"): self.assertEqual(ref_count, 1) self.assertFalse(is_floating) gc.collect() self.assertTrue(vfuncs.object_ref() is None) def test_vfunc_in_object_transfer_none_with_floating(self): vfuncs = self.VFuncs() ref_count, is_floating = vfuncs.get_ref_info_for_vfunc_in_object_transfer_none(self.VFuncs.Object) gc.collect() # python wrapper should maintain the object as floating and add an additional ref self.assertEqual(vfuncs.in_object_grefcount, 2) self.assertTrue(vfuncs.in_object_is_floating) # vfunc caller should only have a single floating ref after the vfunc finishes if hasattr(sys, "getrefcount"): self.assertEqual(ref_count, 1) self.assertTrue(is_floating) gc.collect() gc.collect() self.assertTrue(vfuncs.object_ref() is None) def test_vfunc_in_object_transfer_full_with_floating(self): vfuncs = self.VFuncs() ref_count, is_floating = vfuncs.get_ref_info_for_vfunc_in_object_transfer_full(self.VFuncs.Object) gc.collect() # python wrapper sinks and owns the gobject self.assertEqual(vfuncs.in_object_grefcount, 1) self.assertFalse(vfuncs.in_object_is_floating) # ensure python wrapper took ownership and released if hasattr(sys, "getrefcount"): self.assertEqual(ref_count, 0) self.assertFalse(is_floating) gc.collect() gc.collect() self.assertTrue(vfuncs.object_ref() is None) class TestVFuncsWithHeldObjectArg(unittest.TestCase): # Same tests as TestVFuncsWithObjectArg except we hold # onto the python object reference in all cases. class VFuncs(VFuncsBase): # Object for testing non-floating objects with a held ref. Object = GObject.Object ObjectRef = StrongRef def test_vfunc_return_object_transfer_none_with_held_object(self): vfuncs = self.VFuncs() ref_count, is_floating = vfuncs.get_ref_info_for_vfunc_return_object_transfer_none() # Python holds the single gobject ref in 'vfuncs.object_ref' # Because of this, we do not expect a floating ref or a ref increase. self.assertEqual(ref_count, 1) self.assertFalse(is_floating) # The actual grefcount should stay at 1 even after the vfunc return. self.assertEqual(vfuncs.object_ref().__grefcount__, 1) self.assertFalse(vfuncs.in_object_is_floating) held_object_ref = weakref.ref(vfuncs.object_ref) del vfuncs.object_ref gc.collect() self.assertTrue(held_object_ref() is None) def test_vfunc_out_object_transfer_none_with_held_object(self): vfuncs = self.VFuncs() ref_count, is_floating = vfuncs.get_ref_info_for_vfunc_out_object_transfer_none() self.assertEqual(ref_count, 1) self.assertFalse(is_floating) self.assertEqual(vfuncs.object_ref().__grefcount__, 1) self.assertFalse(vfuncs.in_object_is_floating) held_object_ref = weakref.ref(vfuncs.object_ref) del vfuncs.object_ref gc.collect() self.assertTrue(held_object_ref() is None) def test_vfunc_return_object_transfer_full_with_held_object(self): # The vfunc caller receives full ownership which should not # be floating. However, the held python wrapper also has a ref. vfuncs = self.VFuncs() ref_count, is_floating = vfuncs.get_ref_info_for_vfunc_return_object_transfer_full() # Ref count from the perspective of C after the vfunc is called # The vfunc caller receives a new reference which should not # be floating. However, the held python wrapper also has a ref. self.assertEqual(ref_count, 2) self.assertFalse(is_floating) # Current ref count # The vfunc caller should have decremented its reference. self.assertEqual(vfuncs.object_ref().__grefcount__, 1) held_object_ref = weakref.ref(vfuncs.object_ref) del vfuncs.object_ref gc.collect() self.assertTrue(held_object_ref() is None) def test_vfunc_out_object_transfer_full_with_held_object(self): # Same test as above except uses out arg instead of return vfuncs = self.VFuncs() ref_count, is_floating = vfuncs.get_ref_info_for_vfunc_out_object_transfer_full() # Ref count from the perspective of C after the vfunc is called # The vfunc caller receives a new reference which should not # be floating. However, the held python wrapper also has a ref. self.assertEqual(ref_count, 2) self.assertFalse(is_floating) # Current ref count # The vfunc caller should have decremented its reference. self.assertEqual(vfuncs.object_ref().__grefcount__, 1) held_object_ref = weakref.ref(vfuncs.object_ref()) del vfuncs.object_ref gc.collect() self.assertTrue(held_object_ref() is None) def test_vfunc_in_object_transfer_none_with_held_object(self): vfuncs = self.VFuncs() ref_count, is_floating = vfuncs.get_ref_info_for_vfunc_in_object_transfer_none(self.VFuncs.Object) gc.collect() # Ref count inside vfunc from the perspective of Python self.assertEqual(vfuncs.in_object_grefcount, 2) # initial + python wrapper self.assertFalse(vfuncs.in_object_is_floating) # Ref count from the perspective of C after the vfunc is called self.assertEqual(ref_count, 2) # kept after vfunc + held python wrapper self.assertFalse(is_floating) # Current ref count after C cleans up its reference self.assertEqual(vfuncs.object_ref().__grefcount__, 1) held_object_ref = weakref.ref(vfuncs.object_ref()) del vfuncs.object_ref gc.collect() self.assertTrue(held_object_ref() is None) def test_vfunc_in_object_transfer_full_with_held_object(self): vfuncs = self.VFuncs() ref_count, is_floating = vfuncs.get_ref_info_for_vfunc_in_object_transfer_full(self.VFuncs.Object) gc.collect() # Ref count inside vfunc from the perspective of Python self.assertEqual(vfuncs.in_object_grefcount, 1) # python wrapper takes ownership of the gobject self.assertFalse(vfuncs.in_object_is_floating) # Ref count from the perspective of C after the vfunc is called self.assertEqual(ref_count, 1) self.assertFalse(is_floating) # Current ref count self.assertEqual(vfuncs.object_ref().__grefcount__, 1) held_object_ref = weakref.ref(vfuncs.object_ref()) del vfuncs.object_ref gc.collect() self.assertTrue(held_object_ref() is None) class TestVFuncsWithHeldFloatingArg(unittest.TestCase): # Tests for a floating object which we hold a reference to the python wrapper # on the VFuncs test class. class VFuncs(VFuncsBase): # Object for testing floating objects with a held ref. Object = GObject.InitiallyUnowned ObjectRef = StrongRef def test_vfunc_return_object_transfer_none_with_held_floating(self): # Python holds onto the wrapper which basically means the floating ref # should also be owned by python. vfuncs = self.VFuncs() ref_count, is_floating = vfuncs.get_ref_info_for_vfunc_return_object_transfer_none() # This is a borrowed ref from what is held in python. self.assertEqual(ref_count, 1) self.assertFalse(is_floating) # The actual grefcount should stay at 1 even after the vfunc return. self.assertEqual(vfuncs.object_ref().__grefcount__, 1) held_object_ref = weakref.ref(vfuncs.object_ref) del vfuncs.object_ref gc.collect() self.assertTrue(held_object_ref() is None) def test_vfunc_out_object_transfer_none_with_held_floating(self): # Same as above vfuncs = self.VFuncs() ref_count, is_floating = vfuncs.get_ref_info_for_vfunc_out_object_transfer_none() self.assertEqual(ref_count, 1) self.assertFalse(is_floating) self.assertEqual(vfuncs.object_ref().__grefcount__, 1) held_object_ref = weakref.ref(vfuncs.object_ref) del vfuncs.object_ref gc.collect() self.assertTrue(held_object_ref() is None) def test_vfunc_return_object_transfer_full_with_held_floating(self): vfuncs = self.VFuncs() ref_count, is_floating = vfuncs.get_ref_info_for_vfunc_return_object_transfer_full() # Ref count from the perspective of C after the vfunc is called self.assertEqual(ref_count, 2) self.assertFalse(is_floating) # Current ref count # vfunc wrapper destroyes ref it was given self.assertEqual(vfuncs.object_ref().__grefcount__, 1) held_object_ref = weakref.ref(vfuncs.object_ref) del vfuncs.object_ref gc.collect() self.assertTrue(held_object_ref() is None) def test_vfunc_out_object_transfer_full_with_held_floating(self): # Same test as above except uses out arg instead of return vfuncs = self.VFuncs() ref_count, is_floating = vfuncs.get_ref_info_for_vfunc_out_object_transfer_full() # Ref count from the perspective of C after the vfunc is called self.assertEqual(ref_count, 2) self.assertFalse(is_floating) # Current ref count # vfunc wrapper destroyes ref it was given self.assertEqual(vfuncs.object_ref().__grefcount__, 1) held_object_ref = weakref.ref(vfuncs.object_ref()) del vfuncs.object_ref gc.collect() self.assertTrue(held_object_ref() is None) def test_vfunc_in_floating_transfer_none_with_held_floating(self): vfuncs = self.VFuncs() ref_count, is_floating = vfuncs.get_ref_info_for_vfunc_in_object_transfer_none(self.VFuncs.Object) gc.collect() # Ref count inside vfunc from the perspective of Python self.assertTrue(vfuncs.in_object_is_floating) self.assertEqual(vfuncs.in_object_grefcount, 2) # python wrapper sinks and owns the gobject # Ref count from the perspective of C after the vfunc is called self.assertTrue(is_floating) self.assertEqual(ref_count, 2) # floating + held by wrapper # Current ref count after C cleans up its reference self.assertEqual(vfuncs.object_ref().__grefcount__, 1) held_object_ref = weakref.ref(vfuncs.object_ref()) del vfuncs.object_ref gc.collect() self.assertTrue(held_object_ref() is None) def test_vfunc_in_floating_transfer_full_with_held_floating(self): vfuncs = self.VFuncs() ref_count, is_floating = vfuncs.get_ref_info_for_vfunc_in_object_transfer_full(self.VFuncs.Object) gc.collect() # Ref count from the perspective of C after the vfunc is called self.assertEqual(vfuncs.in_object_grefcount, 1) # python wrapper sinks and owns the gobject self.assertFalse(vfuncs.in_object_is_floating) # Ref count from the perspective of C after the vfunc is called self.assertEqual(ref_count, 1) # held by wrapper self.assertFalse(is_floating) # Current ref count self.assertEqual(vfuncs.object_ref().__grefcount__, 1) held_object_ref = weakref.ref(vfuncs.object_ref()) del vfuncs.object_ref gc.collect() self.assertTrue(held_object_ref() is None) @unittest.skipIf(Regress is None, 'Regress is required') class TestArgumentTypeErrors(unittest.TestCase): def test_object_argument_type_error(self): # ensure TypeError is raised for things which are not GObjects obj = Regress.TestObj() obj.set_bare(GObject.Object()) obj.set_bare(None) self.assertRaises(TypeError, obj.set_bare, object()) self.assertRaises(TypeError, obj.set_bare, 42) self.assertRaises(TypeError, obj.set_bare, 'not an object') def test_instance_argument_error(self): # ensure TypeError is raised for non Regress.TestObj instances. obj = Regress.TestObj() self.assertEqual(Regress.TestObj.instance_method(obj), -1) self.assertRaises(TypeError, Regress.TestObj.instance_method, object()) self.assertRaises(TypeError, Regress.TestObj.instance_method, GObject.Object()) self.assertRaises(TypeError, Regress.TestObj.instance_method, 42) self.assertRaises(TypeError, Regress.TestObj.instance_method, 'not an object') def test_instance_argument_base_type_error(self): # ensure TypeError is raised when a base type is passed to something # expecting a derived type obj = Regress.TestSubObj() self.assertEqual(Regress.TestSubObj.instance_method(obj), 0) self.assertRaises(TypeError, Regress.TestSubObj.instance_method, GObject.Object()) self.assertRaises(TypeError, Regress.TestSubObj.instance_method, Regress.TestObj()) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/tests/test_option.py0000664000000000000000000001070715074674453016436 0ustar00rootroot#!/usr/bin/env python import unittest from gi.repository import GLib from .helper import capture_exceptions class TestOption(unittest.TestCase): def setUp(self): self.parser = GLib.option.OptionParser("NAMES...", description="Option unit test") self.parser.add_option("-t", "--test", help="Unit test option", action="store_false", dest="test", default=True) self.parser.add_option("--g-fatal-warnings", action="store_true", dest="fatal_warnings", help="dummy"), def _create_group(self): def option_callback(option, opt, value, parser): raise Exception("foo") group = GLib.option.OptionGroup( "unittest", "Unit test options", "Show all unittest options", option_list=[ GLib.option.make_option("-f", "-u", "--file", "--unit-file", type="filename", dest="unit_file", help="Unit test option"), GLib.option.make_option("--test-integer", type="int", dest="test_integer", help="Unit integer option"), GLib.option.make_option("--callback-failure-test", action="callback", callback=option_callback, dest="test_integer", help="Unit integer option"), ]) group.add_option("-t", "--test", action="store_false", dest="test", default=True, help="Unit test option") self.parser.add_option_group(group) return group def test_integer(self): self._create_group() options, args = self.parser.parse_args( ["--test-integer", "42", "bla"]) assert options.test_integer == 42 assert args == ["bla"] def test_file(self): self._create_group() options, args = self.parser.parse_args( ["--file", "fn", "bla"]) assert options.unit_file == "fn" assert args == ["bla"] def test_mixed(self): self._create_group() options, args = self.parser.parse_args( ["--file", "fn", "--test-integer", "12", "--test", "--g-fatal-warnings", "nope"]) assert options.unit_file == "fn" assert options.test_integer == 12 assert options.test is False assert options.fatal_warnings is True assert args == ["nope"] def test_parse_args(self): options, args = self.parser.parse_args([]) self.assertFalse(args) options, args = self.parser.parse_args(["foo"]) self.assertEqual(args, ["foo"]) options, args = self.parser.parse_args(["foo", "bar"]) self.assertEqual(args, ["foo", "bar"]) def test_parse_args_double_dash(self): options, args = self.parser.parse_args(["--", "-xxx"]) self.assertEqual(args, ["--", "-xxx"]) def test_parse_args_group(self): group = self._create_group() options, args = self.parser.parse_args( ["--test", "-f", "test"]) self.assertFalse(options.test) self.assertEqual(options.unit_file, "test") self.assertTrue(group.values.test) self.assertFalse(self.parser.values.test) self.assertEqual(group.values.unit_file, "test") self.assertFalse(args) def test_option_value_error(self): self._create_group() self.assertRaises(GLib.option.OptionValueError, self.parser.parse_args, ["--test-integer=text"]) def test_bad_option_error(self): self.assertRaises(GLib.option.BadOptionError, self.parser.parse_args, ["--unknwon-option"]) def test_option_group_constructor(self): self.assertRaises(TypeError, GLib.option.OptionGroup) def test_standard_error(self): self._create_group() with capture_exceptions() as exc: self.parser.parse_args(["--callback-failure-test"]) assert len(exc) == 1 assert exc[0].value.args[0] == "foo" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/tests/test_ossig.py0000664000000000000000000001447515074674453016260 0ustar00rootroot# 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 . from __future__ import absolute_import import os import signal import unittest import threading from contextlib import contextmanager try: from gi.repository import Gtk Gtk_version = Gtk._version except ImportError: Gtk = None Gtk_version = None from gi.repository import Gio, GLib from gi._ossighelper import wakeup_on_signal, register_sigint_fallback class TestOverridesWakeupOnAlarm(unittest.TestCase): @contextmanager def _run_with_timeout(self, timeout, abort_func): failed = [] def fail(): abort_func() failed.append(1) return True fail_id = GLib.timeout_add(timeout, fail) try: yield finally: GLib.source_remove(fail_id) self.assertFalse(failed) def test_basic(self): self.assertEqual(signal.set_wakeup_fd(-1), -1) with wakeup_on_signal(): pass self.assertEqual(signal.set_wakeup_fd(-1), -1) def test_in_thread(self): failed = [] def target(): try: with wakeup_on_signal(): pass except: failed.append(1) t = threading.Thread(target=target) t.start() t.join(5) self.assertFalse(failed) @unittest.skipIf(os.name == "nt", "not on Windows") def test_glib_mainloop(self): loop = GLib.MainLoop() signal.signal(signal.SIGALRM, lambda *args: loop.quit()) GLib.idle_add(signal.setitimer, signal.ITIMER_REAL, 0.001) with self._run_with_timeout(2000, loop.quit): loop.run() @unittest.skipIf(os.name == "nt", "not on Windows") def test_gio_application(self): app = Gio.Application() signal.signal(signal.SIGALRM, lambda *args: app.quit()) GLib.idle_add(signal.setitimer, signal.ITIMER_REAL, 0.001) with self._run_with_timeout(2000, app.quit): app.hold() app.connect("activate", lambda *args: None) app.run() @unittest.skipIf(Gtk is None or os.name == "nt", "not on Windows") @unittest.skipIf(Gtk is None or Gtk_version == "4.0", "not in gtk4") def test_gtk_main(self): signal.signal(signal.SIGALRM, lambda *args: Gtk.main_quit()) GLib.idle_add(signal.setitimer, signal.ITIMER_REAL, 0.001) with self._run_with_timeout(2000, Gtk.main_quit): Gtk.main() @unittest.skipIf(Gtk is None or os.name == "nt", "not on Windows") @unittest.skipIf(Gtk is None or Gtk_version == "4.0", "not in gtk4") def test_gtk_dialog_run(self): w = Gtk.Window() d = Gtk.Dialog(transient_for=w) signal.signal(signal.SIGALRM, lambda *args: d.destroy()) GLib.idle_add(signal.setitimer, signal.ITIMER_REAL, 0.001) with self._run_with_timeout(2000, d.destroy): d.run() class TestSigintFallback(unittest.TestCase): def setUp(self): self.assertEqual( signal.getsignal(signal.SIGINT), signal.default_int_handler) def tearDown(self): self.assertEqual( signal.getsignal(signal.SIGINT), signal.default_int_handler) def test_replace_handler_and_restore_nested(self): with register_sigint_fallback(lambda: None): new_handler = signal.getsignal(signal.SIGINT) self.assertNotEqual(new_handler, signal.default_int_handler) with register_sigint_fallback(lambda: None): self.assertTrue(signal.getsignal(signal.SIGINT) is new_handler) self.assertEqual( signal.getsignal(signal.SIGINT), signal.default_int_handler) def test_no_replace_if_not_default(self): new_handler = lambda *args: None signal.signal(signal.SIGINT, new_handler) try: with register_sigint_fallback(lambda: None): self.assertTrue(signal.getsignal(signal.SIGINT) is new_handler) with register_sigint_fallback(lambda: None): self.assertTrue( signal.getsignal(signal.SIGINT) is new_handler) self.assertTrue(signal.getsignal(signal.SIGINT) is new_handler) finally: signal.signal(signal.SIGINT, signal.default_int_handler) def test_noop_in_threads(self): failed = [] def target(): try: with register_sigint_fallback(lambda: None): with register_sigint_fallback(lambda: None): self.assertTrue( signal.getsignal(signal.SIGINT) is signal.default_int_handler) except: failed.append(1) t = threading.Thread(target=target) t.start() t.join(5) self.assertFalse(failed) @unittest.skipIf(os.name == "nt", "not on Windows") def test_no_replace_if_set_by_glib(self): id_ = GLib.unix_signal_add( GLib.PRIORITY_DEFAULT, signal.SIGINT, lambda *args: None) try: # signal.getsignal() doesn't pick up that unix_signal_add() # has changed the handler, but we should anyway. self.assertEqual( signal.getsignal(signal.SIGINT), signal.default_int_handler) with register_sigint_fallback(lambda: None): self.assertEqual( signal.getsignal(signal.SIGINT), signal.default_int_handler) self.assertEqual( signal.getsignal(signal.SIGINT), signal.default_int_handler) finally: GLib.source_remove(id_) signal.signal(signal.SIGINT, signal.SIG_DFL) signal.signal(signal.SIGINT, signal.default_int_handler) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/tests/test_overrides_gdk.py0000664000000000000000000003001515074674453017747 0ustar00rootroot# -*- Mode: Python; py-indent-offset: 4 -*- # vim: tabstop=4 shiftwidth=4 expandtab import re import os import sys import unittest import pytest import gi import gi.overrides from gi import PyGIDeprecationWarning try: from gi.repository import Gio, Gdk, GdkPixbuf, Gtk GDK4 = Gdk._version == "4.0" except ImportError: Gdk = None Gtk = None GDK4 = False def gtkver(): if Gtk is None: return (0, 0, 0) return (Gtk.get_major_version(), Gtk.get_minor_version(), Gtk.get_micro_version()) try: gi.require_foreign('cairo') has_cairo = True except ImportError: has_cairo = False from .helper import capture_glib_deprecation_warnings @unittest.skipUnless(Gdk, 'Gdk not available') class TestGdk(unittest.TestCase): @unittest.skipIf(sys.platform == "darwin" or os.name == "nt", "crashes") @unittest.skipIf(GDK4, "not in gdk4") def test_constructor(self): attribute = Gdk.WindowAttr() attribute.window_type = Gdk.WindowType.CHILD attributes_mask = Gdk.WindowAttributesType.X | \ Gdk.WindowAttributesType.Y window = Gdk.Window(None, attribute, attributes_mask) self.assertEqual(window.get_window_type(), Gdk.WindowType.CHILD) @unittest.skipIf(GDK4, "not in gdk4") def test_color(self): color = Gdk.Color(100, 200, 300) self.assertEqual(color.red, 100) self.assertEqual(color.green, 200) self.assertEqual(color.blue, 300) with capture_glib_deprecation_warnings(): self.assertEqual(color, Gdk.Color(100, 200, 300)) self.assertNotEqual(color, Gdk.Color(1, 2, 3)) self.assertNotEqual(color, None) # assertNotEqual only tests __ne__. Following line explicitly # tests __eq__ with objects of other types self.assertFalse(color == object()) @unittest.skipIf(GDK4, "not in gdk4") def test_color_floats(self): self.assertEqual(Gdk.Color(13107, 21845, 65535), Gdk.Color.from_floats(0.2, 1.0 / 3.0, 1.0)) self.assertEqual(Gdk.Color(13107, 21845, 65535).to_floats(), (0.2, 1.0 / 3.0, 1.0)) self.assertEqual(Gdk.RGBA(0.2, 1.0 / 3.0, 1.0, 0.5).to_color(), Gdk.Color.from_floats(0.2, 1.0 / 3.0, 1.0)) self.assertEqual(Gdk.RGBA.from_color(Gdk.Color(13107, 21845, 65535)), Gdk.RGBA(0.2, 1.0 / 3.0, 1.0, 1.0)) @unittest.skipIf(GDK4, "not in gdk4") def test_color_to_floats_attrs(self): color = Gdk.Color(13107, 21845, 65535) assert color.red_float == 0.2 color.red_float = 0 assert color.red_float == 0 assert color.green_float == 1.0 / 3.0 color.green_float = 0 assert color.green_float == 0 assert color.blue_float == 1.0 color.blue_float = 0 assert color.blue_float == 0 @unittest.skipIf(GDK4, "not in gdk4") def test_rgba(self): self.assertEqual(Gdk.RGBA, gi.overrides.Gdk.RGBA) rgba = Gdk.RGBA(0.1, 0.2, 0.3, 0.4) self.assertEqual(rgba, Gdk.RGBA(0.1, 0.2, 0.3, 0.4)) self.assertNotEqual(rgba, Gdk.RGBA(0.0, 0.2, 0.3, 0.4)) self.assertEqual(rgba.red, 0.1) self.assertEqual(rgba.green, 0.2) self.assertEqual(rgba.blue, 0.3) self.assertEqual(rgba.alpha, 0.4) rgba.green = 0.9 self.assertEqual(rgba.green, 0.9) self.assertNotEqual(rgba, None) # assertNotEqual only tests __ne__. Following line explicitly # tests __eq__ with objects of other types self.assertFalse(rgba == object()) # Iterator/tuple convsersion self.assertEqual(tuple(Gdk.RGBA(0.1, 0.2, 0.3, 0.4)), (0.1, 0.2, 0.3, 0.4)) @unittest.skipUnless(GDK4, "only in gdk4") def test_rgba_gtk4(self): c = Gdk.RGBA() assert c.to_string() == "rgba(0,0,0,0)" @unittest.skipIf(not has_cairo or GDK4, "not in gdk4") def test_window(self): w = Gtk.Window() w.realize() window = w.get_window() with capture_glib_deprecation_warnings(): assert window.cairo_create() is not None @unittest.skipIf(GDK4, "not in gdk4") def test_drag_context(self): context = Gdk.DragContext() # using it this way crashes.. assert hasattr(context, "finish") @unittest.skipIf(GDK4, "not in gdk4") def test_event(self): event = Gdk.Event.new(Gdk.EventType.CONFIGURE) self.assertEqual(event.type, Gdk.EventType.CONFIGURE) self.assertEqual(event.send_event, 0) event = Gdk.Event() event.type = Gdk.EventType.SCROLL self.assertRaises(AttributeError, lambda: getattr(event, 'foo_bar')) @unittest.skipIf(GDK4, "not in gdk4") def test_scroll_event(self): event = Gdk.Event.new(Gdk.EventType.SCROLL) assert event.direction == Gdk.ScrollDirection.UP @unittest.skipIf(GDK4, "not in gdk4") def test_event_strip_boolean(self): ev = Gdk.EventButton() ev.type = Gdk.EventType.BUTTON_PRESS assert ev.get_coords() == (0.0, 0.0) # https://gitlab.gnome.org/GNOME/pygobject/issues/85 ev = Gdk.Event.new(Gdk.EventType.BUTTON_PRESS) assert ev.get_coords() == (True, 0.0, 0.0) @unittest.skipIf(GDK4, "not in gdk4") def test_event_touch(self): event = Gdk.Event.new(Gdk.EventType.TOUCH_BEGIN) self.assertEqual(event.type, Gdk.EventType.TOUCH_BEGIN) # emulating_pointer is unique to touch events self.assertFalse(event.emulating_pointer) self.assertFalse(event.touch.emulating_pointer) event.emulating_pointer = True self.assertTrue(event.emulating_pointer) self.assertTrue(event.touch.emulating_pointer) @unittest.skipIf(GDK4, "not in gdk4") def test_event_setattr(self): event = Gdk.Event.new(Gdk.EventType.DRAG_MOTION) event.x_root, event.y_root = 0, 5 self.assertEqual(event.dnd.x_root, 0) self.assertEqual(event.dnd.y_root, 5) self.assertEqual(event.x_root, 0) self.assertEqual(event.y_root, 5) # this used to work, keep it that way self.assertFalse(hasattr(event, "foo_bar")) event.foo_bar = 42 # unhandled type event.type = Gdk.EventType.EVENT_LAST with pytest.raises(AttributeError): event.foo_bar event.foo_bar = 42 assert event.foo_bar == 42 @unittest.skipIf(GDK4, "not in gdk4") def test_event_repr(self): event = Gdk.Event.new(Gdk.EventType.CONFIGURE) self.assertTrue("CONFIGURE" in repr(event)) @unittest.skipIf(GDK4, "not in gdk4") def test_event_structures(self): def button_press_cb(button, event): self.assertTrue(isinstance(event, Gdk.EventButton)) self.assertTrue(event.type == Gdk.EventType.BUTTON_PRESS) self.assertEqual(event.send_event, 0) self.assertEqual(event.get_state(), Gdk.ModifierType.CONTROL_MASK) self.assertEqual(event.get_root_coords(), (2, 5)) event.time = 12345 self.assertEqual(event.get_time(), 12345) w = Gtk.Window() b = Gtk.Button() b.connect('button-press-event', button_press_cb) w.add(b) b.show() b.realize() Gdk.test_simulate_button(b.get_window(), 2, 5, 0, Gdk.ModifierType.CONTROL_MASK, Gdk.EventType.BUTTON_PRESS) @unittest.skipIf(GDK4, "not in gdk4") def test_cursor(self): self.assertEqual(Gdk.Cursor, gi.overrides.Gdk.Cursor) with capture_glib_deprecation_warnings(): c = Gdk.Cursor(Gdk.CursorType.WATCH) self.assertNotEqual(c, None) with capture_glib_deprecation_warnings(): c = Gdk.Cursor(cursor_type=Gdk.CursorType.WATCH) self.assertNotEqual(c, None) display_manager = Gdk.DisplayManager.get() display = display_manager.get_default_display() test_pixbuf = GdkPixbuf.Pixbuf.new(GdkPixbuf.Colorspace.RGB, False, 8, 5, 10) with capture_glib_deprecation_warnings() as warn: c = Gdk.Cursor(display, test_pixbuf, y=0, x=0) self.assertNotEqual(c, None) self.assertEqual(len(warn), 1) self.assertTrue(issubclass(warn[0].category, PyGIDeprecationWarning)) self.assertRegex(str(warn[0].message), '.*new_from_pixbuf.*') self.assertRaises(ValueError, Gdk.Cursor, 1, 2, 3) with capture_glib_deprecation_warnings() as warn: c = Gdk.Cursor(display, Gdk.CursorType.WATCH) assert len(warn) == 1 # on macOS the type is switched to PIXMAP behind the scenes assert c.props.cursor_type in ( Gdk.CursorType.WATCH, Gdk.CursorType.CURSOR_IS_PIXMAP) assert c.props.display == display @unittest.skipUnless(GDK4, "only gdk4") def test_cursor_gdk4(self): Gdk.Cursor() Gdk.Cursor(name="foo") Gdk.Cursor(fallback=Gdk.Cursor()) def test_flags(self): self.assertEqual(Gdk.ModifierType.META_MASK | 0, 0x10000000) self.assertEqual(hex(Gdk.ModifierType.META_MASK), '0x10000000') self.assertEqual(str(Gdk.ModifierType.META_MASK), '') # RELEASE_MASK does not exist in gdk4 if not GDK4: self.assertEqual(Gdk.ModifierType.RELEASE_MASK | 0, 0x40000000) self.assertEqual(hex(Gdk.ModifierType.RELEASE_MASK), '0x40000000') self.assertEqual(str(Gdk.ModifierType.RELEASE_MASK), '') self.assertEqual(Gdk.ModifierType.RELEASE_MASK | Gdk.ModifierType.META_MASK, 0x50000000) self.assertEqual(str(Gdk.ModifierType.RELEASE_MASK | Gdk.ModifierType.META_MASK), '') @unittest.skipIf(GDK4, "not in gdk4") def test_color_parse(self): with capture_glib_deprecation_warnings(): c = Gdk.color_parse('#00FF80') self.assertEqual(c.red, 0) self.assertEqual(c.green, 65535) self.assertEqual(c.blue, 32896) self.assertEqual(Gdk.color_parse('bogus'), None) @unittest.skipIf(GDK4, "not in gdk4") def test_color_representations(self): # __repr__ should generate a string which is parsable when possible # http://docs.python.org/2/reference/datamodel.html#object.__repr__ color = Gdk.Color(red=65535, green=32896, blue=1) self.assertEqual(eval(repr(color)), color) rgba = Gdk.RGBA(red=1.0, green=0.8, blue=0.6, alpha=0.4) self.assertEqual(eval(repr(rgba)), rgba) @unittest.skipIf(GDK4, "not in gdk4") def test_rectangle_functions(self): # https://bugzilla.gnome.org/show_bug.cgi?id=756364 a = Gdk.Rectangle() b = Gdk.Rectangle() self.assertTrue(isinstance(Gdk.rectangle_union(a, b), Gdk.Rectangle)) intersect, rect = Gdk.rectangle_intersect(a, b) self.assertTrue(isinstance(rect, Gdk.Rectangle)) self.assertTrue(isinstance(intersect, bool)) @unittest.skipIf(GDK4, "not in gdk4") def test_atom_repr_str(self): atom = Gdk.atom_intern("", True) assert re.match(r"", repr(atom)) assert re.match(r"Gdk.Atom<\d+>", str(atom)) @unittest.skipUnless(GDK4, "only in gdk4") @unittest.skipUnless(gtkver() >= (4, 8, 0), "constructor available since 4.8") def test_file_list(self): f = Gio.File.new_for_path("/tmp") filelist = Gdk.FileList([f]) self.assertTrue(isinstance(filelist, Gdk.FileList)) self.assertEqual(len(filelist), 1) self.assertEqual(filelist[0], f) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/tests/test_overrides_gdkpixbuf.py0000664000000000000000000000362015074674453021167 0ustar00rootroot# Copyright 2018 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, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 # USA import pytest from gi import PyGIDeprecationWarning GdkPixbuf = pytest.importorskip("gi.repository.GdkPixbuf") def test_new_from_data(): width = 600 height = 32769 pixbuf = GdkPixbuf.Pixbuf.new( GdkPixbuf.Colorspace.RGB, True, 8, width, height) pixels = pixbuf.get_pixels() new_pixbuf = GdkPixbuf.Pixbuf.new_from_data( pixels, GdkPixbuf.Colorspace.RGB, True, 8, pixbuf.get_width(), pixbuf.get_height(), pixbuf.get_rowstride()) del pixbuf del pixels new_pixels = new_pixbuf.get_pixels() assert len(new_pixels) == width * height * 4 def test_new_from_data_deprecated_args(): GdkPixbuf.Pixbuf.new_from_data(b"1234", 0, True, 8, 1, 1, 4) GdkPixbuf.Pixbuf.new_from_data(b"1234", 0, True, 8, 1, 1, 4, None) with pytest.warns(PyGIDeprecationWarning, match=".*destroy_fn.*"): GdkPixbuf.Pixbuf.new_from_data( b"1234", 0, True, 8, 1, 1, 4, object(), object(), object()) with pytest.warns(PyGIDeprecationWarning, match=".*destroy_fn_data.*"): GdkPixbuf.Pixbuf.new_from_data( b"1234", 0, True, 8, 1, 1, 4, object(), object(), object()) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/tests/test_overrides_gio.py0000664000000000000000000002633115074674453017766 0ustar00rootrootimport os import platform import random import warnings import pytest from gi.repository import Gio, GLib, GObject from gi import PyGIWarning class Item(GObject.Object): _id = 0 def __init__(self, **kwargs): super(Item, self).__init__(**kwargs) Item._id += 1 self._id = self._id def __repr__(self): return str(self._id) class NamedItem(Item): name = GObject.Property(type=str, default='') def __repr__(self): return self.props.name def test_list_store_sort(): store = Gio.ListStore() items = [NamedItem(name=n) for n in "cabx"] sorted_items = sorted(items, key=lambda i: i.props.name) user_data = [object(), object()] def sort_func(a, b, *args): assert list(args) == user_data assert isinstance(a, NamedItem) assert isinstance(b, NamedItem) cmp = lambda a, b: (a > b) - (a < b) return cmp(a.props.name, b.props.name) store[:] = items assert store[:] != sorted_items store.sort(sort_func, *user_data) assert store[:] == sorted_items def test_list_store_insert_sorted(): store = Gio.ListStore() items = [NamedItem(name=n) for n in "cabx"] sorted_items = sorted(items, key=lambda i: i.props.name) user_data = [object(), object()] def sort_func(a, b, *args): assert list(args) == user_data assert isinstance(a, NamedItem) assert isinstance(b, NamedItem) cmp = lambda a, b: (a > b) - (a < b) return cmp(a.props.name, b.props.name) for item in items: index = store.insert_sorted(item, sort_func, *user_data) assert isinstance(index, int) assert store[:] == sorted_items def test_list_model_len(): model = Gio.ListStore.new(Item) assert len(model) == 0 assert not model for i in range(1, 10): model.append(Item()) assert len(model) == i assert model model.remove_all() assert not model assert len(model) == 0 def test_list_model_get_item_simple(): model = Gio.ListStore.new(Item) with pytest.raises(IndexError): model[0] first_item = Item() model.append(first_item) assert model[0] is first_item assert model[-1] is first_item second_item = Item() model.append(second_item) assert model[1] is second_item assert model[-1] is second_item assert model[-2] is first_item with pytest.raises(IndexError): model[-3] with pytest.raises(TypeError): model[object()] def test_list_model_get_item_slice(): model = Gio.ListStore.new(Item) source = [Item() for i in range(30)] for i in source: model.append(i) assert model[1:10] == source[1:10] assert model[1:-2] == source[1:-2] assert model[-4:-1] == source[-4:-1] assert model[-100:-1] == source[-100:-1] assert model[::-1] == source[::-1] assert model[:] == source[:] def test_list_model_contains(): model = Gio.ListStore.new(Item) item = Item() model.append(item) assert item in model assert Item() not in model with pytest.raises(TypeError): object() in model with pytest.raises(TypeError): None in model def test_list_model_iter(): model = Gio.ListStore.new(Item) item = Item() model.append(item) it = iter(model) assert next(it) is item repr(item) def test_list_store_delitem_simple(): store = Gio.ListStore.new(Item) store.append(Item()) del store[0] assert not store with pytest.raises(IndexError): del store[0] with pytest.raises(IndexError): del store[-1] store.append(Item()) with pytest.raises(IndexError): del store[-2] del store[-1] assert not store source = [Item(), Item()] store.append(source[0]) store.append(source[1]) del store[-1] assert store[:] == [source[0]] with pytest.raises(TypeError): del store[object()] def test_list_store_delitem_slice(): def do_del(count, key): events = [] def on_changed(m, *args): events.append(args) store = Gio.ListStore.new(Item) source = [Item() for i in range(count)] for item in source: store.append(item) store.connect("items-changed", on_changed) source.__delitem__(key) store.__delitem__(key) assert source == store[:] return events values = [None, 1, -15, 3, -2, 0, -3, 5, 7] variants = set() for i in range(500): start = random.choice(values) stop = random.choice(values) step = random.choice(values) length = abs(random.choice(values) or 0) if step == 0: step += 1 variants.add((length, start, stop, step)) for length, start, stop, step in variants: do_del(length, slice(start, stop, step)) # basics do_del(10, slice(None, None, None)) do_del(10, slice(None, None, None)) do_del(10, slice(None, None, -1)) do_del(10, slice(0, 5, None)) do_del(10, slice(0, 10, 1)) do_del(10, slice(0, 10, 2)) do_del(10, slice(14, 2, -1)) # test some fast paths assert do_del(100, slice(None, None, None)) == [(0, 100, 0)] assert do_del(100, slice(None, None, -1)) == [(0, 100, 0)] assert do_del(100, slice(0, 50, 1)) == [(0, 50, 0)] def test_list_store_setitem_simple(): store = Gio.ListStore.new(Item) first = Item() store.append(first) class Wrong(GObject.Object): pass with pytest.raises(TypeError): store[0] = object() with pytest.raises(TypeError): store[0] = None with pytest.raises(TypeError): store[0] = Wrong() assert store[:] == [first] new = Item() store[0] = new assert len(store) == 1 store[-1] = Item() assert len(store) == 1 with pytest.raises(IndexError): store[1] = Item() with pytest.raises(IndexError): store[-2] = Item() store = Gio.ListStore.new(Item) source = [Item(), Item(), Item()] for item in source: store.append(item) new = Item() store[1] = new assert store[:] == [source[0], new, source[2]] with pytest.raises(TypeError): store[object()] = Item() def test_list_store_setitem_slice(): def do_set(count, key, new_count): if count == 0 and key.step is not None \ and platform.python_implementation() == "PyPy": # https://foss.heptapod.net/pypy/pypy/-/issues/2804 return store = Gio.ListStore.new(Item) source = [Item() for i in range(count)] new = [Item() for i in range(new_count)] for item in source: store.append(item) source_error = None try: source.__setitem__(key, new) except ValueError as e: source_error = type(e) store_error = None try: store.__setitem__(key, new) except Exception as e: store_error = type(e) assert source_error == store_error assert source == store[:] values = [None, 1, -15, 3, -2, 0, 3, 4, 100] variants = set() for i in range(500): start = random.choice(values) stop = random.choice(values) step = random.choice(values) length = abs(random.choice(values) or 0) new = random.choice(values) or 0 if step == 0: step += 1 variants.add((length, start, stop, step, new)) for length, start, stop, step, new in variants: do_set(length, slice(start, stop, step), new) # basics do_set(10, slice(None, None, None), 20) do_set(10, slice(None, None, None), 0) do_set(10, slice(None, None, -1), 20) do_set(10, slice(None, None, -1), 10) do_set(10, slice(0, 5, None), 20) do_set(10, slice(0, 10, 1), 0) # test iterators store = Gio.ListStore.new(Item) store[:] = iter([Item() for i in range(10)]) assert len(store) == 10 # make sure we do all or nothing store = Gio.ListStore.new(Item) with pytest.raises(TypeError): store[:] = [Item(), object()] assert len(store) == 0 def test_action_map_add_action_entries(): actionmap = Gio.SimpleActionGroup() test_data = [] def f(action, parameter, data): test_data.append('test back') actionmap.add_action_entries(( ("simple", f), ("with_type", f, "i"), ("with_state", f, "s", "'left'", f), )) assert actionmap.has_action("simple") assert actionmap.has_action("with_type") assert actionmap.has_action("with_state") actionmap.add_action_entries(( ("with_user_data", f), ), "user_data") assert actionmap.has_action("with_user_data") with pytest.raises(TypeError): actionmap.add_action_entries(( ("invaild_type_string", f, 'asdf'), )) with pytest.raises(ValueError): actionmap.add_action_entries(( ("stateless_with_change_state", f, None, None, f), )) actionmap.activate_action("simple") assert test_data[0] == 'test back' def test_types_init_warn(): types = [ Gio.DBusAnnotationInfo, Gio.DBusArgInfo, Gio.DBusMethodInfo, Gio.DBusSignalInfo, Gio.DBusInterfaceInfo, Gio.DBusNodeInfo, ] for t in types: with warnings.catch_warnings(record=True) as warn: warnings.simplefilter('always') t() assert issubclass(warn[0].category, PyGIWarning) def test_file_fspath(): file, stream = Gio.File.new_tmp('TestGFile.XXXXXX') content = b'hello\0world\x7F!' stream.get_output_stream().write_bytes(GLib.Bytes(content)) stream.close() path = file.peek_path() assert isinstance(path, str) fspath = file.__fspath__() assert isinstance(fspath, str) assert fspath == path with open(file, 'rb') as file_like: assert file_like.read() == content def test_file_fspath_with_no_path(): file = Gio.File.new_for_path('') path = file.peek_path() # In older versions of GLib, creating a GFile for an empty path will result # in one representing the current pwd instead of a GDummyFile with no path. if path is None: with pytest.raises(TypeError): file.__fspath__() else: assert path == file.__fspath__() assert path == os.getcwd() @pytest.mark.skipif( not hasattr(Gio.ListStore, "find_with_equal_func_full"), reason="ListStore.find_with_equal_func_full() is available in Gio 2.74" ) def test_list_store_find_with_equal_func(): def test(*user_data): class TestObject(GObject.Object): def __init__(self, val): super().__init__() self.val = val NUM = 5 data = [TestObject(i) for i in range(NUM)] list_store = Gio.ListStore() for d in data: list_store.append(d) def equal_func(a, b, *data): assert data == user_data return a.val == b.val for i in range(NUM): res, position = (list_store.find_with_equal_func( data[i], equal_func, *user_data )) assert res assert position == i not_in_list_store = TestObject(NUM + 1) res, position = (list_store.find_with_equal_func( not_in_list_store, equal_func, *user_data )) assert not res test() test((100, "data")) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/tests/test_overrides_glib.py0000664000000000000000000006624615074674453020136 0ustar00rootroot# -*- Mode: Python; py-indent-offset: 4 -*- # vim: tabstop=4 shiftwidth=4 expandtab import os import gc import unittest import tempfile import socket import pytest import gi from gi.repository import GLib from .helper import capture_gi_deprecation_warnings def test_io_add_watch_get_args(): get_args = GLib._io_add_watch_get_args func = lambda: None # create a closed channel for testing fd, fn = tempfile.mkstemp() os.close(fd) try: chan = GLib.IOChannel(filename=fn) chan.shutdown(True) finally: os.remove(fn) # old way with capture_gi_deprecation_warnings(): assert get_args(chan, GLib.IOCondition.IN, func) == ( chan, 0, GLib.IOCondition.IN, func, tuple()) with pytest.raises(TypeError): get_args(chan, GLib.IOCondition.IN, object()) # new way prio = GLib.PRIORITY_DEFAULT with capture_gi_deprecation_warnings(): assert get_args(chan, prio, GLib.IOCondition.IN, func, 99) == \ (chan, prio, GLib.IOCondition.IN, func, (99,)) with pytest.raises(TypeError): assert get_args(chan, prio, GLib.IOCondition.IN) with pytest.raises(TypeError): assert get_args(chan, prio, 99) @pytest.mark.skipif(os.name != "nt", reason="windows only") def test_io_add_watch_get_args_win32_socket(): get_args = GLib._io_add_watch_get_args s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) func = lambda: None prio = GLib.PRIORITY_DEFAULT chan = get_args(s, prio, GLib.IOCondition.IN, func)[0] assert isinstance(chan, GLib.IOChannel) chan.shutdown(False) def test_threads_init(): with capture_gi_deprecation_warnings() as w: GLib.threads_init() assert len(w) def test_gerror_matches(): e = GLib.Error(domain=42, code=24) assert e.matches(42, 24) def test_timeout_add_seconds(): h = GLib.timeout_add_seconds( 100, lambda *x: None, 1, 2, 3, priority=GLib.PRIORITY_HIGH_IDLE) GLib.source_remove(h) def test_iochannel(): with pytest.raises(TypeError): GLib.IOChannel() def test_iochannel_write(): fd, fn = tempfile.mkstemp() os.close(fd) chan = GLib.IOChannel(filename=fn, mode="r+") try: assert chan.write(b"foo", 2) == 2 chan.seek(0) assert chan.read() == b"fo" finally: chan.shutdown(True) @pytest.mark.skipif(os.name == "nt", reason="unix only") def test_has_unix_signal_add(): with capture_gi_deprecation_warnings(): GLib.unix_signal_add == GLib.unix_signal_add_full @pytest.mark.skipif(os.name != "nt", reason="windows only") def test_iochannel_win32(): fd, fn = tempfile.mkstemp() closed = False try: channel = GLib.IOChannel(hwnd=fd) try: assert channel.read() == b"" finally: closed = True channel.shutdown(True) finally: if not closed: os.close(fd) os.remove(fn) class TestGVariant(unittest.TestCase): def test_create_simple(self): variant = GLib.Variant('i', 42) self.assertTrue(isinstance(variant, GLib.Variant)) self.assertEqual(variant.get_int32(), 42) variant = GLib.Variant('s', '') self.assertTrue(isinstance(variant, GLib.Variant)) self.assertEqual(variant.get_string(), '') variant = GLib.Variant('s', 'hello') self.assertTrue(isinstance(variant, GLib.Variant)) self.assertEqual(variant.get_string(), 'hello') def test_simple_invalid_ops(self): variant = GLib.Variant('i', 42) with pytest.raises(TypeError): len(variant) with pytest.raises(TypeError): variant[0] with pytest.raises(TypeError): variant.keys() def test_create_variant(self): variant = GLib.Variant('v', GLib.Variant('i', 42)) self.assertTrue(isinstance(variant, GLib.Variant)) self.assertTrue(isinstance(variant.get_variant(), GLib.Variant)) self.assertEqual(variant.get_type_string(), 'v') self.assertEqual(variant.get_variant().get_type_string(), 'i') self.assertEqual(variant.get_variant().get_int32(), 42) variant = GLib.Variant('v', GLib.Variant('v', GLib.Variant('i', 42))) self.assertEqual(variant.get_type_string(), 'v') self.assertEqual(variant.get_variant().get_type_string(), 'v') self.assertEqual(variant.get_variant().get_variant().get_type_string(), 'i') self.assertEqual(variant.get_variant().get_variant().get_int32(), 42) def test_create_tuple(self): variant = GLib.Variant('()', ()) self.assertEqual(variant.get_type_string(), '()') self.assertEqual(variant.n_children(), 0) variant = GLib.Variant('(i)', (3,)) self.assertEqual(variant.get_type_string(), '(i)') self.assertTrue(isinstance(variant, GLib.Variant)) self.assertEqual(variant.n_children(), 1) self.assertTrue(isinstance(variant.get_child_value(0), GLib.Variant)) self.assertEqual(variant.get_child_value(0).get_int32(), 3) variant = GLib.Variant('(ss)', ('mec', 'mac')) self.assertEqual(variant.get_type_string(), '(ss)') self.assertTrue(isinstance(variant, GLib.Variant)) self.assertTrue(isinstance(variant.get_child_value(0), GLib.Variant)) self.assertTrue(isinstance(variant.get_child_value(1), GLib.Variant)) self.assertEqual(variant.get_child_value(0).get_string(), 'mec') self.assertEqual(variant.get_child_value(1).get_string(), 'mac') # nested tuples variant = GLib.Variant('((si)(ub))', (('hello', -1), (42, True))) self.assertEqual(variant.get_type_string(), '((si)(ub))') self.assertEqual(variant.unpack(), (('hello', -1), (42, True))) def test_new_tuple_sink(self): # https://bugzilla.gnome.org/show_bug.cgi?id=735166 variant = GLib.Variant.new_tuple(GLib.Variant.new_tuple()) del variant gc.collect() def test_create_dictionary(self): variant = GLib.Variant('a{si}', {}) self.assertTrue(isinstance(variant, GLib.Variant)) self.assertEqual(variant.get_type_string(), 'a{si}') self.assertEqual(variant.n_children(), 0) variant = GLib.Variant('a{si}', {'': 1, 'key1': 2, 'key2': 3}) self.assertEqual(variant.get_type_string(), 'a{si}') self.assertTrue(isinstance(variant, GLib.Variant)) self.assertTrue(isinstance(variant.get_child_value(0), GLib.Variant)) self.assertTrue(isinstance(variant.get_child_value(1), GLib.Variant)) self.assertTrue(isinstance(variant.get_child_value(2), GLib.Variant)) self.assertEqual(variant.unpack(), {'': 1, 'key1': 2, 'key2': 3}) # nested dictionaries variant = GLib.Variant('a{sa{si}}', {}) self.assertTrue(isinstance(variant, GLib.Variant)) self.assertEqual(variant.get_type_string(), 'a{sa{si}}') self.assertEqual(variant.n_children(), 0) d = {'': {'': 1, 'keyn1': 2}, 'key1': {'key11': 11, 'key12': 12}} variant = GLib.Variant('a{sa{si}}', d) self.assertEqual(variant.get_type_string(), 'a{sa{si}}') self.assertTrue(isinstance(variant, GLib.Variant)) self.assertEqual(variant.unpack(), d) # init with an iterable variant = GLib.Variant('a{si}', [("foo", 2)]) assert variant.unpack() == {'foo': 2} with pytest.raises(TypeError): GLib.Variant('a{si}', [("foo",)]) with pytest.raises(TypeError): GLib.Variant('a{si}', [("foo", 1, 2)]) def test_create_array(self): variant = GLib.Variant('ai', []) self.assertEqual(variant.get_type_string(), 'ai') self.assertEqual(variant.n_children(), 0) variant = GLib.Variant('ai', [1, 2]) self.assertEqual(variant.get_type_string(), 'ai') self.assertTrue(isinstance(variant, GLib.Variant)) self.assertTrue(isinstance(variant.get_child_value(0), GLib.Variant)) self.assertTrue(isinstance(variant.get_child_value(1), GLib.Variant)) self.assertEqual(variant.get_child_value(0).get_int32(), 1) self.assertEqual(variant.get_child_value(1).get_int32(), 2) variant = GLib.Variant('as', []) self.assertEqual(variant.get_type_string(), 'as') self.assertEqual(variant.n_children(), 0) variant = GLib.Variant('as', ['']) self.assertEqual(variant.get_type_string(), 'as') self.assertTrue(isinstance(variant, GLib.Variant)) self.assertTrue(isinstance(variant.get_child_value(0), GLib.Variant)) self.assertEqual(variant.get_child_value(0).get_string(), '') variant = GLib.Variant('as', ['hello', 'world']) self.assertEqual(variant.get_type_string(), 'as') self.assertTrue(isinstance(variant, GLib.Variant)) self.assertTrue(isinstance(variant.get_child_value(0), GLib.Variant)) self.assertTrue(isinstance(variant.get_child_value(1), GLib.Variant)) self.assertEqual(variant.get_child_value(0).get_string(), 'hello') self.assertEqual(variant.get_child_value(1).get_string(), 'world') # nested arrays variant = GLib.Variant('aai', []) self.assertEqual(variant.get_type_string(), 'aai') self.assertEqual(variant.n_children(), 0) variant = GLib.Variant('aai', [[]]) self.assertEqual(variant.get_type_string(), 'aai') self.assertEqual(variant.n_children(), 1) self.assertEqual(variant.get_child_value(0).n_children(), 0) variant = GLib.Variant('aai', [[1, 2], [3, 4, 5]]) self.assertEqual(variant.get_type_string(), 'aai') self.assertEqual(variant.unpack(), [[1, 2], [3, 4, 5]]) def test_create_array_guchar(self): variant = GLib.Variant('ay', [97, 97, 97]) assert variant.unpack() == [97, 97, 97] variant = GLib.Variant('ay', b'aaa') assert variant.unpack() == [97, 97, 97] variant = GLib.Variant('ay', iter([1, 2, 3])) assert variant.unpack() == [1, 2, 3] with self.assertRaises(TypeError): GLib.Variant('ay', u'aaa') with self.assertRaises(TypeError): GLib.Variant('ay', object()) def test_create_maybe(self): variant = GLib.Variant('mai', None) self.assertEqual(variant.get_type_string(), 'mai') self.assertEqual(variant.n_children(), 0) self.assertEqual(variant.unpack(), None) variant = GLib.Variant('mai', []) self.assertEqual(variant.get_type_string(), 'mai') self.assertEqual(variant.n_children(), 1) variant = GLib.Variant('mami', [None]) self.assertEqual(variant.get_type_string(), 'mami') self.assertEqual(variant.n_children(), 1) variant = GLib.Variant('mami', [None, 13, None]) self.assertEqual(variant.get_type_string(), 'mami') self.assertEqual(variant.n_children(), 1) array = variant.get_child_value(0) self.assertEqual(array.n_children(), 3) element = array.get_child_value(0) self.assertEqual(element.n_children(), 0) element = array.get_child_value(1) self.assertEqual(element.n_children(), 1) self.assertEqual(element.get_child_value(0).get_int32(), 13) element = array.get_child_value(2) self.assertEqual(element.n_children(), 0) def test_create_complex(self): variant = GLib.Variant('(as)', ([],)) self.assertEqual(variant.get_type_string(), '(as)') self.assertEqual(variant.n_children(), 1) self.assertEqual(variant.get_child_value(0).n_children(), 0) variant = GLib.Variant('(as)', ([''],)) self.assertEqual(variant.get_type_string(), '(as)') self.assertEqual(variant.n_children(), 1) self.assertEqual(variant.get_child_value(0).n_children(), 1) self.assertEqual(variant.get_child_value(0).get_child_value(0).get_string(), '') variant = GLib.Variant('(as)', (['hello'],)) self.assertEqual(variant.get_type_string(), '(as)') self.assertEqual(variant.n_children(), 1) self.assertEqual(variant.get_child_value(0).n_children(), 1) self.assertEqual(variant.get_child_value(0).get_child_value(0).get_string(), 'hello') variant = GLib.Variant('a(ii)', []) self.assertEqual(variant.get_type_string(), 'a(ii)') self.assertEqual(variant.n_children(), 0) variant = GLib.Variant('a(ii)', [(5, 6)]) self.assertEqual(variant.get_type_string(), 'a(ii)') self.assertEqual(variant.n_children(), 1) self.assertEqual(variant.get_child_value(0).n_children(), 2) self.assertEqual(variant.get_child_value(0).get_child_value(0).get_int32(), 5) self.assertEqual(variant.get_child_value(0).get_child_value(1).get_int32(), 6) variant = GLib.Variant('(a(ii))', ([],)) self.assertEqual(variant.get_type_string(), '(a(ii))') self.assertEqual(variant.n_children(), 1) self.assertEqual(variant.get_child_value(0).n_children(), 0) variant = GLib.Variant('(a(ii))', ([(5, 6)],)) self.assertEqual(variant.get_type_string(), '(a(ii))') self.assertEqual(variant.n_children(), 1) self.assertEqual(variant.get_child_value(0).n_children(), 1) self.assertEqual(variant.get_child_value(0).get_child_value(0).n_children(), 2) self.assertEqual(variant.get_child_value(0).get_child_value(0).get_child_value(0).get_int32(), 5) self.assertEqual(variant.get_child_value(0).get_child_value(0).get_child_value(1).get_int32(), 6) obj = {'a1': (1, True), 'a2': (2, False)} variant = GLib.Variant('a{s(ib)}', obj) self.assertEqual(variant.get_type_string(), 'a{s(ib)}') self.assertEqual(variant.unpack(), obj) obj = {'a1': (1, GLib.Variant('b', True)), 'a2': (2, GLib.Variant('y', 255))} variant = GLib.Variant('a{s(iv)}', obj) self.assertEqual(variant.get_type_string(), 'a{s(iv)}') self.assertEqual(variant.unpack(), {'a1': (1, True), 'a2': (2, 255)}) obj = (1, {'a': {'a1': True, 'a2': False}, 'b': {'b1': False}, 'c': {} }, 'foo') variant = GLib.Variant('(ia{sa{sb}}s)', obj) self.assertEqual(variant.get_type_string(), '(ia{sa{sb}}s)') self.assertEqual(variant.unpack(), obj) obj = {"frequency": GLib.Variant('t', 738000000), "hierarchy": GLib.Variant('i', 0), "bandwidth": GLib.Variant('x', 8), "code-rate-hp": GLib.Variant('d', 2.0 / 3.0), "constellation": GLib.Variant('s', "QAM16"), "guard-interval": GLib.Variant('u', 4)} variant = GLib.Variant('a{sv}', obj) self.assertEqual(variant.get_type_string(), 'a{sv}') self.assertEqual(variant.unpack(), {"frequency": 738000000, "hierarchy": 0, "bandwidth": 8, "code-rate-hp": 2.0 / 3.0, "constellation": "QAM16", "guard-interval": 4 }) def test_create_errors(self): # excess arguments self.assertRaises(TypeError, GLib.Variant, 'i', 42, 3) self.assertRaises(TypeError, GLib.Variant, '(i)', (42, 3)) # not enough arguments self.assertRaises(TypeError, GLib.Variant, '(ii)', (42,)) # data type mismatch self.assertRaises(TypeError, GLib.Variant, 'i', 'hello') self.assertRaises(TypeError, GLib.Variant, 's', 42) self.assertRaises(TypeError, GLib.Variant, '(ss)', 'mec', 'mac') self.assertRaises(TypeError, GLib.Variant, '(s)', 'hello') # invalid format string self.assertRaises(TypeError, GLib.Variant, 'Q', 1) # invalid types self.assertRaises(TypeError, GLib.Variant, '(ii', (42, 3)) self.assertRaises(TypeError, GLib.Variant, '(ii))', (42, 3)) self.assertRaises(TypeError, GLib.Variant, 'a{si', {}) self.assertRaises(TypeError, GLib.Variant, 'a{si}}', {}) self.assertRaises(TypeError, GLib.Variant, 'a{iii}', {}) def test_unpack(self): # simple values res = GLib.Variant.new_int32(-42).unpack() self.assertEqual(res, -42) res = GLib.Variant.new_uint64(34359738368).unpack() self.assertEqual(res, 34359738368) res = GLib.Variant.new_boolean(True).unpack() self.assertEqual(res, True) res = GLib.Variant.new_object_path('/foo/Bar').unpack() self.assertEqual(res, '/foo/Bar') # variant res = GLib.Variant('v', GLib.Variant.new_int32(-42)).unpack() self.assertEqual(res, -42) GLib.Variant('v', GLib.Variant('v', GLib.Variant('i', 42))) self.assertEqual(res, -42) # tuple res = GLib.Variant.new_tuple(GLib.Variant.new_int32(-1), GLib.Variant.new_string('hello')).unpack() self.assertEqual(res, (-1, 'hello')) # array vb = GLib.VariantBuilder.new(gi._gi.variant_type_from_string('ai')) vb.add_value(GLib.Variant.new_int32(-1)) vb.add_value(GLib.Variant.new_int32(3)) res = vb.end().unpack() self.assertEqual(res, [-1, 3]) # dictionary res = GLib.Variant('a{si}', {'key1': 1, 'key2': 2}).unpack() self.assertEqual(res, {'key1': 1, 'key2': 2}) # maybe v = GLib.Variant('mi', 1) self.assertEqual(v.unpack(), 1) v = GLib.Variant('mi', None) self.assertEqual(v.unpack(), None) v = GLib.Variant('mai', []) self.assertEqual(v.unpack(), []) v = GLib.Variant('m()', ()) self.assertEqual(v.unpack(), ()) v = GLib.Variant('mami', [None, 1, None]) self.assertEqual(v.unpack(), [None, 1, None]) def test_iteration(self): # array index access vb = GLib.VariantBuilder.new(gi._gi.variant_type_from_string('ai')) vb.add_value(GLib.Variant.new_int32(-1)) vb.add_value(GLib.Variant.new_int32(3)) v = vb.end() self.assertEqual(len(v), 2) self.assertEqual(v[0], -1) self.assertEqual(v[1], 3) self.assertEqual(v[-1], 3) self.assertEqual(v[-2], -1) self.assertRaises(IndexError, v.__getitem__, 2) self.assertRaises(IndexError, v.__getitem__, -3) self.assertRaises(ValueError, v.__getitem__, 'a') # array iteration self.assertEqual([x for x in v], [-1, 3]) self.assertEqual(list(v), [-1, 3]) # tuple index access v = GLib.Variant.new_tuple(GLib.Variant.new_int32(-1), GLib.Variant.new_string('hello')) self.assertEqual(len(v), 2) self.assertEqual(v[0], -1) self.assertEqual(v[1], 'hello') self.assertEqual(v[-1], 'hello') self.assertEqual(v[-2], -1) self.assertRaises(IndexError, v.__getitem__, 2) self.assertRaises(IndexError, v.__getitem__, -3) self.assertRaises(ValueError, v.__getitem__, 'a') # tuple iteration self.assertEqual([x for x in v], [-1, 'hello']) self.assertEqual(tuple(v), (-1, 'hello')) # dictionary index access vsi = GLib.Variant('a{si}', {'key1': 1, 'key2': 2}) vis = GLib.Variant('a{is}', {1: 'val1', 5: 'val2'}) self.assertEqual(len(vsi), 2) self.assertEqual(vsi['key1'], 1) self.assertEqual(vsi['key2'], 2) self.assertRaises(KeyError, vsi.__getitem__, 'unknown') self.assertEqual(len(vis), 2) self.assertEqual(vis[1], 'val1') self.assertEqual(vis[5], 'val2') self.assertRaises(KeyError, vsi.__getitem__, 3) # dictionary iteration self.assertEqual(set(vsi.keys()), set(['key1', 'key2'])) self.assertEqual(set(vis.keys()), set([1, 5])) # string index access v = GLib.Variant('s', 'hello') self.assertEqual(len(v), 5) self.assertEqual(v[0], 'h') self.assertEqual(v[4], 'o') self.assertEqual(v[-1], 'o') self.assertEqual(v[-5], 'h') self.assertRaises(IndexError, v.__getitem__, 5) self.assertRaises(IndexError, v.__getitem__, -6) # string iteration self.assertEqual([x for x in v], ['h', 'e', 'l', 'l', 'o']) def test_split_signature(self): self.assertEqual(GLib.Variant.split_signature('()'), []) self.assertEqual(GLib.Variant.split_signature('s'), ['s']) self.assertEqual(GLib.Variant.split_signature('as'), ['as']) self.assertEqual(GLib.Variant.split_signature('(s)'), ['s']) self.assertEqual(GLib.Variant.split_signature('(iso)'), ['i', 's', 'o']) self.assertEqual(GLib.Variant.split_signature('(s(ss)i(ii))'), ['s', '(ss)', 'i', '(ii)']) self.assertEqual(GLib.Variant.split_signature('(as)'), ['as']) self.assertEqual(GLib.Variant.split_signature('(s(ss)iaiaasa(ii))'), ['s', '(ss)', 'i', 'ai', 'aas', 'a(ii)']) self.assertEqual(GLib.Variant.split_signature('(a{iv}(ii)((ss)a{s(ss)}))'), ['a{iv}', '(ii)', '((ss)a{s(ss)})']) def test_hash(self): v1 = GLib.Variant('s', 'somestring') v2 = GLib.Variant('s', 'somestring') v3 = GLib.Variant('s', 'somestring2') self.assertTrue(v2 in set([v1, v3])) self.assertTrue(v2 in frozenset([v1, v3])) self.assertTrue(v2 in {v1: '1', v3: '2'}) def test_compare(self): # Check if identical GVariant are equal def assert_equal(vtype, value): self.assertEqual(GLib.Variant(vtype, value), GLib.Variant(vtype, value)) def assert_not_equal(vtype1, value1, vtype2, value2): self.assertNotEqual(GLib.Variant(vtype1, value1), GLib.Variant(vtype2, value2)) numbers = ['y', 'n', 'q', 'i', 'u', 'x', 't', 'h', 'd'] for num in numbers: assert_equal(num, 42) assert_not_equal(num, 42, num, 41) assert_not_equal(num, 42, 's', '42') assert_equal('s', 'something') assert_not_equal('s', 'something', 's', 'somethingelse') assert_not_equal('s', 'something', 'i', 1234) assert_equal('g', 'dustybinqhogx') assert_not_equal('g', 'dustybinqhogx', 'g', 'dustybin') assert_not_equal('g', 'dustybinqhogx', 'i', 1234) assert_equal('o', '/dev/null') assert_not_equal('o', '/dev/null', 'o', '/dev/zero') assert_not_equal('o', '/dev/null', 'i', 1234) assert_equal('(s)', ('strtuple',)) assert_not_equal('(s)', ('strtuple',), '(s)', ('strtuple2',)) assert_equal('a{si}', {'str': 42}) assert_not_equal('a{si}', {'str': 42}, 'a{si}', {'str': 43}) assert_equal('v', GLib.Variant('i', 42)) assert_not_equal('v', GLib.Variant('i', 42), 'v', GLib.Variant('i', 43)) assert GLib.Variant('i', 42) != object() assert not GLib.Variant('i', 42) == object() def test_bool(self): # Check if the GVariant bool matches the unpacked Pythonic bool def assert_equals_bool(vtype, value): self.assertEqual(bool(GLib.Variant(vtype, value)), bool(value)) # simple values assert_equals_bool('b', True) assert_equals_bool('b', False) numbers = ['y', 'n', 'q', 'i', 'u', 'x', 't', 'h', 'd'] for number in numbers: assert_equals_bool(number, 0) assert_equals_bool(number, 1) assert_equals_bool('s', '') assert_equals_bool('g', '') assert_equals_bool('s', 'something') assert_equals_bool('o', '/dev/null') assert_equals_bool('g', 'dustybinqhogx') # arrays assert_equals_bool('ab', [True]) assert_equals_bool('ab', [False]) for number in numbers: assert_equals_bool('a' + number, []) assert_equals_bool('a' + number, [0]) assert_equals_bool('as', []) assert_equals_bool('as', ['']) assert_equals_bool('ao', []) assert_equals_bool('ao', ['/']) assert_equals_bool('ag', []) assert_equals_bool('ag', ['']) assert_equals_bool('aai', [[]]) # tuples assert_equals_bool('()', ()) for number in numbers: assert_equals_bool('(' + number + ')', (0,)) assert_equals_bool('(s)', ('',)) assert_equals_bool('(o)', ('/',)) assert_equals_bool('(g)', ('',)) assert_equals_bool('(())', ((),)) # dictionaries assert_equals_bool('a{si}', {}) assert_equals_bool('a{si}', {'': 0}) # complex types, always True assert_equals_bool('(as)', ([],)) assert_equals_bool('a{s(i)}', {'': (0,)}) # variant types, recursive unpacking assert_equals_bool('v', GLib.Variant('i', 0)) assert_equals_bool('v', GLib.Variant('i', 1)) # maybe types assert_equals_bool('mi', 42) assert_equals_bool('mi', 0) assert_equals_bool('mi', None) def test_repr(self): # with C constructor v = GLib.Variant.new_uint32(42) self.assertEqual(repr(v), "GLib.Variant('u', 42)") # with override constructor v = GLib.Variant('(is)', (1, 'somestring')) self.assertEqual(repr(v), "GLib.Variant('(is)', (1, 'somestring'))") def test_str(self): # with C constructor v = GLib.Variant.new_uint32(42) self.assertEqual(str(v), 'uint32 42') # with override constructor v = GLib.Variant('(is)', (1, 'somestring')) self.assertEqual(str(v), "(1, 'somestring')") def test_parse_error(self): # This test doubles as a test for GLib.Error marshaling. source_str = 'abc' with self.assertRaises(GLib.Error) as context: GLib.Variant.parse(None, source_str, None, None) e = context.exception text = GLib.Variant.parse_error_print_context(e, source_str) self.assertTrue(source_str in text) def test_parse_error_exceptions(self): source_str = 'abc' self.assertRaisesRegex(TypeError, 'Must be GLib.Error, not int', GLib.Variant.parse_error_print_context, 42, source_str) gerror = GLib.Error(message=42) # not a string self.assertRaisesRegex(TypeError, ".*Must be string, not int.*", GLib.Variant.parse_error_print_context, gerror, source_str) gerror = GLib.Error(domain=42) # not a string self.assertRaisesRegex(TypeError, ".*Must be string, not int.*", GLib.Variant.parse_error_print_context, gerror, source_str) gerror = GLib.Error(code='not an int') self.assertRaisesRegex(TypeError, ".*Must be number, not str.*", GLib.Variant.parse_error_print_context, gerror, source_str) gerror = GLib.Error(code=GLib.MAXUINT) self.assertRaisesRegex(OverflowError, ".*not in range.*", GLib.Variant.parse_error_print_context, gerror, source_str) class TestConstants(unittest.TestCase): def test_basic_types_limits(self): self.assertTrue(isinstance(GLib.MINFLOAT, float)) self.assertTrue(isinstance(GLib.MAXLONG, int)) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/tests/test_overrides_gobject.py0000664000000000000000000002365615074674453020634 0ustar00rootrootimport pytest from gi import PyGIDeprecationWarning from gi.repository import GObject, GLib, GIMarshallingTests from .helper import ignore_gi_deprecation_warnings def test_stop_emission_deprec(): class TestObject(GObject.GObject): int_prop = GObject.Property(default=0, type=int) obj = TestObject() def notify_callback(obj, *args): with pytest.warns(PyGIDeprecationWarning): obj.stop_emission("notify::int-prop") with pytest.warns(PyGIDeprecationWarning): obj.emit_stop_by_name("notify::int-prop") obj.stop_emission_by_name("notify::int-prop") obj.connect("notify::int-prop", notify_callback) obj.notify("int-prop") def test_signal_parse_name(): obj = GObject.GObject() assert GObject.signal_parse_name("notify", obj, True) == (1, 0) with pytest.raises(ValueError): GObject.signal_parse_name("foobar", obj, True) def test_signal_query(): obj = GObject.GObject() res = GObject.signal_query("notify", obj) assert res.signal_name == "notify" assert res.itype == obj.__gtype__ res = GObject.signal_query("foobar", obj) assert res is None def test_value_repr(): v = GObject.Value() assert repr(v) == "" v = GObject.Value(int, 0) assert repr(v) == "" def test_value_no_init(): v = GObject.Value() with pytest.raises(TypeError): v.set_value(0) v.init(GObject.TYPE_LONG) assert v.get_value() == 0 v.set_value(0) def test_value_invalid_type(): v = GObject.Value() assert v.g_type == GObject.TYPE_INVALID assert isinstance(GObject.TYPE_INVALID, GObject.GType) with pytest.raises(ValueError, match="Invalid GType"): v.init(GObject.TYPE_INVALID) with pytest.raises( TypeError, match="GObject.Value needs to be initialized first"): v.set_value(None) assert v.get_value() is None def test_value_long(): v = GObject.Value(GObject.TYPE_LONG) assert v.get_value() == 0 v.set_value(0) assert v.get_value() == 0 v.set_value(GLib.MAXLONG) assert v.get_value() == GLib.MAXLONG v.set_value(GLib.MINLONG) assert v.get_value() == GLib.MINLONG with pytest.raises(OverflowError): v.set_value(GLib.MAXLONG + 1) with pytest.raises(OverflowError): v.set_value(GLib.MINLONG - 1) def test_value_ulong(): v = GObject.Value(GObject.TYPE_ULONG) assert v.get_value() == 0 v.set_value(0) assert v.get_value() == 0 v.set_value(GLib.MAXULONG) assert v.get_value() == GLib.MAXULONG with pytest.raises(OverflowError): v.set_value(GLib.MAXULONG + 1) with pytest.raises(OverflowError): v.set_value(-1) with pytest.raises(TypeError): v.set_value(object()) with pytest.raises(TypeError): v.set_value(None) def test_value_float(): v = GObject.Value(GObject.TYPE_FLOAT) for getter, setter in [(v.get_value, v.set_value), (v.get_float, v.set_float)]: assert getter() == 0.0 setter(0) assert getter() == 0 setter(GLib.MAXFLOAT) assert getter() == GLib.MAXFLOAT setter(GLib.MINFLOAT) assert getter() == GLib.MINFLOAT setter(-GLib.MAXFLOAT) assert getter() == -GLib.MAXFLOAT with pytest.raises(OverflowError): setter(GLib.MAXFLOAT * 2) with pytest.raises(OverflowError): setter(-GLib.MAXFLOAT * 2) with pytest.raises(TypeError): setter(object()) with pytest.raises(TypeError): setter(None) with pytest.raises(TypeError): setter(1j) v.reset() def test_value_double(): v = GObject.Value(GObject.TYPE_DOUBLE) assert v.get_value() == 0.0 v.set_value(0) assert v.get_value() == 0 v.set_value(GLib.MAXDOUBLE) assert v.get_value() == GLib.MAXDOUBLE v.set_value(GLib.MINDOUBLE) assert v.get_value() == GLib.MINDOUBLE v.set_value(-GLib.MAXDOUBLE) assert v.get_value() == -GLib.MAXDOUBLE with pytest.raises(TypeError): v.set_value(object()) with pytest.raises(TypeError): v.set_value(None) with pytest.raises(TypeError): v.set_value(1j) def test_value_uint64(): v = GObject.Value(GObject.TYPE_UINT64) assert v.get_value() == 0 v.set_value(0) assert v.get_value() == 0 v.set_value(GLib.MAXUINT64) assert v.get_value() == GLib.MAXUINT64 with pytest.raises(OverflowError): v.set_value(GLib.MAXUINT64 + 1) with pytest.raises(OverflowError): v.set_value(-1) def test_value_int64(): v = GObject.Value(GObject.TYPE_INT64) assert v.get_value() == 0 v.set_value(0) assert v.get_value() == 0 v.set_value(GLib.MAXINT64) assert v.get_value() == GLib.MAXINT64 v.set_value(GLib.MININT64) assert v.get_value() == GLib.MININT64 with pytest.raises(OverflowError): v.set_value(GLib.MAXINT64 + 1) with pytest.raises(OverflowError): v.set_value(GLib.MININT64 - 1) with pytest.raises(TypeError): v.set_value(object()) with pytest.raises(TypeError): v.set_value(None) def test_value_pointer(): v = GObject.Value(GObject.TYPE_POINTER) assert v.get_value() == 0 v.set_value(42) assert v.get_value() == 42 v.set_value(0) assert v.get_value() == 0 def test_value_unichar(): assert GObject.TYPE_UNICHAR == GObject.TYPE_UINT v = GObject.Value(GObject.TYPE_UNICHAR) assert v.get_value() == 0 v.set_value(42) assert v.get_value() == 42 v.set_value(GLib.MAXUINT) assert v.get_value() == GLib.MAXUINT def test_value_gtype(): class TestObject(GObject.GObject): pass v = GObject.Value(GObject.TYPE_GTYPE) assert v.get_value() == GObject.TYPE_INVALID v.set_value(TestObject.__gtype__) assert v.get_value() == TestObject.__gtype__ v.set_value(TestObject) assert v.get_value() == TestObject.__gtype__ with pytest.raises(TypeError): v.set_value(None) def test_value_variant(): v = GObject.Value(GObject.TYPE_VARIANT) assert v.get_value() is None variant = GLib.Variant('i', 42) v.set_value(variant) assert v.get_value() == variant v.set_value(None) assert v.get_value() is None with pytest.raises(TypeError): v.set_value(object()) def test_value_param(): # FIXME: set_value and get_value trigger a critical # GObject.Value(GObject.TYPE_PARAM) pass def test_value_string(): v = GObject.Value(GObject.TYPE_STRING) for getter, setter in [(v.get_value, v.set_value), (v.get_string, v.set_string)]: assert getter() is None with pytest.raises(TypeError): setter(b"bar") setter(u"quux") assert getter() == u"quux" assert isinstance(getter(), str) setter(None) assert getter() is None v.reset() def test_value_pyobject(): class Foo(object): pass v = GObject.Value(GObject.TYPE_PYOBJECT) assert v.get_value() is None for obj in [Foo(), None, 42, "foo"]: v.set_value(obj) assert v.get_value() == obj @ignore_gi_deprecation_warnings def test_value_char(): v = GObject.Value(GObject.TYPE_CHAR) assert v.get_value() == 0 v.set_value(42) assert v.get_value() == 42 v.set_value(-1) assert v.get_value() == -1 v.set_value(b"a") assert v.get_value() == 97 v.set_value(b"\x00") assert v.get_value() == 0 with pytest.raises(TypeError): v.set_value(u"a") with pytest.raises(OverflowError): v.set_value(128) def test_value_uchar(): v = GObject.Value(GObject.TYPE_UCHAR) assert v.get_value() == 0 v.set_value(200) assert v.get_value() == 200 v.set_value(b"a") assert v.get_value() == 97 v.set_value(b"\x00") assert v.get_value() == 0 with pytest.raises(TypeError): v.set_value(u"a") with pytest.raises(OverflowError): v.set_value(256) def test_value_set_boxed_deprecate_non_boxed(): v = GObject.Value(GObject.TYPE_POINTER) with pytest.warns(PyGIDeprecationWarning): v.get_boxed() with pytest.warns(PyGIDeprecationWarning): v.set_boxed(None) def test_value_boolean(): v = GObject.Value(GObject.TYPE_BOOLEAN) for getter, setter in [(v.get_value, v.set_value), (v.get_boolean, v.set_boolean)]: assert getter() is False assert isinstance(getter(), bool) setter(42) assert getter() is True setter(-1) assert getter() is True setter(0) assert getter() is False setter([]) assert getter() is False setter(["foo"]) assert getter() is True setter(None) assert getter() is False v.reset() def test_value_enum(): t = GIMarshallingTests.GEnum v = GObject.Value(t) for getter, setter in [(v.get_value, v.set_value), (v.get_enum, v.set_enum)]: assert v.g_type == t.__gtype__ assert getter() == 0 setter(t.VALUE1) assert getter() == t.VALUE1 # FIXME: we should try to return an enum type assert type(getter()) is int setter(2424242) assert getter() == 2424242 setter(-1) assert getter() == -1 with pytest.raises(TypeError): setter(object()) with pytest.raises(TypeError): setter(None) v.reset() def test_value_object(): v = GObject.Value(GIMarshallingTests.Object) assert v.g_type.is_a(GObject.TYPE_OBJECT) for getter, setter in [(v.get_value, v.set_value), (v.get_object, v.set_object)]: assert getter() is None setter(None) assert getter() is None obj = GIMarshallingTests.Object() setter(obj) assert getter() is obj with pytest.raises(TypeError): setter(object()) v.reset() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/tests/test_overrides_gtk.py0000664000000000000000000033413115074674453017775 0ustar00rootroot# -*- Mode: Python; py-indent-offset: 4 -*- # vim: tabstop=4 shiftwidth=4 expandtab import contextlib import unittest import sys import gc import warnings import timeit import pytest from .helper import ignore_gi_deprecation_warnings, capture_glib_warnings import gi.overrides import gi.types from gi.repository import Gio, GLib, GObject try: from gi.repository import Gtk, GdkPixbuf, Gdk PyGTKDeprecationWarning = Gtk.PyGTKDeprecationWarning Gtk_version = Gtk._version except ImportError: Gtk = None Gtk_version = None PyGTKDeprecationWarning = None GdkPixbuf = None Gdk = None def gtkver(): if Gtk is None: return (0, 0, 0) return (Gtk.get_major_version(), Gtk.get_minor_version(), Gtk.get_micro_version()) GTK4 = (Gtk and Gtk._version == "4.0") @contextlib.contextmanager def realized(widget): """Makes sure the widget is realized. view = Gtk.TreeView() with realized(view): do_something(view) """ if isinstance(widget, Gtk.Window): toplevel = widget else: if Gtk._version == "4.0": toplevel = widget.get_parent() else: toplevel = widget.get_parent_window() if toplevel is None: window = Gtk.Window() if Gtk._version == "4.0": window.set_child(widget) else: window.add(widget) window.show() widget.realize() if Gtk._version == "4.0": context = GLib.MainContext() while context.pending(): context.iteration(False) else: while Gtk.events_pending(): Gtk.main_iteration() assert widget.get_realized() yield widget if toplevel is None: if Gtk._version == "4.0": window.set_child(None) else: window.remove(widget) window.destroy() if Gtk._version == "4.0": context = GLib.MainContext() while context.pending(): context.iteration(False) else: while Gtk.events_pending(): Gtk.main_iteration() @unittest.skipUnless(Gtk, 'Gtk not available') @unittest.skipIf(Gtk_version == "4.0", "not in gtk4") def test_freeze_child_notif(): events = [] def on_notify(widget, spec): events.append(spec.name) b = Gtk.Box() c = Gtk.Button() c.connect("child-notify", on_notify) c.freeze_child_notify() b.pack_start(c, True, True, 0) b.child_set_property(c, "pack-type", Gtk.PackType.END) b.child_set_property(c, "pack-type", Gtk.PackType.START) c.thaw_child_notify() assert events.count("pack-type") == 1 del events[:] with c.freeze_child_notify(): b.child_set_property(c, "pack-type", Gtk.PackType.END) b.child_set_property(c, "pack-type", Gtk.PackType.START) assert events.count("pack-type") == 1 @unittest.skipUnless(Gtk, 'Gtk not available') @unittest.skipIf(Gtk_version == "4.0", "not in gtk4") def test_menu_popup(): m = Gtk.Menu() with capture_glib_warnings(): m.popup(None, None, None, None, 0, 0) m.popdown() @unittest.skipUnless(Gtk, 'Gtk not available') @unittest.skipIf(Gtk_version == "4.0", "not in gtk4") def test_button_stock(): with capture_glib_warnings(): button = Gtk.Button(stock=Gtk.STOCK_OK) assert button.props.label == Gtk.STOCK_OK assert button.props.use_stock @unittest.skipUnless(Gtk, 'Gtk not available') def test_wrapper_toggle_refs(): if not GTK4: BASE = Gtk.Button else: BASE = Gtk.Widget class MyWidget(BASE): def __init__(self, height): BASE.__init__(self) self._height = height def do_measure(self, orientation, for_size): if orientation == Gtk.Orientation.VERTICAL: return (self._height, self._height, -1, -1) else: return (0, 0, -1, -1) def do_get_preferred_height(self): return (self._height, self._height) height = 142 w = Gtk.Window() b = MyWidget(height) if not GTK4: w.add(b) b.show_all() else: w.set_child(b) del b gc.collect() gc.collect() assert w.get_preferred_size().minimum_size.height >= height @unittest.skipUnless(Gtk, 'Gtk not available') @ignore_gi_deprecation_warnings class TestGtk(unittest.TestCase): @unittest.skipIf(Gtk_version == "4.0", "not in gtk4") def test_container(self): box = Gtk.Box() self.assertTrue(isinstance(box, Gtk.Box)) self.assertTrue(isinstance(box, Gtk.Container)) self.assertTrue(isinstance(box, Gtk.Widget)) self.assertTrue(box) label = Gtk.Label() label2 = Gtk.Label() box.add(label) box.add(label2) self.assertTrue(label in box) self.assertTrue(label2 in box) self.assertEqual(len(box), 2) self.assertTrue(box) labels = [x for x in box] self.assertEqual(labels, [label, label2]) @unittest.skipIf(Gtk_version == "4.0", "not in gtk4") def test_actions(self): self.assertEqual(Gtk.Action, gi.overrides.Gtk.Action) action = Gtk.Action(name="test", label="Test", tooltip="Test Action", stock_id=Gtk.STOCK_COPY) self.assertEqual(action.get_name(), "test") self.assertEqual(action.get_label(), "Test") self.assertEqual(action.get_tooltip(), "Test Action") self.assertEqual(action.get_stock_id(), Gtk.STOCK_COPY) self.assertEqual(Gtk.RadioAction, gi.overrides.Gtk.RadioAction) action = Gtk.RadioAction(name="test", label="Test", tooltip="Test Action", stock_id=Gtk.STOCK_COPY, value=1) self.assertEqual(action.get_name(), "test") self.assertEqual(action.get_label(), "Test") self.assertEqual(action.get_tooltip(), "Test Action") self.assertEqual(action.get_stock_id(), Gtk.STOCK_COPY) self.assertEqual(action.get_current_value(), 1) @unittest.skipIf(Gtk_version == "4.0", "not in gtk4") def test_actiongroup(self): self.assertEqual(Gtk.ActionGroup, gi.overrides.Gtk.ActionGroup) action_group = Gtk.ActionGroup(name='TestActionGroup') callback_data = "callback data" def test_action_callback_data(action, user_data): self.assertEqual(user_data, callback_data) def test_radio_action_callback_data(action, current, user_data): self.assertEqual(user_data, callback_data) action_group.add_actions([ ('test-action1', None, 'Test Action 1', None, None, test_action_callback_data), ('test-action2', Gtk.STOCK_COPY, 'Test Action 2', None, None, test_action_callback_data)], callback_data) action_group.add_toggle_actions([ ('test-toggle-action1', None, 'Test Toggle Action 1', None, None, test_action_callback_data, False), ('test-toggle-action2', Gtk.STOCK_COPY, 'Test Toggle Action 2', None, None, test_action_callback_data, True)], callback_data) action_group.add_radio_actions([ ('test-radio-action1', None, 'Test Radio Action 1'), ('test-radio-action2', Gtk.STOCK_COPY, 'Test Radio Action 2')], 1, test_radio_action_callback_data, callback_data) expected_results = [('test-action1', Gtk.Action), ('test-action2', Gtk.Action), ('test-toggle-action1', Gtk.ToggleAction), ('test-toggle-action2', Gtk.ToggleAction), ('test-radio-action1', Gtk.RadioAction), ('test-radio-action2', Gtk.RadioAction)] for action in action_group.list_actions(): a = (action.get_name(), type(action)) self.assertTrue(a in expected_results) expected_results.remove(a) action.activate() @unittest.skipIf(Gtk_version == "4.0", "not in gtk4") def test_action_group_error_handling(self): action_group = Gtk.ActionGroup(name='TestActionGroup') with pytest.raises(TypeError): action_group.add_actions(42) with pytest.raises(TypeError): action_group.add_toggle_actions(42) with pytest.raises(TypeError): action_group.add_radio_actions(42) @unittest.skipIf(Gtk_version == "4.0", "not in gtk4") def test_action_group_no_user_data(self): action_group = Gtk.ActionGroup(name='TestActionGroup') called = [] def test_action_callback_no_data(action): called.append(action) action_group.add_actions([ ('test-action1', None, 'Test Action 1', None, None, test_action_callback_no_data)]) action_group.add_actions([('test2-action1',)]) action_group.get_action('test-action1').activate() action_group.add_toggle_actions([ ('test-action2', None, 'Test Action 2', None, None, test_action_callback_no_data)]) action_group.add_toggle_actions([('test2-action2',)]) action_group.get_action('test-action2').activate() def test_action_callback_no_data_radio(action, current): called.append(action) action_group.add_radio_actions([ ('test-action3', None, 'Test Action 3', None, None, 0), ('test-action4', None, 'Test Action 4', None, None, 1)], 1, test_action_callback_no_data_radio) action_group.add_radio_actions([('test2-action3',)]) action = action_group.get_action('test-action3') assert action.get_current_value() == 1 action.activate() assert len(called) == 3 @unittest.skipIf(Gtk_version == "4.0", "not in gtk4") def test_uimanager(self): self.assertEqual(Gtk.UIManager, gi.overrides.Gtk.UIManager) ui = Gtk.UIManager() ui.add_ui_from_string(""" """) menubar = ui.get_widget("/menubar1") self.assertEqual(type(menubar), Gtk.MenuBar) ag = Gtk.ActionGroup(name="ag1") ui.insert_action_group(ag) ag2 = Gtk.ActionGroup(name="ag2") ui.insert_action_group(ag2) groups = ui.get_action_groups() self.assertEqual(ag, groups[-2]) self.assertEqual(ag2, groups[-1]) with pytest.raises(TypeError): ui.add_ui_from_string(42) @unittest.skipIf(Gtk_version == "4.0", "not in gtk4") def test_uimanager_nonascii(self): ui = Gtk.UIManager() ui.add_ui_from_string(b''.decode('UTF-8')) mi = ui.get_widget("/menubær1") self.assertEqual(type(mi), Gtk.MenuBar) @unittest.skipIf(Gtk_version == "4.0", "not in gtk4") def test_window_gtk3(self): # standard Window w = Gtk.Window() self.assertEqual(w.get_property('type'), Gtk.WindowType.TOPLEVEL) # type works as keyword argument w = Gtk.Window(type=Gtk.WindowType.POPUP) self.assertEqual(w.get_property('type'), Gtk.WindowType.POPUP) class TestWindow(Gtk.Window): __gtype_name__ = "TestWindow" # works from builder builder = Gtk.Builder() builder.add_from_string(''' popup popup ''') self.assertEqual(builder.get_object('win').get_property('type'), Gtk.WindowType.POPUP) self.assertEqual(builder.get_object('testwin').get_property('type'), Gtk.WindowType.TOPLEVEL) self.assertEqual(builder.get_object('testpop').get_property('type'), Gtk.WindowType.POPUP) @unittest.skipUnless(Gtk_version == "4.0", "no GtkWindowType in gtk4") def test_window_gtk4(self): w = Gtk.Window() # check that setting default size works w.set_default_size(300, 300) self.assertEqual(w.get_default_size(), (300, 300)) class TestWindow(Gtk.Window): __gtype_name__ = "TestWindow" # works from builder builder = Gtk.Builder() builder.add_from_string(''' amazing amazing-test ''') self.assertEqual(builder.get_object("win").get_property("css-name"), "amazing") self.assertEqual(builder.get_object("testwin").get_property("css-name"), "amazing-test") def test_dialog_classes(self): self.assertEqual(Gtk.Dialog, gi.overrides.Gtk.Dialog) if not GTK4: self.assertEqual(Gtk.FileChooserDialog, gi.overrides.Gtk.FileChooserDialog) self.assertEqual(Gtk.RecentChooserDialog, gi.overrides.Gtk.RecentChooserDialog) self.assertEqual(Gtk.ColorSelectionDialog, gi.overrides.Gtk.ColorSelectionDialog) self.assertEqual(Gtk.FontSelectionDialog, gi.overrides.Gtk.FontSelectionDialog) def test_dialog_base(self): dialog = Gtk.Dialog(title='Foo', modal=True) self.assertTrue(isinstance(dialog, Gtk.Dialog)) self.assertTrue(isinstance(dialog, Gtk.Window)) self.assertEqual('Foo', dialog.get_title()) self.assertTrue(dialog.get_modal()) @unittest.skipIf(GTK4, "flags not in gtk4") def test_dialog_deprecations(self): with warnings.catch_warnings(record=True) as warn: warnings.simplefilter('always') dialog = Gtk.Dialog(title='Foo', flags=Gtk.DialogFlags.MODAL) self.assertTrue(dialog.get_modal()) self.assertEqual(len(warn), 1) self.assertTrue(issubclass(warn[0].category, PyGTKDeprecationWarning)) self.assertRegex(str(warn[0].message), '.*flags.*modal.*') with warnings.catch_warnings(record=True) as warn: warnings.simplefilter('always') dialog = Gtk.Dialog(title='Foo', flags=Gtk.DialogFlags.DESTROY_WITH_PARENT) self.assertTrue(dialog.get_destroy_with_parent()) self.assertEqual(len(warn), 1) self.assertTrue(issubclass(warn[0].category, PyGTKDeprecationWarning)) self.assertRegex(str(warn[0].message), '.*flags.*destroy_with_parent.*') @unittest.skipIf(GTK4, "flags not in gtk4") def test_dialog_deprecation_stacklevels(self): # Test warning levels are setup to give the correct filename for # deprecations in different classes in the inheritance hierarchy. # Base class self.assertEqual(Gtk.Dialog, gi.overrides.Gtk.Dialog) with warnings.catch_warnings(record=True) as warn: warnings.simplefilter('always') Gtk.Dialog(flags=Gtk.DialogFlags.MODAL) self.assertEqual(len(warn), 1) self.assertRegex(warn[0].filename, '.*test_overrides_gtk.*') # Validate overridden base with overridden sub-class. self.assertEqual(Gtk.MessageDialog, gi.overrides.Gtk.MessageDialog) with warnings.catch_warnings(record=True) as warn: warnings.simplefilter('always') Gtk.MessageDialog(flags=Gtk.DialogFlags.MODAL) self.assertEqual(len(warn), 1) self.assertRegex(warn[0].filename, '.*test_overrides_gtk.*') # Validate overridden base with non-overridden sub-class. self.assertEqual(Gtk.AboutDialog, gi.repository.Gtk.AboutDialog) with warnings.catch_warnings(record=True) as warn: warnings.simplefilter('always') Gtk.AboutDialog(flags=Gtk.DialogFlags.MODAL) self.assertEqual(len(warn), 1) self.assertRegex(warn[0].filename, '.*test_overrides_gtk.*') def test_dialog_add_buttons(self): if not GTK4: # The overloaded "buttons" keyword gives a warning when attempting # to use it for adding buttons as was available in PyGTK. with warnings.catch_warnings(record=True) as warn: warnings.simplefilter('always') dialog = Gtk.Dialog(title='Foo', modal=True, buttons=('test-button1', 1)) self.assertEqual(len(warn), 1) self.assertTrue(issubclass(warn[0].category, PyGTKDeprecationWarning)) self.assertRegex(str(warn[0].message), '.*ButtonsType.*add_buttons.*') else: dialog = Gtk.Dialog() dialog.add_buttons('test-button1', 1) dialog.add_buttons('test-button2', 2, 'gtk-close', Gtk.ResponseType.CLOSE) button = dialog.get_widget_for_response(1) self.assertEqual('test-button1', button.get_label()) button = dialog.get_widget_for_response(2) self.assertEqual('test-button2', button.get_label()) button = dialog.get_widget_for_response(Gtk.ResponseType.CLOSE) self.assertEqual('gtk-close', button.get_label()) with pytest.raises(ValueError, match="even number"): dialog.add_buttons('test-button2', 2, 'gtk-close') @unittest.skipIf(Gtk_version == "4.0", "not in gtk4") def test_dialog_deprecated_attributes(self): dialog = Gtk.Dialog() assert dialog.action_area == dialog.get_action_area() assert dialog.vbox == dialog.get_content_area() def test_about_dialog(self): dialog = Gtk.AboutDialog() self.assertTrue(isinstance(dialog, Gtk.Window)) if not GTK4: self.assertTrue(isinstance(dialog, Gtk.Dialog)) # AboutDialog is not sub-classed in overrides, make sure # the mro still injects the base class "add_buttons" override. self.assertTrue(hasattr(dialog, 'add_buttons')) def test_message_dialog(self): dialog = Gtk.MessageDialog(title='message dialog test', modal=True, buttons=Gtk.ButtonsType.OK, text='dude!') self.assertTrue(isinstance(dialog, Gtk.Dialog)) self.assertTrue(isinstance(dialog, Gtk.Window)) self.assertEqual('message dialog test', dialog.get_title()) self.assertTrue(dialog.get_modal()) text = dialog.get_property('text') self.assertEqual('dude!', text) if not GTK4: dialog.format_secondary_text('2nd text') self.assertEqual(dialog.get_property('secondary-text'), '2nd text') self.assertFalse(dialog.get_property('secondary-use-markup')) dialog.format_secondary_markup('2nd markup') self.assertEqual(dialog.get_property('secondary-text'), '2nd markup') self.assertTrue(dialog.get_property('secondary-use-markup')) @unittest.skipIf(Gtk_version == "4.0", "not in gtk4") def test_color_selection_dialog(self): dialog = Gtk.ColorSelectionDialog(title="color selection dialog test") self.assertTrue(isinstance(dialog, Gtk.Dialog)) self.assertTrue(isinstance(dialog, Gtk.Window)) self.assertEqual('color selection dialog test', dialog.get_title()) def test_file_chooser_dialog(self): # might cause a GVFS warning, do not break on this with capture_glib_warnings(allow_warnings=True): dialog = Gtk.FileChooserDialog(title='file chooser dialog test', action=Gtk.FileChooserAction.SAVE) self.assertTrue(isinstance(dialog, Gtk.Dialog)) self.assertTrue(isinstance(dialog, Gtk.Window)) self.assertEqual('file chooser dialog test', dialog.get_title()) action = dialog.get_property('action') self.assertEqual(Gtk.FileChooserAction.SAVE, action) def test_file_chooser_dialog_default_action(self): # might cause a GVFS warning, do not break on this with capture_glib_warnings(allow_warnings=True): dialog = Gtk.FileChooserDialog(title='file chooser dialog test') action = dialog.get_property('action') self.assertEqual(Gtk.FileChooserAction.OPEN, action) @unittest.skipIf(Gtk_version == "4.0", "not in gtk4") def test_font_selection_dialog(self): dialog = Gtk.FontSelectionDialog(title="font selection dialog test") self.assertTrue(isinstance(dialog, Gtk.Dialog)) self.assertTrue(isinstance(dialog, Gtk.Window)) self.assertEqual('font selection dialog test', dialog.get_title()) @unittest.skipIf(GTK4, "not in gtk4") def test_recent_chooser_dialog(self): test_manager = Gtk.RecentManager() dialog = Gtk.RecentChooserDialog(title='recent chooser dialog test', recent_manager=test_manager) self.assertTrue(isinstance(dialog, Gtk.Dialog)) self.assertTrue(isinstance(dialog, Gtk.Window)) self.assertEqual('recent chooser dialog test', dialog.get_title()) class TestClass(GObject.GObject): __gtype_name__ = "GIOverrideTreeAPITest" def __init__(self, tester, int_value, string_value): super(TestGtk.TestClass, self).__init__() self.tester = tester self.int_value = int_value self.string_value = string_value def check(self, int_value, string_value): self.tester.assertEqual(int_value, self.int_value) self.tester.assertEqual(string_value, self.string_value) def test_buttons(self): if not GTK4: self.assertEqual(Gtk.Button, gi.overrides.Gtk.Button) # test Gtk.Button button = Gtk.Button() self.assertTrue(isinstance(button, Gtk.Button)) if Gtk._version != "4.0": self.assertTrue(isinstance(button, Gtk.Container)) self.assertTrue(isinstance(button, Gtk.Widget)) if Gtk_version != "4.0": # Using stock items causes hard warning in devel versions of GTK. with capture_glib_warnings(allow_warnings=True): button = Gtk.Button.new_from_stock(Gtk.STOCK_CLOSE) self.assertEqual(Gtk.STOCK_CLOSE, button.get_label()) self.assertTrue(button.get_use_stock()) self.assertTrue(button.get_use_underline()) # test Gtk.Button use_stock button = Gtk.Button(label=Gtk.STOCK_CLOSE, use_stock=True, use_underline=True) self.assertEqual(Gtk.STOCK_CLOSE, button.get_label()) self.assertTrue(button.get_use_stock()) self.assertTrue(button.get_use_underline()) # test Gtk.LinkButton button = Gtk.LinkButton(uri='http://www.Gtk.org', label='Gtk') self.assertTrue(isinstance(button, Gtk.Button)) if Gtk._version != "4.0": self.assertTrue(isinstance(button, Gtk.Container)) self.assertTrue(isinstance(button, Gtk.Widget)) self.assertEqual('http://www.Gtk.org', button.get_uri()) self.assertEqual('Gtk', button.get_label()) def test_inheritance(self): for name in gi.overrides.Gtk.__all__: over = getattr(gi.overrides.Gtk, name) for element in dir(Gtk): try: klass = getattr(Gtk, element) info = klass.__info__ except (NotImplementedError, AttributeError): continue # Get all parent classes and interfaces klass inherits from if isinstance(info, gi.types.ObjectInfo): classes = list(info.get_interfaces()) parent = info.get_parent() while parent is not None and parent.get_name() != "Object": classes.append(parent) parent = parent.get_parent() classes = [kl for kl in classes if kl.get_namespace() == "Gtk"] else: continue for kl in classes: if kl.get_name() == name: self.assertTrue(issubclass(klass, over,), "%r does not inherit from override %r" % (klass, over,)) def test_editable(self): self.assertEqual(Gtk.Editable, gi.overrides.Gtk.Editable) # need to use Gtk.Entry because Editable is an interface entry = Gtk.Entry() pos = entry.insert_text('HeWorld', 0) self.assertEqual(pos, 7) pos = entry.insert_text('llo ', 2) self.assertEqual(pos, 6) text = entry.get_chars(0, 11) self.assertEqual('Hello World', text) def test_label(self): label = Gtk.Label(label='Hello') self.assertTrue(isinstance(label, Gtk.Widget)) self.assertEqual(label.get_text(), 'Hello') def adjustment_check(self, adjustment, value=0.0, lower=0.0, upper=0.0, step_increment=0.0, page_increment=0.0, page_size=0.0): self.assertEqual(adjustment.get_value(), value) self.assertEqual(adjustment.get_lower(), lower) self.assertEqual(adjustment.get_upper(), upper) self.assertEqual(adjustment.get_step_increment(), step_increment) self.assertEqual(adjustment.get_page_increment(), page_increment) self.assertEqual(adjustment.get_page_size(), page_size) def test_adjustment(self): adjustment = Gtk.Adjustment(value=1, lower=0, upper=6, step_increment=4, page_increment=5, page_size=3) self.adjustment_check(adjustment, value=1, lower=0, upper=6, step_increment=4, page_increment=5, page_size=3) adjustment = Gtk.Adjustment(value=1, lower=0, upper=6, step_increment=4, page_increment=5) self.adjustment_check(adjustment, value=1, lower=0, upper=6, step_increment=4, page_increment=5) adjustment = Gtk.Adjustment(value=1, lower=0, upper=6, step_increment=4) self.adjustment_check(adjustment, value=1, lower=0, upper=6, step_increment=4) adjustment = Gtk.Adjustment(value=1, lower=0, upper=6) self.adjustment_check(adjustment, value=1, lower=0, upper=6) adjustment = Gtk.Adjustment() self.adjustment_check(adjustment) if not GTK4: adjustment = Gtk.Adjustment(1, -1, 3, 0, 0, 0) self.adjustment_check(adjustment, value=1, lower=-1, upper=3) adjustment = Gtk.Adjustment(1, -1, 3, 0, 0, 0, value=2) self.adjustment_check(adjustment, value=2, lower=-1, upper=3) @unittest.skipIf(Gtk_version == "4.0", "not in gtk4") def test_table(self): table = Gtk.Table() self.assertTrue(isinstance(table, Gtk.Table)) if Gtk._version != "4.0": self.assertTrue(isinstance(table, Gtk.Container)) self.assertTrue(isinstance(table, Gtk.Widget)) self.assertEqual(table.get_size(), (1, 1)) self.assertEqual(table.get_homogeneous(), False) table = Gtk.Table(n_rows=2, n_columns=3) self.assertEqual(table.get_size(), (2, 3)) self.assertEqual(table.get_homogeneous(), False) table = Gtk.Table(n_rows=2, n_columns=3, homogeneous=True) self.assertEqual(table.get_size(), (2, 3)) self.assertEqual(table.get_homogeneous(), True) label = Gtk.Label(label='Hello') self.assertTrue(isinstance(label, Gtk.Widget)) table.attach(label, 0, 1, 0, 1) self.assertEqual(label, table.get_children()[0]) def test_scrolledwindow(self): sw = Gtk.ScrolledWindow() self.assertTrue(isinstance(sw, Gtk.ScrolledWindow)) if Gtk._version != "4.0": self.assertTrue(isinstance(sw, Gtk.Container)) self.assertTrue(isinstance(sw, Gtk.Widget)) sb = sw.get_hscrollbar() self.assertEqual(sw.get_hadjustment(), sb.get_adjustment()) sb = sw.get_vscrollbar() self.assertEqual(sw.get_vadjustment(), sb.get_adjustment()) @unittest.skipIf(Gtk_version == "4.0", "not in gtk4") def test_widget_drag_methods(self): widget = Gtk.Button() # here we are not checking functionality, only that the methods exist # and except the right number of arguments widget.drag_check_threshold(0, 0, 0, 0) # drag_dest_ methods widget.drag_dest_set(Gtk.DestDefaults.DROP, None, Gdk.DragAction.COPY) widget.drag_dest_add_image_targets() widget.drag_dest_add_text_targets() widget.drag_dest_add_uri_targets() widget.drag_dest_get_track_motion() widget.drag_dest_set_track_motion(True) widget.drag_dest_get_target_list() widget.drag_dest_set_target_list(None) widget.drag_dest_set_target_list(Gtk.TargetList.new([Gtk.TargetEntry.new('test', 0, 0)])) widget.drag_dest_unset() widget.drag_highlight() widget.drag_unhighlight() # drag_source_ methods widget.drag_source_set(Gdk.ModifierType.BUTTON1_MASK, None, Gdk.DragAction.MOVE) widget.drag_source_add_image_targets() widget.drag_source_add_text_targets() widget.drag_source_add_uri_targets() widget.drag_source_set_icon_name("_About") widget.drag_source_set_icon_pixbuf(GdkPixbuf.Pixbuf()) widget.drag_source_set_icon_stock(Gtk.STOCK_ABOUT) widget.drag_source_get_target_list() widget.drag_source_set_target_list(None) widget.drag_source_set_target_list(Gtk.TargetList.new([Gtk.TargetEntry.new('test', 0, 0)])) widget.drag_source_unset() # these methods cannot be called because they require a valid drag on # a real GdkWindow. So we only check that they exist and are callable. self.assertTrue(hasattr(widget, 'drag_dest_set_proxy')) self.assertTrue(hasattr(widget, 'drag_get_data')) @unittest.skipIf(Gtk_version != "4.0", "gtk4 only") def test_widget_drag_methods_gtk4(self): widget = Gtk.Button() widget.drag_check_threshold(0, 0, 0, 0) # drag source drag_source = Gtk.DragSource() content = Gdk.ContentProvider.new_for_value("data") drag_source.set_content(content) drag_source.set_actions(Gdk.DragAction.COPY) image = Gtk.Image.new_from_icon_name("dialog-warning") drag_source.set_icon(image.get_paintable(), 0, 0) widget.add_controller(drag_source) # drop target drop_target = Gtk.DropTarget.new(Gdk.ContentFormats.new([]), Gdk.DragAction.COPY) widget.add_controller(drop_target) widget.remove_controller(drag_source) widget.remove_controller(drop_target) @unittest.skipIf(sys.platform == "darwin", "crashes") @unittest.skipIf(GTK4, "uses lots of gtk3 only api") def test_tree_view_drag_target_list_gtk3(self): mixed_target_list = [Gtk.TargetEntry.new('test0', 0, 0), ('test1', 1, 1), Gtk.TargetEntry.new('test2', 2, 2), ('test3', 3, 3)] def _test_target_list(targets): for i, target in enumerate(targets): self.assertTrue(isinstance(target, Gtk.TargetEntry)) self.assertEqual(target.target, 'test' + str(i)) self.assertEqual(target.flags, i) self.assertEqual(target.info, i) _test_target_list(Gtk._construct_target_list(mixed_target_list)) widget = Gtk.Button() widget.drag_dest_set(Gtk.DestDefaults.DROP, None, Gdk.DragAction.COPY) widget.drag_dest_set_target_list(mixed_target_list) widget.drag_dest_get_target_list() widget.drag_source_set(Gdk.ModifierType.BUTTON1_MASK, None, Gdk.DragAction.MOVE) widget.drag_source_set_target_list(mixed_target_list) widget.drag_source_get_target_list() treeview = Gtk.TreeView() treeview.enable_model_drag_source(Gdk.ModifierType.BUTTON1_MASK, mixed_target_list, Gdk.DragAction.DEFAULT | Gdk.DragAction.MOVE) treeview.enable_model_drag_dest(mixed_target_list, Gdk.DragAction.DEFAULT | Gdk.DragAction.MOVE) @unittest.skipUnless(GTK4, "gtk4 only") def test_tree_view_drag_content_formats_gtk4(self): content_formats = Gdk.ContentFormats.new( ["application/json", "GTK_TREE_MODEL_ROW"] ) treeview = Gtk.TreeView() treeview.enable_model_drag_source(Gdk.ModifierType.BUTTON1_MASK, content_formats, Gdk.DragAction.MOVE) treeview.enable_model_drag_dest(content_formats, Gdk.DragAction.MOVE) @unittest.skipIf(Gtk_version == "4.0", "not in gtk4") def test_scrollbar(self): adjustment = Gtk.Adjustment() hscrollbar = Gtk.HScrollbar() vscrollbar = Gtk.VScrollbar() self.assertNotEqual(hscrollbar.props.adjustment, adjustment) self.assertNotEqual(vscrollbar.props.adjustment, adjustment) hscrollbar = Gtk.HScrollbar(adjustment=adjustment) vscrollbar = Gtk.VScrollbar(adjustment=adjustment) self.assertEqual(hscrollbar.props.adjustment, adjustment) self.assertEqual(vscrollbar.props.adjustment, adjustment) def test_iconview(self): # PyGTK compat iconview = Gtk.IconView() self.assertEqual(iconview.props.model, None) model = Gtk.ListStore(str) iconview = Gtk.IconView(model=model) self.assertEqual(iconview.props.model, model) @unittest.skipIf(Gtk_version == "4.0", "not in gtk4") def test_toolbutton(self): # PyGTK compat # Using stock items causes hard warning in devel versions of GTK. with capture_glib_warnings(allow_warnings=True): button = Gtk.ToolButton() self.assertEqual(button.props.stock_id, None) button = Gtk.ToolButton(stock_id='gtk-new') self.assertEqual(button.props.stock_id, 'gtk-new') icon = Gtk.Image.new_from_stock(Gtk.STOCK_OPEN, Gtk.IconSize.SMALL_TOOLBAR) button = Gtk.ToolButton(label='mylabel', icon_widget=icon) self.assertEqual(button.props.label, 'mylabel') self.assertEqual(button.props.icon_widget, icon) @unittest.skipIf(Gtk_version == "4.0", "not in gtk4") def test_iconset(self): Gtk.IconSet() pixbuf = GdkPixbuf.Pixbuf() Gtk.IconSet.new_from_pixbuf(pixbuf) with warnings.catch_warnings(record=True) as warn: warnings.simplefilter('always') Gtk.IconSet(pixbuf) assert issubclass(warn[0].category, PyGTKDeprecationWarning) def test_viewport(self): vadjustment = Gtk.Adjustment() hadjustment = Gtk.Adjustment() viewport = Gtk.Viewport(hadjustment=hadjustment, vadjustment=vadjustment) self.assertEqual(viewport.props.vadjustment, vadjustment) self.assertEqual(viewport.props.hadjustment, hadjustment) @unittest.skipIf(Gtk_version == "4.0", "not in gtk4") def test_stock_lookup(self): stock_item = Gtk.stock_lookup('gtk-ok') self.assertEqual(type(stock_item), Gtk.StockItem) self.assertEqual(stock_item.stock_id, 'gtk-ok') self.assertEqual(Gtk.stock_lookup('nosuchthing'), None) @unittest.skipIf(Gtk_version == "4.0", "not in gtk4") def test_gtk_main(self): # with no arguments GLib.idle_add(Gtk.main_quit) Gtk.main() # overridden function ignores its arguments GLib.idle_add(Gtk.main_quit, 'hello') Gtk.main() @unittest.skipIf(Gtk_version == "4.0", "not in gtk4") def test_widget_render_icon(self): button = Gtk.Button(label='OK') pixbuf = button.render_icon(Gtk.STOCK_OK, Gtk.IconSize.BUTTON) self.assertTrue(pixbuf is not None) @unittest.skipUnless( Gtk_version == "4.0", "GtkWidget prior to gtk4 is not iterable") def test_widget_iterable(self): widget = Gtk.Box() children = [child for child in widget] self.assertEqual(len(children), 0) nr_children = 7 for i in range(nr_children): widget.append(Gtk.Label()) children = [child for child in widget] self.assertEqual(len(children), nr_children) first_child = children[0] last_child = children[-1] self.assertEqual(first_child, widget.get_first_child()) self.assertEqual(last_child, widget.get_last_child()) self.assertTrue(first_child in widget) self.assertTrue(last_child in widget) widget.remove(first_child) self.assertTrue(first_child not in widget) self.assertTrue(last_child in widget) widget.remove(last_child) self.assertTrue(first_child not in widget) self.assertTrue(last_child not in widget) @unittest.skipUnless(Gtk, 'Gtk not available') class TestWidget(unittest.TestCase): @unittest.skipIf(Gtk_version == "4.0", "not in gtk4") def test_style_get_property_gvalue(self): button = Gtk.Button() value = GObject.Value(int, -42) button.style_get_property('focus-padding', value) # Test only that the style property changed since we can't actuall # set it. self.assertNotEqual(value.get_int(), -42) @unittest.skipIf(Gtk_version == "4.0", "not in gtk4") def test_style_get_property_return_with_explicit_gvalue(self): button = Gtk.Button() value = GObject.Value(int, -42) result = button.style_get_property('focus-padding', value) self.assertIsInstance(result, int) self.assertNotEqual(result, -42) @unittest.skipIf(Gtk_version == "4.0", "not in gtk4") def test_style_get_property_return_with_implicit_gvalue(self): button = Gtk.Button() result = button.style_get_property('focus-padding') self.assertIsInstance(result, int) self.assertNotEqual(result, -42) @unittest.skipIf(Gtk_version == "4.0", "not in gtk4") def test_style_get_property_error(self): button = Gtk.Button() with self.assertRaises(ValueError): button.style_get_property('not-a-valid-style-property') @unittest.skipIf(Gtk_version != "4.0", "only in gtk4") def test_translate_coordinates(self): box = Gtk.Box() child = Gtk.Button() box.append(child) with realized(box): assert box.translate_coordinates(child, 42, 24) == (42.0, 24.0) assert box.translate_coordinates(Gtk.Button(), 0, 0) is None @unittest.skipIf(sys.platform == "darwin", "hangs") @unittest.skipUnless(Gtk, 'Gtk not available') class TestSignals(unittest.TestCase): def test_class_closure_override_with_aliased_type(self): class WindowWithSizeAllocOverride(Gtk.ScrolledWindow): if not GTK4: __gsignals__ = {'size-allocate': 'override'} def __init__(self): Gtk.ScrolledWindow.__init__(self) self._alloc_called = False self._alloc_value = None self._alloc_error = None def do_size_allocate(self, *args): self._alloc_called = True self._alloc_value = args[0] try: Gtk.ScrolledWindow.do_size_allocate(self, *args) except Exception as e: self._alloc_error = e win = WindowWithSizeAllocOverride() rect = Gdk.Rectangle() rect.width = 100 rect.height = 100 with realized(win): win.show() win.get_preferred_size() if GTK4: win.size_allocate(rect, 0) else: win.size_allocate(rect) self.assertTrue(win._alloc_called) if GTK4: self.assertIsInstance(win._alloc_value, int) else: self.assertIsInstance(win._alloc_value, Gdk.Rectangle) self.assertTrue(win._alloc_error is None, win._alloc_error) @unittest.expectedFailure # https://bugzilla.gnome.org/show_bug.cgi?id=735693 def test_overlay_child_position(self): def get_child_position(overlay, widget, rect, user_data=None): rect.x = 1 rect.y = 2 rect.width = 3 rect.height = 4 return True overlay = Gtk.Overlay() overlay.connect('get-child-position', get_child_position) rect = Gdk.Rectangle() rect.x = -1 rect.y = -1 rect.width = -1 rect.height = -1 overlay.emit('get-child-position', None, rect) self.assertEqual(rect.x, 1) self.assertEqual(rect.y, 2) self.assertEqual(rect.width, 3) self.assertEqual(rect.height, 4) @unittest.skipUnless(Gtk, 'Gtk not available') class TestBuilder(unittest.TestCase): class SignalTest(GObject.GObject): __gtype_name__ = "GIOverrideSignalTest" __gsignals__ = { "test-signal": (GObject.SignalFlags.RUN_FIRST, None, []), } class SignalTestObject(GObject.GObject): __gtype_name__ = "GIOverrideSignalTestObject" def test_add_from_string(self): builder = Gtk.Builder() with pytest.raises(TypeError): builder.add_from_string(object()) builder.add_from_string(u"") builder.add_from_string("") def get_example(string): return u"""\
%s
""" % string builder.add_from_string(get_example(u"ä" * 1000)) builder = Gtk.Builder() builder.add_objects_from_string(u"", ['']) builder.add_objects_from_string("", ['']) builder.add_objects_from_string(get_example(u"ä" * 1000), ['']) with pytest.raises(TypeError): builder.add_objects_from_string(object(), []) def test_extract_handler_and_args_object(self): class Obj(): pass obj = Obj() obj.foo = lambda: None handler, args = Gtk._extract_handler_and_args(obj, 'foo') self.assertEqual(handler, obj.foo) self.assertEqual(len(args), 0) def test_extract_handler_and_args_dict(self): obj = {'foo': lambda: None} handler, args = Gtk._extract_handler_and_args(obj, 'foo') self.assertEqual(handler, obj['foo']) self.assertEqual(len(args), 0) def test_extract_handler_and_args_with_seq(self): obj = {'foo': (lambda: None, 1, 2)} handler, args = Gtk._extract_handler_and_args(obj, 'foo') self.assertEqual(handler, obj['foo'][0]) self.assertSequenceEqual(args, [1, 2]) def test_extract_handler_and_args_no_handler_error(self): obj = dict(foo=lambda: None) self.assertRaises(AttributeError, Gtk._extract_handler_and_args, obj, 'not_a_handler') def test_extract_handler_and_args_type_mismatch(self): with pytest.raises(TypeError): Gtk._extract_handler_and_args({"foo": object()}, "foo") with pytest.raises(TypeError): Gtk._extract_handler_and_args({"foo": []}, "foo") def test_builder_with_handler_and_args(self): args_collector = [] def on_signal(*args): args_collector.append(args) signals_dict = {'on_signal1': (on_signal, 1, 2), 'on_signal2': on_signal} if GTK4: builder = Gtk.Builder(signals_dict) else: builder = Gtk.Builder() builder.add_from_string(""" """) if not GTK4: builder.connect_signals(signals_dict) objects = builder.get_objects() self.assertEqual(len(objects), 1) obj, = objects obj.emit('test-signal') self.assertEqual(len(args_collector), 2) self.assertSequenceEqual(args_collector[0], (obj, 1, 2)) self.assertSequenceEqual(args_collector[1], (obj, )) def test_builder_with_handler_object(self): args_collector = [] def on_signal(*args): args_collector.append(args) signals_dict = {'on_signal1': (on_signal, 1, 2), 'on_signal2': on_signal} if GTK4: builder = Gtk.Builder(signals_dict) else: builder = Gtk.Builder() builder.add_from_string(""" """) if not GTK4: builder.connect_signals(signals_dict) obj = builder.get_object("foo") emitter = builder.get_object("object_sig_test") emitter.emit("test-signal") assert len(args_collector) == 2 assert args_collector[0] == (obj, 1, 2) assert args_collector[1] == (obj, ) def test_builder(self): self.assertEqual(Gtk.Builder, gi.overrides.Gtk.Builder) class SignalCheck: def __init__(self): self.sentinel = 0 self.after_sentinel = 0 def on_signal_1(self, *args): self.sentinel += 1 self.after_sentinel += 1 def on_signal_3(self, *args): self.sentinel += 3 def on_signal_after(self, *args): if self.after_sentinel == 1: self.after_sentinel += 1 signal_checker = SignalCheck() signal_checker = SignalCheck() if GTK4: builder = Gtk.Builder(signal_checker) else: builder = Gtk.Builder() # add object1 to the builder builder.add_from_string(""" """) # only add object3 to the builder builder.add_objects_from_string(""" """, ['object3']) # hook up signals for Gtk3 if not GTK4: builder.connect_signals(signal_checker) # call their notify signals and check sentinel objects = builder.get_objects() self.assertEqual(len(objects), 2) for obj in objects: obj.emit('test-signal') self.assertEqual(signal_checker.sentinel, 4) self.assertEqual(signal_checker.after_sentinel, 2) @unittest.skipUnless(Gtk, 'Gtk not available') class TestTreeModelRow(unittest.TestCase): def test_tree_model_row(self): model = Gtk.TreeStore(int) iter_ = model.append(None, [42]) path = model.get_path(iter_) Gtk.TreeModelRow(model, iter_) row = Gtk.TreeModelRow(model, path) with pytest.raises(TypeError): row["foo"] with pytest.raises(TypeError): Gtk.TreeModelRow(model, 42) with pytest.raises(TypeError): Gtk.TreeModelRow(42, path) iter_ = model.append(None, [24]) row = Gtk.TreeModelRow(model, iter_) assert row.previous[0] == 42 assert row.get_previous()[0] == 42 assert row.previous.previous is None @unittest.skipUnless(Gtk, "Gtk not available") class TestCustomSorter(): class Person(GObject.GObject): name = GObject.Property(type=str, default="") def __init__(self, name): super().__init__() self.props.name = name user_data = "user_data" def names_sort(self, name_a, name_b, user_data): assert user_data is None if name_a.props.name < name_b.props.name: return Gtk.Ordering.SMALLER elif name_a.props.name > name_b.props.name: return Gtk.Ordering.LARGER else: return Gtk.Ordering.EQUAL def names_invert_sort(self, name_a, name_b, user_data): assert user_data == self.user_data if name_a.props.name < name_b.props.name: return Gtk.Ordering.LARGER elif name_a.props.name > name_b.props.name: return Gtk.Ordering.SMALLER else: return Gtk.Ordering.EQUAL @unittest.skipIf(Gtk_version != "4.0", "gtk4 only") def test_custom_sorter_init(self): custom_sorter_empty = Gtk.CustomSorter() assert isinstance(custom_sorter_empty, Gtk.CustomSorter) custom_sorter_empty.set_sort_func(self.names_sort) assert isinstance(custom_sorter_empty, Gtk.CustomSorter) custom_sorter_empty.set_sort_func( self.names_invert_sort, self.user_data) assert isinstance(custom_sorter_empty, Gtk.CustomSorter) custom_sorter_empty_sort = Gtk.CustomSorter.new(None) assert isinstance(custom_sorter_empty_sort, Gtk.CustomSorter) custom_sorter_with_sort = Gtk.CustomSorter.new(self.names_sort, None) assert isinstance(custom_sorter_with_sort, Gtk.CustomSorter) custom_sorter_with_sort_ud = Gtk.CustomSorter.new( self.names_invert_sort, self.user_data) assert isinstance(custom_sorter_with_sort_ud, Gtk.CustomSorter) @unittest.skipIf(Gtk_version != "4.0", "gtk4 only") def test_custom_sorter_with_model(self): model = Gio.ListStore.new(self.Person) sort_model = Gtk.SortListModel.new(model) assert sort_model.props.sorter is None empty_sorter = Gtk.CustomSorter() empty_sorter.set_sort_func(self.names_sort, None) sort_model.set_sorter(empty_sorter) assert sort_model.props.sorter is empty_sorter john = self.Person("john") bob = self.Person("bob") model.append(john) model.append(bob) assert sort_model[0] == bob assert sort_model[1] == john alice = self.Person("alice") model.append(alice) assert sort_model[0] == alice assert sort_model[2] == john new_model = Gio.ListStore.new(self.Person) new_sort_model = Gtk.SortListModel.new(new_model) assert new_sort_model.props.sorter is None invert_sorter = Gtk.CustomSorter.new( self.names_invert_sort, self.user_data) new_sort_model.set_sorter(invert_sorter) assert new_sort_model.props.sorter is invert_sorter beatles = ["john", "paul", "george", "ringo"] for member in beatles: new_model.append(self.Person(member)) expected_result = ["ringo", "paul", "john", "george"] for result, member in zip(new_sort_model, expected_result): assert result.props.name == member @unittest.skipUnless(Gtk, 'Gtk not available') class TestListStore(unittest.TestCase): def test_insert_with_values(self): model = Gtk.ListStore(int) assert hasattr(model, 'insert_with_values') iter_ = model.insert_with_values(0, (0,), [42]) assert isinstance(iter_, Gtk.TreeIter) assert hasattr(model, 'insert_with_valuesv') iter_ = model.insert_with_valuesv(0, (0,), [43]) assert isinstance(iter_, Gtk.TreeIter) assert len(model) == 2 @ignore_gi_deprecation_warnings @unittest.skipUnless(Gtk, 'Gtk not available') class TestTreeModel(unittest.TestCase): @unittest.skipIf(Gtk_version == "4.0", "not in gtk4") def test_tree_model_sort_new_with_model_old(self): # https://gitlab.gnome.org/GNOME/gtk/-/merge_requests/1134 model = Gtk.TreeStore(int) sort_model = model.sort_new_with_model() assert isinstance(sort_model, Gtk.TreeModelSort) assert sort_model.get_model() == model def test_tree_model_sort_new_with_model_new(self): # https://gitlab.gnome.org/GNOME/gtk/-/merge_requests/1134 model = Gtk.TreeStore(int) sort_model = Gtk.TreeModelSort.new_with_model(child_model=model) assert isinstance(sort_model, Gtk.TreeModelSort) assert sort_model.get_model() == model def test_tree_model_sort(self): if not GTK4: self.assertEqual(Gtk.TreeModelSort, gi.overrides.Gtk.TreeModelSort) model = Gtk.TreeStore(int, bool) model_sort = Gtk.TreeModelSort(model=model) self.assertEqual(model_sort.get_model(), model) def test_tree_store(self): self.assertEqual(Gtk.TreeStore, gi.overrides.Gtk.TreeStore) self.assertEqual(Gtk.ListStore, gi.overrides.Gtk.ListStore) self.assertEqual(Gtk.TreeModel, gi.overrides.Gtk.TreeModel) self.assertEqual(Gtk.TreeViewColumn, gi.overrides.Gtk.TreeViewColumn) class TestPyObject(object): pass test_pyobj = TestPyObject() test_pydict = {1: 1, "2": 2, "3": "3"} test_pylist = [1, "2", "3"] tree_store = Gtk.TreeStore(int, 'gchararray', TestGtk.TestClass, GObject.TYPE_PYOBJECT, object, object, object, bool, bool, GObject.TYPE_UINT, GObject.TYPE_ULONG, GObject.TYPE_INT64, GObject.TYPE_UINT64, GObject.TYPE_UCHAR, GObject.TYPE_CHAR) parent = None for i in range(97): label = 'this is child #%d' % i testobj = TestGtk.TestClass(self, i, label) parent = tree_store.append(parent, (i, label, testobj, testobj, test_pyobj, test_pydict, test_pylist, i % 2, bool(i % 2), i, GLib.MAXULONG, GLib.MININT64, 0xffffffffffffffff, 254, b'a' )) # test set parent = tree_store.append(parent) i = 97 label = 'this is child #%d' % i testobj = TestGtk.TestClass(self, i, label) tree_store.set(parent, 0, i, 2, testobj, 1, label, 3, testobj, 4, test_pyobj, 5, test_pydict, 6, test_pylist, 7, i % 2, 8, bool(i % 2), 9, i, 10, GLib.MAXULONG, 11, GLib.MININT64, 12, 0xffffffffffffffff, 13, 254, 14, b'a') parent = tree_store.append(parent) i = 98 label = 'this is child #%d' % i testobj = TestGtk.TestClass(self, i, label) tree_store.set(parent, {0: i, 2: testobj, 1: label, 3: testobj, 4: test_pyobj, 5: test_pydict, 6: test_pylist, 7: i % 2, 8: bool(i % 2), 9: i, 10: GLib.MAXULONG, 11: GLib.MININT64, 12: 0xffffffffffffffff, 13: 254, 14: b'a'}) parent = tree_store.append(parent) i = 99 label = 'this is child #%d' % i testobj = TestGtk.TestClass(self, i, label) tree_store.set(parent, (0, 2, 1, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14), (i, testobj, label, testobj, test_pyobj, test_pydict, test_pylist, i % 2, bool(i % 2), i, GLib.MAXULONG, GLib.MININT64, 0xffffffffffffffff, 254, b'a')) # len gets the number of children in the root node # since we kept appending to the previous node # there should only be one child of the root self.assertEqual(len(tree_store), 1) # walk the tree to see if the values were stored correctly parent = None i = 0 treeiter = tree_store.iter_children(parent) while treeiter: i = tree_store.get_value(treeiter, 0) s = tree_store.get_value(treeiter, 1) obj = tree_store.get_value(treeiter, 2) obj.check(i, s) obj2 = tree_store.get_value(treeiter, 3) self.assertEqual(obj, obj2) pyobj = tree_store.get_value(treeiter, 4) self.assertEqual(pyobj, test_pyobj) pydict = tree_store.get_value(treeiter, 5) self.assertEqual(pydict, test_pydict) pylist = tree_store.get_value(treeiter, 6) self.assertEqual(pylist, test_pylist) bool_1 = tree_store.get_value(treeiter, 7) bool_2 = tree_store.get_value(treeiter, 8) self.assertEqual(bool_1, bool_2) self.assertTrue(isinstance(bool_1, bool)) self.assertTrue(isinstance(bool_2, bool)) uint_ = tree_store.get_value(treeiter, 9) self.assertEqual(uint_, i) ulong_ = tree_store.get_value(treeiter, 10) self.assertEqual(ulong_, GLib.MAXULONG) int64_ = tree_store.get_value(treeiter, 11) self.assertEqual(int64_, GLib.MININT64) uint64_ = tree_store.get_value(treeiter, 12) self.assertEqual(uint64_, 0xffffffffffffffff) uchar_ = tree_store.get_value(treeiter, 13) self.assertEqual(ord(uchar_), 254) char_ = tree_store.get_value(treeiter, 14) self.assertEqual(char_, 'a') parent = treeiter treeiter = tree_store.iter_children(parent) self.assertEqual(i, 99) def test_tree_store_signals(self): tree_store = Gtk.TreeStore(int, bool) def on_row_inserted(tree_store, tree_path, tree_iter, signal_list): signal_list.append('row-inserted') def on_row_changed(tree_store, tree_path, tree_iter, signal_list): signal_list.append('row-changed') signals = [] tree_store.connect('row-inserted', on_row_inserted, signals) tree_store.connect('row-changed', on_row_changed, signals) # adding rows with and without data should only call one signal tree_store.append(None, (0, False)) self.assertEqual(signals, ['row-inserted']) signals.pop() tree_store.append(None) self.assertEqual(signals, ['row-inserted']) signals.pop() tree_store.prepend(None, (0, False)) self.assertEqual(signals, ['row-inserted']) signals.pop() tree_store.prepend(None) self.assertEqual(signals, ['row-inserted']) signals.pop() tree_store.insert(None, 1, (0, False)) self.assertEqual(signals, ['row-inserted']) signals.pop() tree_store.insert(None, 1) self.assertEqual(signals, ['row-inserted']) # One set one signal signals.pop() tree_iter = tree_store.append(None, (10, False)) tree_store.set(tree_iter, (0, 1), (20, True)) self.assertEqual(signals, ['row-inserted', 'row-changed']) def test_list_store(self): class TestPyObject(object): pass test_pyobj = TestPyObject() test_pydict = {1: 1, "2": 2, "3": "3"} test_pylist = [1, "2", "3"] list_store = Gtk.ListStore(int, str, 'GIOverrideTreeAPITest', object, object, object, bool, bool) for i in range(1, 93): label = 'this is row #%d' % i testobj = TestGtk.TestClass(self, i, label) list_store.append((i, label, testobj, test_pyobj, test_pydict, test_pylist, i % 2, bool(i % 2))) i = 93 label = u'this is row #93' treeiter = list_store.append() list_store.set_value(treeiter, 0, i) list_store.set_value(treeiter, 1, label) list_store.set_value(treeiter, 2, TestGtk.TestClass(self, i, label)) list_store.set_value(treeiter, 3, test_pyobj) list_store.set_value(treeiter, 4, test_pydict) list_store.set_value(treeiter, 5, test_pylist) list_store.set_value(treeiter, 6, 1) list_store.set_value(treeiter, 7, True) # test prepend label = 'this is row #0' list_store.prepend((0, label, TestGtk.TestClass(self, 0, label), test_pyobj, test_pydict, test_pylist, 0, False)) # test automatic unicode->str conversion i = 94 label = u'this is row #94' treeiter = list_store.append((i, label, TestGtk.TestClass(self, i, label), test_pyobj, test_pydict, test_pylist, 0, False)) # add sorted items out of order to test insert* apis # also test sending in None to not set a column i = 97 label = 'this is row #97' treeiter = list_store.append((None, None, None, test_pyobj, None, test_pylist, 1, None)) list_store.set_value(treeiter, 0, i) list_store.set_value(treeiter, 1, label) list_store.set_value(treeiter, 2, TestGtk.TestClass(self, i, label)) list_store.set_value(treeiter, 4, test_pydict) list_store.set_value(treeiter, 7, True) # this should append i = 99 label = 'this is row #99' list_store.insert(9999, (i, label, TestGtk.TestClass(self, i, label), test_pyobj, test_pydict, test_pylist, 1, True)) i = 96 label = 'this is row #96' list_store.insert_before(treeiter, (i, label, TestGtk.TestClass(self, i, label), test_pyobj, test_pydict, test_pylist, 0, False)) i = 98 label = 'this is row #98' list_store.insert_after(treeiter, (i, label, TestGtk.TestClass(self, i, label), test_pyobj, test_pydict, test_pylist, 0, False)) i = 95 label = 'this is row #95' list_store.insert(95, (i, label, TestGtk.TestClass(self, i, label), test_pyobj, test_pydict, test_pylist, 1, True)) i = 100 label = 'this is row #100' treeiter = list_store.append() list_store.set(treeiter, 1, label, 0, i, 2, TestGtk.TestClass(self, i, label), 3, test_pyobj, 4, test_pydict, 5, test_pylist, 6, 0, 7, False) i = 101 label = 'this is row #101' treeiter = list_store.append() list_store.set(treeiter, {1: label, 0: i, 2: TestGtk.TestClass(self, i, label), 3: test_pyobj, 4: test_pydict, 5: test_pylist, 6: 1, 7: True}) i = 102 label = 'this is row #102' treeiter = list_store.append() list_store.set(treeiter, (1, 0, 2, 3, 4, 5, 6, 7), (label, i, TestGtk.TestClass(self, i, label), test_pyobj, test_pydict, test_pylist, 0, False)) self.assertEqual(len(list_store), 103) # walk the list to see if the values were stored correctly i = 0 treeiter = list_store.get_iter_first() counter = 0 while treeiter: i = list_store.get_value(treeiter, 0) self.assertEqual(i, counter) s = list_store.get_value(treeiter, 1) obj = list_store.get_value(treeiter, 2) obj.check(i, s) pyobj = list_store.get_value(treeiter, 3) self.assertEqual(pyobj, test_pyobj) pydict = list_store.get_value(treeiter, 4) self.assertEqual(pydict, test_pydict) pylist = list_store.get_value(treeiter, 5) self.assertEqual(pylist, test_pylist) bool_1 = list_store.get_value(treeiter, 6) bool_2 = list_store.get_value(treeiter, 7) self.assertEqual(bool_1, bool_2) self.assertTrue(isinstance(bool_1, bool)) self.assertTrue(isinstance(bool_2, bool)) treeiter = list_store.iter_next(treeiter) counter += 1 self.assertEqual(i, 102) def test_list_store_sort(self): def comp1(model, row1, row2, user_data): v1 = model[row1][1] v2 = model[row2][1] # make "m" smaller than anything else if v1.startswith('m') and not v2.startswith('m'): return -1 if v2.startswith('m') and not v1.startswith('m'): return 1 return (v1 > v2) - (v1 < v2) list_store = Gtk.ListStore(int, str) list_store.set_sort_func(2, comp1, None) list_store.append((1, 'apples')) list_store.append((3, 'oranges')) list_store.append((2, 'mango')) # not sorted yet, should be original order self.assertEqual([list(i) for i in list_store], [[1, 'apples'], [3, 'oranges'], [2, 'mango']]) # sort with our custom function list_store.set_sort_column_id(2, Gtk.SortType.ASCENDING) self.assertEqual([list(i) for i in list_store], [[2, 'mango'], [1, 'apples'], [3, 'oranges']]) list_store.set_sort_column_id(2, Gtk.SortType.DESCENDING) self.assertEqual([list(i) for i in list_store], [[3, 'oranges'], [1, 'apples'], [2, 'mango']]) def test_list_store_signals(self): list_store = Gtk.ListStore(int, bool) def on_row_inserted(list_store, tree_path, tree_iter, signal_list): signal_list.append('row-inserted') def on_row_changed(list_store, tree_path, tree_iter, signal_list): signal_list.append('row-changed') signals = [] list_store.connect('row-inserted', on_row_inserted, signals) list_store.connect('row-changed', on_row_changed, signals) # adding rows with and without data should only call one signal list_store.append((0, False)) self.assertEqual(signals, ['row-inserted']) signals.pop() list_store.append() self.assertEqual(signals, ['row-inserted']) signals.pop() list_store.prepend((0, False)) self.assertEqual(signals, ['row-inserted']) signals.pop() list_store.prepend() self.assertEqual(signals, ['row-inserted']) signals.pop() list_store.insert(1, (0, False)) self.assertEqual(signals, ['row-inserted']) signals.pop() list_store.insert(1) self.assertEqual(signals, ['row-inserted']) # One set one signal signals.pop() tree_iter = list_store.append((10, False)) list_store.set(tree_iter, (0, 1), (20, True)) self.assertEqual(signals, ['row-inserted', 'row-changed']) def test_list_store_insert_before(self): store = Gtk.ListStore(object) signals = [] def on_row_inserted(store, tree_path, tree_iter, signal_list): signal_list.append('row-inserted') def on_row_changed(store, tree_path, tree_iter, signal_list): signal_list.append('row-changed') store.connect('row-inserted', on_row_inserted, signals) store.connect('row-changed', on_row_changed, signals) iter_ = store.append([0]) assert store.get_value(iter_, 0) == 0 assert signals == ['row-inserted'] del signals[:] # append empty iter_ = store.insert_before(None) assert store.get_path(iter_).get_indices() == [1] assert store.get_value(iter_, 0) is None assert signals == ['row-inserted'] del signals[:] # insert empty iter_ = store.insert_before(iter_) assert store.get_path(iter_).get_indices() == [1] assert store.get_value(iter_, 0) is None assert signals == ['row-inserted'] del signals[:] # append non-empty iter_ = store.insert_before(None, [1234]) assert store.get_path(iter_).get_indices() == [3] assert store.get_value(iter_, 0) == 1234 assert signals == ['row-inserted'] del signals[:] # insert non-empty iter_ = store.insert_before(iter_, [4321]) assert store.get_path(iter_).get_indices() == [3] assert store.get_value(iter_, 0) == 4321 assert signals == ['row-inserted'] del signals[:] assert [r[0] for r in store] == [0, None, None, 4321, 1234] def test_list_store_insert_after(self): store = Gtk.ListStore(object) signals = [] def on_row_inserted(store, tree_path, tree_iter, signal_list): signal_list.append('row-inserted') def on_row_changed(store, tree_path, tree_iter, signal_list): signal_list.append('row-changed') store.connect('row-inserted', on_row_inserted, signals) store.connect('row-changed', on_row_changed, signals) iter_ = store.append([0]) assert store.get_value(iter_, 0) == 0 assert signals == ['row-inserted'] del signals[:] # prepend empty iter_ = store.insert_after(None) assert store.get_path(iter_).get_indices() == [0] assert store.get_value(iter_, 0) is None assert signals == ['row-inserted'] del signals[:] # insert empty iter_ = store.insert_after(iter_) assert store.get_path(iter_).get_indices() == [1] assert store.get_value(iter_, 0) is None assert signals == ['row-inserted'] del signals[:] # prepend non-empty iter_ = store.insert_after(None, [1234]) assert store.get_path(iter_).get_indices() == [0] assert store.get_value(iter_, 0) == 1234 assert signals == ['row-inserted'] del signals[:] # insert non-empty iter_ = store.insert_after(iter_, [4321]) assert store.get_path(iter_).get_indices() == [1] assert store.get_value(iter_, 0) == 4321 assert signals == ['row-inserted'] del signals[:] assert [r[0] for r in store] == [1234, 4321, None, None, 0] def test_tree_store_insert_before(self): store = Gtk.TreeStore(object) signals = [] def on_row_inserted(store, tree_path, tree_iter, signal_list): signal_list.append('row-inserted') def on_row_changed(store, tree_path, tree_iter, signal_list): signal_list.append('row-changed') store.connect('row-inserted', on_row_inserted, signals) store.connect('row-changed', on_row_changed, signals) parent = store.append(None, [-1]) assert signals == ['row-inserted'] del signals[:] iter_ = store.append(parent, [0]) assert store.get_path(iter_).get_indices() == [0, 0] assert store.get_value(iter_, 0) == 0 assert signals == ['row-inserted'] del signals[:] # append empty iter_ = store.insert_before(parent, None) assert store.get_path(iter_).get_indices() == [0, 1] assert store.get_value(iter_, 0) is None assert signals == ['row-inserted'] del signals[:] # insert empty iter_ = store.insert_before(parent, iter_) assert store.get_path(iter_).get_indices() == [0, 1] assert store.get_value(iter_, 0) is None assert signals == ['row-inserted'] del signals[:] # append non-empty iter_ = store.insert_before(parent, None, [1234]) assert store.get_path(iter_).get_indices() == [0, 3] assert store.get_value(iter_, 0) == 1234 assert signals == ['row-inserted'] del signals[:] # insert non-empty iter_ = store.insert_before(parent, iter_, [4321]) assert store.get_path(iter_).get_indices() == [0, 3] assert store.get_value(iter_, 0) == 4321 assert signals == ['row-inserted'] del signals[:] def func(model, path, iter_, rows): rows.append((path.get_indices(), model[iter_][:])) rows = [] store.foreach(func, rows) assert rows == [ ([0], [-1]), ([0, 0], [0]), ([0, 1], [None]), ([0, 2], [None]), ([0, 3], [4321]), ([0, 4], [1234])] def test_tree_store_insert_before_none(self): store = Gtk.TreeStore(object) root = store.append(None) sub = store.append(root) iter_ = store.insert_before(None, None, [1]) assert store.get_path(iter_).get_indices() == [1] iter_ = store.insert_before(root, None, [1]) assert store.get_path(iter_).get_indices() == [0, 1] iter_ = store.insert_before(sub, None, [1]) assert store.get_path(iter_).get_indices() == [0, 0, 0] iter_ = store.insert_before(None, root, [1]) assert store.get_path(iter_).get_indices() == [0] iter_ = store.insert_before(None, sub, [1]) assert store.get_path(iter_).get_indices() == [1, 0] def test_tree_store_insert_after(self): store = Gtk.TreeStore(object) signals = [] def on_row_inserted(store, tree_path, tree_iter, signal_list): signal_list.append('row-inserted') def on_row_changed(store, tree_path, tree_iter, signal_list): signal_list.append('row-changed') store.connect('row-inserted', on_row_inserted, signals) store.connect('row-changed', on_row_changed, signals) parent = store.append(None, [-1]) assert signals == ['row-inserted'] del signals[:] iter_ = store.append(parent, [0]) assert store.get_path(iter_).get_indices() == [0, 0] assert store.get_value(iter_, 0) == 0 assert signals == ['row-inserted'] del signals[:] # append empty iter_ = store.insert_after(parent, None) assert store.get_path(iter_).get_indices() == [0, 0] assert store.get_value(iter_, 0) is None assert signals == ['row-inserted'] del signals[:] # insert empty iter_ = store.insert_after(parent, iter_) assert store.get_path(iter_).get_indices() == [0, 1] assert store.get_value(iter_, 0) is None assert signals == ['row-inserted'] del signals[:] # append non-empty iter_ = store.insert_after(parent, None, [1234]) assert store.get_path(iter_).get_indices() == [0, 0] assert store.get_value(iter_, 0) == 1234 assert signals == ['row-inserted'] del signals[:] # insert non-empty iter_ = store.insert_after(parent, iter_, [4321]) assert store.get_path(iter_).get_indices() == [0, 1] assert store.get_value(iter_, 0) == 4321 assert signals == ['row-inserted'] del signals[:] def func(model, path, iter_, rows): rows.append((path.get_indices(), model[iter_][:])) rows = [] store.foreach(func, rows) assert rows == [ ([0], [-1]), ([0, 0], [1234]), ([0, 1], [4321]), ([0, 2], [None]), ([0, 3], [None]), ([0, 4], [0])] def test_tree_store_insert_after_none(self): store = Gtk.TreeStore(object) root = store.append(None) sub = store.append(root) iter_ = store.insert_after(None, None, [1]) assert store.get_path(iter_).get_indices() == [0] iter_ = store.insert_after(root, None, [1]) assert store.get_path(iter_).get_indices() == [1, 0] iter_ = store.insert_after(sub, None, [1]) assert store.get_path(iter_).get_indices() == [1, 1, 0] iter_ = store.insert_after(None, root, [1]) assert store.get_path(iter_).get_indices() == [2] iter_ = store.insert_after(None, sub, [1]) assert store.get_path(iter_).get_indices() == [1, 2] def test_tree_path(self): p1 = Gtk.TreePath() p2 = Gtk.TreePath.new_first() self.assertEqual(p1, p2) self.assertEqual(str(p1), '0') self.assertEqual(len(p1), 1) p1 = Gtk.TreePath(2) p2 = Gtk.TreePath.new_from_string('2') self.assertEqual(p1, p2) self.assertEqual(str(p1), '2') self.assertEqual(len(p1), 1) p1 = Gtk.TreePath('1:2:3') p2 = Gtk.TreePath.new_from_string('1:2:3') self.assertEqual(p1, p2) self.assertEqual(str(p1), '1:2:3') self.assertEqual(len(p1), 3) p1 = Gtk.TreePath((1, 2, 3)) p2 = Gtk.TreePath.new_from_string('1:2:3') self.assertEqual(p1, p2) self.assertEqual(str(p1), '1:2:3') self.assertEqual(len(p1), 3) self.assertNotEqual(p1, None) self.assertTrue(p1 > None) self.assertTrue(p1 >= None) self.assertFalse(p1 < None) self.assertFalse(p1 <= None) self.assertEqual(tuple(p1), (1, 2, 3)) self.assertEqual(p1[0], 1) self.assertEqual(p1[1], 2) self.assertEqual(p1[2], 3) self.assertRaises(IndexError, p1.__getitem__, 3) def test_tree_path_empty(self): p1 = Gtk.TreePath.new() assert str(p1) == "" def test_tree_model(self): tree_store = Gtk.TreeStore(int, str) self.assertTrue(tree_store) self.assertEqual(len(tree_store), 0) self.assertEqual(tree_store.get_iter_first(), None) def get_by_index(row, col=None): if col: return tree_store[row][col] else: return tree_store[row] self.assertRaises(TypeError, get_by_index, None) self.assertRaises(TypeError, get_by_index, "") self.assertRaises(TypeError, get_by_index, ()) self.assertRaises(IndexError, get_by_index, "0") self.assertRaises(IndexError, get_by_index, 0) self.assertRaises(IndexError, get_by_index, (0,)) self.assertRaises(ValueError, tree_store.get_iter, "0") self.assertRaises(ValueError, tree_store.get_iter, 0) self.assertRaises(ValueError, tree_store.get_iter, (0,)) self.assertRaises(ValueError, tree_store.get_iter_from_string, "0") for row in tree_store: self.fail("Should not be reached") class DerivedIntType(int): pass class DerivedStrType(str): pass for i in range(100): label = 'this is row #%d' % i parent = tree_store.append(None, (DerivedIntType(i), DerivedStrType(label),)) self.assertNotEqual(parent, None) for j in range(20): label = 'this is child #%d of node #%d' % (j, i) child = tree_store.append(parent, (j, label,)) self.assertNotEqual(child, None) self.assertTrue(tree_store) self.assertEqual(len(tree_store), 100) self.assertEqual(tree_store.iter_previous(tree_store.get_iter(0)), None) for i, row in enumerate(tree_store): self.assertEqual(row.model, tree_store) self.assertEqual(row.parent, None) self.assertEqual(tree_store[i].path, row.path) self.assertEqual(tree_store[str(i)].path, row.path) self.assertEqual(tree_store[(i,)].path, row.path) self.assertEqual(tree_store[i][0], i) self.assertEqual(tree_store[i][1], "this is row #%d" % i) aiter = tree_store.get_iter(i) self.assertEqual(tree_store.get_path(aiter), row.path) aiter = tree_store.get_iter(str(i)) self.assertEqual(tree_store.get_path(aiter), row.path) aiter = tree_store.get_iter((i,)) self.assertEqual(tree_store.get_path(aiter), row.path) self.assertEqual(tree_store.iter_parent(aiter), row.parent) next = tree_store.iter_next(aiter) if i < len(tree_store) - 1: self.assertEqual(tree_store.get_path(next), row.next.path) self.assertEqual(tree_store.get_path(tree_store.iter_previous(next)), tree_store.get_path(aiter)) else: self.assertEqual(next, None) self.assertEqual(tree_store.iter_n_children(row.iter), 20) child = tree_store.iter_children(row.iter) for j, childrow in enumerate(row.iterchildren()): child_path = tree_store.get_path(child) self.assertEqual(childrow.path, child_path) self.assertEqual(childrow.parent.path, row.path) self.assertEqual(childrow.path, tree_store[child].path) self.assertEqual(childrow.path, tree_store[child_path].path) self.assertEqual(childrow[0], tree_store[child][0]) self.assertEqual(childrow[0], j) self.assertEqual(childrow[1], tree_store[child][1]) self.assertEqual(childrow[1], 'this is child #%d of node #%d' % (j, i)) self.assertRaises(IndexError, get_by_index, child, 2) tree_store[child][1] = 'this was child #%d of node #%d' % (j, i) self.assertEqual(childrow[1], 'this was child #%d of node #%d' % (j, i)) nth_child = tree_store.iter_nth_child(row.iter, j) self.assertEqual(childrow.path, tree_store.get_path(nth_child)) childrow2 = tree_store["%d:%d" % (i, j)] self.assertEqual(childrow.path, childrow2.path) childrow2 = tree_store[(i, j,)] self.assertEqual(childrow.path, childrow2.path) child = tree_store.iter_next(child) if j < 19: self.assertEqual(childrow.next.path, tree_store.get_path(child)) else: self.assertEqual(child, childrow.next) self.assertEqual(child, None) self.assertEqual(j, 19) self.assertEqual(i, 99) # negative indices for i in range(-1, -100, -1): i_real = i + 100 self.assertEqual(tree_store[i][0], i_real) row = tree_store[i] for j in range(-1, -20, -1): j_real = j + 20 path = (i_real, j_real,) self.assertEqual(tree_store[path][-2], j_real) label = 'this was child #%d of node #%d' % (j_real, i_real) self.assertEqual(tree_store[path][-1], label) new_label = 'this still is child #%d of node #%d' % (j_real, i_real) tree_store[path][-1] = new_label self.assertEqual(tree_store[path][-1], new_label) self.assertRaises(IndexError, get_by_index, path, -3) self.assertRaises(IndexError, get_by_index, -101) last_row = tree_store[99] self.assertNotEqual(last_row, None) for i, childrow in enumerate(last_row.iterchildren()): if i < 19: self.assertTrue(tree_store.remove(childrow.iter)) else: self.assertFalse(tree_store.remove(childrow.iter)) self.assertEqual(i, 19) self.assertEqual(tree_store.iter_n_children(last_row.iter), 0) for childrow in last_row.iterchildren(): self.fail("Should not be reached") aiter = tree_store.get_iter(10) self.assertRaises(TypeError, tree_store.get, aiter, 1, 'a') self.assertRaises(ValueError, tree_store.get, aiter, 1, -1) self.assertRaises(ValueError, tree_store.get, aiter, 1, 100) self.assertEqual(tree_store.get(aiter, 0, 1), (10, 'this is row #10')) # check __delitem__ self.assertEqual(len(tree_store), 100) aiter = tree_store.get_iter(10) del tree_store[aiter] self.assertEqual(len(tree_store), 99) self.assertRaises(TypeError, tree_store.__delitem__, None) self.assertRaises(IndexError, tree_store.__delitem__, -101) self.assertRaises(IndexError, tree_store.__delitem__, 101) def test_tree_model_get_iter_fail(self): # TreeModel class with a failing get_iter() class MyTreeModel(GObject.GObject, Gtk.TreeModel): def do_get_iter(self, iter): return (False, None) tm = MyTreeModel() self.assertEqual(tm.get_iter_first(), None) def test_tree_model_edit(self): model = Gtk.ListStore(int, str, float) model.append([1, "one", -0.1]) model.append([2, "two", -0.2]) def set_row(value): model[1] = value self.assertRaises(TypeError, set_row, 3) self.assertRaises(TypeError, set_row, "three") self.assertRaises(ValueError, set_row, []) self.assertRaises(ValueError, set_row, [3, "three"]) model[0] = (3, "three", -0.3) def test_tree_row_slice(self): model = Gtk.ListStore(int, str, float) model.append([1, "one", -0.1]) self.assertEqual([1, "one", -0.1], model[0][:]) self.assertEqual([1, "one"], model[0][:2]) self.assertEqual(["one", -0.1], model[0][1:]) self.assertEqual(["one"], model[0][1:-1]) self.assertEqual([1], model[0][:-2]) self.assertEqual([], model[0][5:]) self.assertEqual([1, -0.1], model[0][0:3:2]) model[0][:] = (2, "two", -0.2) self.assertEqual([2, "two", -0.2], model[0][:]) model[0][:2] = (3, "three") self.assertEqual([3, "three", -0.2], model[0][:]) model[0][1:] = ("four", -0.4) self.assertEqual([3, "four", -0.4], model[0][:]) model[0][1:-1] = ("five",) self.assertEqual([3, "five", -0.4], model[0][:]) model[0][0:3:2] = (6, -0.6) self.assertEqual([6, "five", -0.6], model[0][:]) def set_row1(): model[0][5:] = ("doesn't", "matter",) self.assertRaises(ValueError, set_row1) def set_row2(): model[0][:1] = (0, "zero", 0) self.assertRaises(ValueError, set_row2) def set_row3(): model[0][:2] = ("0", 0) self.assertRaises(TypeError, set_row3) def test_tree_row_sequence(self): model = Gtk.ListStore(int, str, float) model.append([1, "one", -0.1]) self.assertEqual([1, "one", -0.1], model[0][0, 1, 2]) self.assertEqual([1, "one"], model[0][0, 1]) self.assertEqual(["one", -0.1], model[0][1, 2]) self.assertEqual("one", model[0][1]) self.assertEqual([1, -0.1], model[0][0, 2]) self.assertEqual([-0.1, 1], model[0][2, 0]) model[0][0, 1, 2] = (2, "two", -0.2) self.assertEqual([2, "two", -0.2], model[0][0, 1, 2]) model[0][0, 1] = (3, "three") self.assertEqual([3, "three"], model[0][0, 1]) model[0][1, 2] = ("four", -0.4) self.assertEqual(["four", -0.4], model[0][1, 2]) model[0][0, 2] = (5, -0.5) self.assertEqual([5, -0.5], model[0][0, 2]) model[0][0, 1, 2] = (6, "six", -0.6) self.assertEqual([-0.6, 6, "six"], model[0][2, 0, 1]) def set_row1(): model[0][4, 5] = ("shouldn't", "work",) self.assertRaises(IndexError, set_row1) def set_row2(): model[0][0, 1] = (0, "zero", 0) self.assertRaises(ValueError, set_row2) def set_row3(): model[0][0, 1] = ("shouldn't", 0) self.assertRaises(TypeError, set_row3) def set_row4(): model[0][0, "two"] = (0, "zero") self.assertRaises(TypeError, set_row4) def test_tree_model_set_value_to_none(self): # Tests allowing the usage of None to set an empty value on a model. store = Gtk.ListStore(str) row = store.append(['test']) self.assertSequenceEqual(store[0][:], ['test']) store.set_value(row, 0, None) self.assertSequenceEqual(store[0][:], [None]) def test_signal_emission_tree_path_coerce(self): class Model(GObject.Object, Gtk.TreeModel): pass model = Model() tree_paths = [] def on_any_signal(model, path, *args): tree_paths.append(path.to_string()) model.connect('row-changed', on_any_signal) model.connect('row-deleted', on_any_signal) model.connect('row-has-child-toggled', on_any_signal) model.connect('row-inserted', on_any_signal) model.row_changed('0', Gtk.TreeIter()) self.assertEqual(tree_paths[-1], '0') model.row_deleted('1') self.assertEqual(tree_paths[-1], '1') model.row_has_child_toggled('2', Gtk.TreeIter()) self.assertEqual(tree_paths[-1], '2') model.row_inserted('3', Gtk.TreeIter()) self.assertEqual(tree_paths[-1], '3') def test_tree_model_filter(self): model = Gtk.ListStore(int, str, float) model.append([1, "one", -0.1]) model.append([2, "two", -0.2]) filtered = Gtk.TreeModelFilter(child_model=model) self.assertEqual(filtered[0][1], 'one') filtered[0][1] = 'ONE' self.assertEqual(filtered[0][1], 'ONE') def foo(store, iter_, data): assert data is None return False filtered.set_visible_func(foo) filtered.refilter() assert len(filtered) == 0 def test_list_store_performance(self): model = Gtk.ListStore(int, str) iterations = 2000 start = timeit.default_timer() i = iterations while i > 0: model.append([1, 'hello']) i -= 1 end = timeit.default_timer() sys.stderr.write('[%.0f µs/append] ' % ((end - start) * 1000000 / iterations)) def test_filter_new_default(self): # Test filter_new accepts implicit default of None model = Gtk.ListStore(int) filt = model.filter_new() self.assertTrue(filt is not None) def test_tree_store_set(self): tree_store = Gtk.TreeStore(int, int) iter_ = tree_store.append(None) tree_store.set(iter_) assert tree_store.get_value(iter_, 0) == 0 tree_store.set(iter_, 0, 42) assert tree_store.get_value(iter_, 0) == 42 assert tree_store.get_value(iter_, 1) == 0 tree_store.set(iter_, 0, 42, 1, 24) assert tree_store.get_value(iter_, 1) == 24 tree_store.set(iter_, 1, 124) assert tree_store.get_value(iter_, 1) == 124 with pytest.raises(TypeError): tree_store.set(iter_, 0, 42, "foo", 24) with pytest.raises(TypeError): tree_store.set(iter_, "foo") with pytest.raises(TypeError): tree_store.set(iter_, [1, 2, 3]) with pytest.raises(TypeError): tree_store.set(iter_, 0, 42, 24) def test_list_store_set(self): list_store = Gtk.ListStore(int, int) iter_ = list_store.append() list_store.set(iter_) assert list_store.get_value(iter_, 0) == 0 list_store.set(iter_, 0, 42) assert list_store.get_value(iter_, 0) == 42 assert list_store.get_value(iter_, 1) == 0 list_store.set(iter_, 0, 42, 1, 24) assert list_store.get_value(iter_, 1) == 24 list_store.set(iter_, 1, 124) assert list_store.get_value(iter_, 1) == 124 with pytest.raises(TypeError): list_store.set(iter_, 0, 42, "foo", 24) with pytest.raises(TypeError): list_store.set(iter_, "foo") with pytest.raises(TypeError): list_store.set(iter_, [1, 2, 3]) with pytest.raises(TypeError): list_store.set(iter_, 0, 42, 24) def test_set_default_sort_func(self): list_store = Gtk.ListStore(int) list_store.append([2]) list_store.append([1]) def sort_func(store, iter1, iter2, data): assert data is None cmp = lambda a, b: (a > b) - (a < b) return cmp(store[iter1][0], store[iter2][0]) list_store.set_default_sort_func(sort_func) list_store.set_sort_column_id( Gtk.TREE_SORTABLE_DEFAULT_SORT_COLUMN_ID, Gtk.SortType.ASCENDING) assert [v[0] for v in list_store] == [1, 2] def test_model_rows_reordered(self): list_store = Gtk.ListStore(int) list_store.append([2]) list_store.append([1]) list_store.rows_reordered(Gtk.TreePath.new_first(), None, [0, 1]) list_store.rows_reordered(0, None, [0, 1]) def test_model_set_row(self): list_store = Gtk.ListStore(int, int) list_store.append([1, 2]) iter_ = list_store.get_iter_first() list_store.set_row(iter_, [3, 4]) assert list_store[0][:] == [3, 4] list_store.set_row(iter_, [None, 7]) assert list_store[0][:] == [3, 7] list_store.set_row(iter_, [None, GObject.Value(int, 9)]) assert list_store[0][:] == [3, 9] def test_model_set_row_skip_on_none(self): list_store = Gtk.ListStore(int, int, int, int) list_store.append([1, 2, 3, 4]) iter_ = list_store.get_iter_first() list_store.set_row(iter_, [None, 7, None, 9]) assert list_store[0][:] == [1, 7, 3, 9] @unittest.skipIf(sys.platform == "darwin", "hangs") @unittest.skipUnless(Gtk, 'Gtk not available') class TestTreeView(unittest.TestCase): def test_tree_view(self): store = Gtk.ListStore(int, str) store.append((0, "foo")) store.append((1, "bar")) view = Gtk.TreeView() with realized(view): view.set_cursor(store[1].path) view.set_cursor(str(store[1].path)) view.get_cell_area(store[1].path) view.get_cell_area(str(store[1].path)) def test_tree_view_column(self): cell = Gtk.CellRendererText() col = Gtk.TreeViewColumn(title='This is just a test', cell_renderer=cell, text=0, style=2) # Regression test for: https://bugzilla.gnome.org/show_bug.cgi?id=711173 col.set_cell_data_func(cell, None, None) def test_tree_view_add_column_with_attributes(self): model = Gtk.ListStore(str, str, str) # deliberately use out-of-order sorting here; we assign column 0 to # model index 2, etc. model.append(['cell13', 'cell11', 'cell12']) model.append(['cell23', 'cell21', 'cell22']) tree = Gtk.TreeView(model=model) cell1 = Gtk.CellRendererText() cell2 = Gtk.CellRendererText() cell3 = Gtk.CellRendererText() cell4 = Gtk.CellRendererText() tree.insert_column_with_attributes(0, 'Head2', cell2, text=2) tree.insert_column_with_attributes(0, 'Head1', cell1, text=1) tree.insert_column_with_attributes(-1, 'Head3', cell3, text=0) # unconnected tree.insert_column_with_attributes(-1, 'Head4', cell4) with realized(tree): tree.set_cursor(model[0].path) if Gtk._version == "4.0": context = GLib.MainContext() while context.pending(): context.iteration(False) else: while Gtk.events_pending(): Gtk.main_iteration() self.assertEqual(tree.get_column(0).get_title(), 'Head1') self.assertEqual(tree.get_column(1).get_title(), 'Head2') self.assertEqual(tree.get_column(2).get_title(), 'Head3') self.assertEqual(tree.get_column(3).get_title(), 'Head4') # cursor should be at the first row if not GTK4: # not sure why this doesn't work with gtk4 self.assertEqual(cell1.props.text, 'cell11') self.assertEqual(cell2.props.text, 'cell12') self.assertEqual(cell3.props.text, 'cell13') self.assertEqual(cell4.props.text, None) def test_tree_view_column_set_attributes(self): store = Gtk.ListStore(int, str) directors = ['Fellini', 'Tarantino', 'Tarkovskiy'] for i, director in enumerate(directors): store.append([i, director]) treeview = Gtk.TreeView() treeview.set_model(store) column = Gtk.TreeViewColumn() treeview.append_column(column) cell = Gtk.CellRendererText() column.pack_start(cell, expand=True) column.set_attributes(cell, text=1) with realized(treeview): if not GTK4: # not sure why this doesn't work with gtk4 self.assertTrue(cell.props.text in directors) def test_tree_selection(self): store = Gtk.ListStore(int, str) for i in range(10): store.append((i, "foo")) view = Gtk.TreeView() view.set_model(store) firstpath = store.get_path(store.get_iter_first()) sel = view.get_selection() sel.select_path(firstpath) (m, s) = sel.get_selected() self.assertEqual(m, store) self.assertEqual(store.get_path(s), firstpath) sel.select_path(0) (m, s) = sel.get_selected() self.assertEqual(m, store) self.assertEqual(store.get_path(s), firstpath) sel.select_path("0:0") (m, s) = sel.get_selected() self.assertEqual(m, store) self.assertEqual(store.get_path(s), firstpath) sel.select_path((0, 0)) (m, s) = sel.get_selected() self.assertEqual(m, store) self.assertEqual(store.get_path(s), firstpath) sel.unselect_all() (m, s) = sel.get_selected() assert s is None sel.select_path(0) m, r = sel.get_selected_rows() assert m == store assert len(r) == 1 assert r[0] == store[0].path def test_scroll_to_cell(self): store = Gtk.ListStore(int, str) store.append((0, "foo")) view = Gtk.TreeView() view.set_model(store) view.scroll_to_cell(store[0].path) view.scroll_to_cell(0) @unittest.skipUnless(Gtk, 'Gtk not available') class TestTextBuffer(unittest.TestCase): def test_text_buffer(self): self.assertEqual(Gtk.TextBuffer, gi.overrides.Gtk.TextBuffer) buffer = Gtk.TextBuffer() assert buffer.get_tag_table() is not None tag = buffer.create_tag('title', font='Sans 18') self.assertEqual(tag.props.name, 'title') self.assertEqual(tag.props.font, 'Sans 18') (start, end) = buffer.get_bounds() mark = buffer.create_mark(None, start) self.assertFalse(mark.get_left_gravity()) buffer.set_text('Hello Jane Hello Bob') (start, end) = buffer.get_bounds() text = buffer.get_text(start, end, False) self.assertEqual(text, 'Hello Jane Hello Bob') buffer.set_text('') (start, end) = buffer.get_bounds() text = buffer.get_text(start, end, False) self.assertEqual(text, '') buffer.insert(end, 'HelloHello') buffer.insert(end, ' Bob') cursor_iter = end.copy() cursor_iter.backward_chars(9) buffer.place_cursor(cursor_iter) buffer.insert_at_cursor(' Jane ') (start, end) = buffer.get_bounds() text = buffer.get_text(start, end, False) self.assertEqual(text, 'Hello Jane Hello Bob') sel = buffer.get_selection_bounds() self.assertEqual(sel, ()) buffer.select_range(start, end) sel = buffer.get_selection_bounds() self.assertTrue(sel[0].equal(start)) self.assertTrue(sel[1].equal(end)) buffer.set_text('') buffer.insert_with_tags(buffer.get_start_iter(), 'HelloHello') start, end = buffer.get_bounds() text = buffer.get_text(start, end, False) self.assertEqual(text, 'HelloHello') buffer.set_text('') buffer.insert_with_tags_by_name(buffer.get_start_iter(), 'HelloHello') start, end = buffer.get_bounds() text = buffer.get_text(start, end, False) self.assertEqual(text, 'HelloHello') try: starts_tag = Gtk.TextIter.starts_tag except AttributeError: starts_tag = Gtk.TextIter.begins_tag buffer.set_text('') buffer.insert_with_tags(buffer.get_start_iter(), 'HelloHello', tag) (start, end) = buffer.get_bounds() self.assertTrue(starts_tag(start, tag)) self.assertTrue(start.has_tag(tag)) buffer.set_text('') buffer.insert_with_tags_by_name(buffer.get_start_iter(), 'HelloHello', 'title') (start, end) = buffer.get_bounds() self.assertTrue(starts_tag(start, tag)) self.assertTrue(start.has_tag(tag)) self.assertRaises(ValueError, buffer.insert_with_tags_by_name, buffer.get_start_iter(), 'HelloHello', 'unknowntag') def test_insert(self): buffer = Gtk.TextBuffer() start = buffer.get_bounds()[0] with pytest.raises(TypeError): buffer.insert(start, 42) with pytest.raises(TypeError): buffer.insert_at_cursor(42) def test_text_iter(self): try: starts_tag = Gtk.TextIter.starts_tag except AttributeError: starts_tag = Gtk.TextIter.begins_tag self.assertEqual(Gtk.TextIter, gi.overrides.Gtk.TextIter) buffer = Gtk.TextBuffer() buffer.set_text('Hello Jane Hello Bob') tag = buffer.create_tag('title', font='Sans 18') (start, end) = buffer.get_bounds() start.forward_chars(10) buffer.apply_tag(tag, start, end) self.assertTrue(starts_tag(start)) self.assertTrue(end.ends_tag()) self.assertTrue(start.toggles_tag()) self.assertTrue(end.toggles_tag()) start.backward_chars(1) self.assertFalse(starts_tag(start)) self.assertFalse(start.ends_tag()) self.assertFalse(start.toggles_tag()) def test_text_buffer_search(self): buffer = Gtk.TextBuffer() buffer.set_text('Hello World Hello GNOME') i = buffer.get_iter_at_offset(0) self.assertTrue(isinstance(i, Gtk.TextIter)) self.assertEqual(i.forward_search('world', 0, None), None) (start, end) = i.forward_search('World', 0, None) self.assertEqual(start.get_offset(), 6) self.assertEqual(end.get_offset(), 11) (start, end) = i.forward_search('world', Gtk.TextSearchFlags.CASE_INSENSITIVE, None) self.assertEqual(start.get_offset(), 6) self.assertEqual(end.get_offset(), 11) def test_insert_text_signal_location_modification(self): # Regression test for: https://bugzilla.gnome.org/show_bug.cgi?id=736175 def callback(buffer, location, text, length): location.assign(buffer.get_end_iter()) buffer = Gtk.TextBuffer() buffer.set_text('first line\n') buffer.connect('insert-text', callback) # attempt insertion at the beginning of the buffer, the callback will # modify the insert location to the end. buffer.place_cursor(buffer.get_start_iter()) buffer.insert_at_cursor('second line\n') self.assertEqual(buffer.get_property('text'), 'first line\nsecond line\n') @unittest.skipIf(gtkver() < (3, 20, 0), "broken with older gtk") def test_backward_find_char(self): buffer = Gtk.TextBuffer() buffer.set_text('abc') res = buffer.get_iter_at_line(99) if GTK4: end = res.iter else: end = res values = [] def pred_func(ch, user_data): values.append(ch) return ch == u"a" self.assertTrue(end.backward_find_char(pred_func)) self.assertEqual(values, [u"c", u"b", u"a"]) @unittest.skipUnless(Gtk, 'Gtk not available') @unittest.skipIf(Gtk_version == "4.0", "not in gtk4") class TestPaned(unittest.TestCase): def test_pack_defaults(self): p = Gtk.Paned() l1 = Gtk.Label() l2 = Gtk.Label() p.pack1(l1) p.pack2(l2) assert p.get_children() == [l1, l2] @unittest.skipUnless(Gtk, 'Gtk not available') class TestContainer(unittest.TestCase): @unittest.skipIf(Gtk_version == "4.0", "not in gtk4") def test_child_set_property(self): box = Gtk.Box() child = Gtk.Button() box.pack_start(child, expand=False, fill=True, padding=0) box.child_set_property(child, 'padding', 42) value = GObject.Value(int) box.child_get_property(child, 'padding', value) self.assertEqual(value.get_int(), 42) @unittest.skipIf(Gtk_version == "4.0", "not in gtk4") def test_child_get_property_gvalue(self): box = Gtk.Box() child = Gtk.Button() box.pack_start(child, expand=False, fill=True, padding=42) value = GObject.Value(int) box.child_get_property(child, 'padding', value) self.assertEqual(value.get_int(), 42) @unittest.skipIf(Gtk_version == "4.0", "not in gtk4") def test_child_get_property_return_with_explicit_gvalue(self): box = Gtk.Box() child = Gtk.Button() box.pack_start(child, expand=False, fill=True, padding=42) value = GObject.Value(int) result = box.child_get_property(child, 'padding', value) self.assertEqual(result, 42) @unittest.skipIf(Gtk_version == "4.0", "not in gtk4") def test_child_get_property_return_with_implicit_gvalue(self): box = Gtk.Box() child = Gtk.Button() box.pack_start(child, expand=False, fill=True, padding=42) result = box.child_get_property(child, 'padding') self.assertEqual(result, 42) @unittest.skipIf(Gtk_version == "4.0", "not in gtk4") def test_child_get_property_error(self): box = Gtk.Box() child = Gtk.Button() if Gtk_version == "4.0": box.add(child) else: box.pack_start(child, expand=False, fill=True, padding=42) with self.assertRaises(ValueError): box.child_get_property(child, 'not-a-valid-child-property') @unittest.skipIf(Gtk_version == "4.0", "not in gtk4") def test_child_get_and_set(self): box = Gtk.Box() child = Gtk.Button() box.pack_start(child, expand=True, fill=True, padding=42) expand, fill, padding = box.child_get(child, 'expand', 'fill', 'padding') self.assertEqual(expand, True) self.assertEqual(fill, True) self.assertEqual(padding, 42) box.child_set(child, expand=False, fill=False, padding=21, pack_type=1) expand, fill, padding, pack_type = box.child_get(child, 'expand', 'fill', 'padding', 'pack-type') self.assertEqual(expand, False) self.assertEqual(fill, False) self.assertEqual(padding, 21) @pytest.mark.skipif(not Gtk, reason="Test requires GTK") def test_button_focus_on_click(): b = Gtk.Button() b.set_focus_on_click(True) assert b.get_focus_on_click() b.set_focus_on_click(False) assert not b.get_focus_on_click() @pytest.mark.skipif(not Gtk, reason="Test requires GTK") @pytest.mark.parametrize( "data", [ "* { background: white; }", "* { background: white; }".encode() ] ) def test_css_provider_load_from_data(data): provider = Gtk.CssProvider.new() provider.load_from_data(data) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/tests/test_overrides_pango.py0000664000000000000000000000436315074674453020315 0ustar00rootroot# -*- Mode: Python; py-indent-offset: 4 -*- # vim: tabstop=4 shiftwidth=4 expandtab import unittest try: from gi.repository import Pango from gi.repository import PangoCairo except ImportError: Pango = None PangoCairo = None @unittest.skipUnless(Pango, 'Pango not available') class TestPango(unittest.TestCase): def test_default_font_description(self): desc = Pango.FontDescription() self.assertEqual(desc.get_variant(), Pango.Variant.NORMAL) def test_font_description(self): desc = Pango.FontDescription('monospace') self.assertEqual(desc.get_family(), 'monospace') self.assertEqual(desc.get_variant(), Pango.Variant.NORMAL) def test_layout(self): self.assertRaises(TypeError, Pango.Layout) context = Pango.Context() layout = Pango.Layout(context) self.assertEqual(layout.get_context(), context) layout.set_markup("Foobar") self.assertEqual(layout.get_text(), "Foobar") def test_layout_set_markup(self): context = Pango.Context() layout = Pango.Layout(context) layout.set_markup("abc") assert layout.get_text() == "abc" layout.set_markup("abc", -1) assert layout.get_text() == "abc" layout.set_markup("abc", 2) assert layout.get_text() == "ab" def test_layout_set_test(self): context = Pango.Context() layout = Pango.Layout(context) layout.set_text("abc") assert layout.get_text() == "abc" layout.set_text("abc", -1) assert layout.get_text() == "abc" layout.set_text("abc", 2) assert layout.get_text() == "ab" def test_break_keyword_escape(self): # https://bugzilla.gnome.org/show_bug.cgi?id=697363 self.assertTrue(hasattr(Pango, 'break_')) self.assertTrue(Pango.break_ is not None) def test_context_get_metrics(self): # Test default "language" argument font_map = PangoCairo.font_map_get_default() context = font_map.create_context() desc = Pango.FontDescription('monospace') metrics1 = context.get_metrics(desc) metrics2 = context.get_metrics(desc, context.get_language()) self.assertEqual(metrics1.get_ascent(), metrics2.get_ascent()) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/tests/test_properties.py0000664000000000000000000015101115074674453017314 0ustar00rootrootimport os import gc import sys import struct import types import unittest import tempfile import pytest from gi.repository import GObject from gi.repository.GObject import ParamFlags, GType, new from gi.repository.GObject import \ TYPE_INT, TYPE_UINT, TYPE_LONG, TYPE_ULONG, TYPE_INT64, \ TYPE_UINT64, TYPE_GTYPE, TYPE_INVALID, TYPE_NONE, TYPE_STRV, \ TYPE_INTERFACE, TYPE_CHAR, TYPE_UCHAR, TYPE_BOOLEAN, TYPE_FLOAT, \ TYPE_DOUBLE, TYPE_POINTER, TYPE_BOXED, TYPE_PARAM, TYPE_OBJECT, \ TYPE_STRING, TYPE_PYOBJECT, TYPE_VARIANT from gi.repository.GLib import \ MININT, MAXINT, MAXUINT, MINLONG, MAXLONG, MAXULONG, \ MAXUINT64, MAXINT64, MININT64 from gi.repository import Gio from gi.repository import GLib from gi.repository import GIMarshallingTests from gi.repository import Regress from gi import _propertyhelper as propertyhelper from .helper import capture_glib_warnings class PropertyObject(GObject.GObject): normal = GObject.Property(type=str) construct = GObject.Property( type=str, flags=ParamFlags.READABLE | ParamFlags.WRITABLE | ParamFlags.CONSTRUCT, default='default') construct_only = GObject.Property( type=str, flags=ParamFlags.READABLE | ParamFlags.WRITABLE | ParamFlags.CONSTRUCT_ONLY) uint64 = GObject.Property( type=TYPE_UINT64, flags=ParamFlags.READABLE | ParamFlags.WRITABLE | ParamFlags.CONSTRUCT) enum = GObject.Property( type=Gio.SocketType, default=Gio.SocketType.STREAM) boxed = GObject.Property( type=GLib.Regex, flags=ParamFlags.READABLE | ParamFlags.WRITABLE | ParamFlags.CONSTRUCT) flags = GObject.Property( type=GIMarshallingTests.Flags, flags=ParamFlags.READABLE | ParamFlags.WRITABLE | ParamFlags.CONSTRUCT, default=GIMarshallingTests.Flags.VALUE1) gtype = GObject.Property( type=TYPE_GTYPE, flags=ParamFlags.READABLE | ParamFlags.WRITABLE | ParamFlags.CONSTRUCT) strings = GObject.Property( type=TYPE_STRV, flags=ParamFlags.READABLE | ParamFlags.WRITABLE | ParamFlags.CONSTRUCT) variant = GObject.Property( type=TYPE_VARIANT, flags=ParamFlags.READABLE | ParamFlags.WRITABLE | ParamFlags.CONSTRUCT) variant_def = GObject.Property( type=TYPE_VARIANT, flags=ParamFlags.READABLE | ParamFlags.WRITABLE | ParamFlags.CONSTRUCT, default=GLib.Variant('i', 42)) interface = GObject.Property( type=Gio.File, flags=ParamFlags.READABLE | ParamFlags.WRITABLE | ParamFlags.CONSTRUCT) class PropertyInheritanceObject(Regress.TestObj): # override property from the base class, with a different type string = GObject.Property(type=int) # a property entirely defined at the Python level python_prop = GObject.Property(type=str) class PropertySubClassObject(PropertyInheritanceObject): # override property from the base class, with a different type python_prop = GObject.Property(type=int) class TestPropertyInheritanceObject(unittest.TestCase): def test_override_gi_property(self): self.assertNotEqual(Regress.TestObj.props.string.value_type, PropertyInheritanceObject.props.string.value_type) obj = PropertyInheritanceObject() self.assertEqual(type(obj.props.string), int) obj.props.string = 4 self.assertEqual(obj.props.string, 4) def test_override_python_property(self): obj = PropertySubClassObject() self.assertEqual(type(obj.props.python_prop), int) obj.props.python_prop = 5 self.assertEqual(obj.props.python_prop, 5) class TestPropertyObject(unittest.TestCase): def test_get_set(self): obj = PropertyObject() obj.props.normal = "value" self.assertEqual(obj.props.normal, "value") def test_hasattr_on_object(self): obj = PropertyObject() self.assertTrue(hasattr(obj.props, "normal")) def test_hasattr_on_class(self): self.assertTrue(hasattr(PropertyObject.props, "normal")) def test_set_on_class(self): def set(obj): obj.props.normal = "foobar" self.assertRaises(TypeError, set, PropertyObject) def test_iteration(self): for obj in (PropertyObject.props, PropertyObject().props): names = [] for pspec in obj: gtype = GType(pspec) self.assertEqual(gtype.parent.name, 'GParam') names.append(pspec.name) names.sort() self.assertEqual(names, ['boxed', 'construct', 'construct-only', 'enum', 'flags', 'gtype', 'interface', 'normal', 'strings', 'uint64', 'variant', 'variant-def']) def test_normal(self): obj = new(PropertyObject, normal="123") self.assertEqual(obj.props.normal, "123") obj.set_property('normal', '456') self.assertEqual(obj.props.normal, "456") obj.props.normal = '789' self.assertEqual(obj.props.normal, "789") def test_construct(self): obj = new(PropertyObject, construct="123") self.assertEqual(obj.props.construct, "123") obj.set_property('construct', '456') self.assertEqual(obj.props.construct, "456") obj.props.construct = '789' self.assertEqual(obj.props.construct, "789") def test_utf8(self): test_utf8 = "♥" unicode_utf8 = u"♥" obj = new(PropertyObject, construct_only=unicode_utf8) self.assertEqual(obj.props.construct_only, test_utf8) obj.set_property('construct', unicode_utf8) self.assertEqual(obj.props.construct, test_utf8) obj.props.normal = unicode_utf8 self.assertEqual(obj.props.normal, test_utf8) def test_utf8_lone_surrogate(self): obj = PropertyObject() with pytest.raises(TypeError): obj.set_property('construct', '\ud83d') def test_int_to_str(self): obj = new(PropertyObject, construct_only=1) self.assertEqual(obj.props.construct_only, '1') obj.set_property('construct', '2') self.assertEqual(obj.props.construct, '2') obj.props.normal = 3 self.assertEqual(obj.props.normal, '3') def test_construct_only(self): obj = new(PropertyObject, construct_only="123") self.assertEqual(obj.props.construct_only, "123") self.assertRaises(TypeError, setattr, obj.props, 'construct_only', '456') self.assertRaises(TypeError, obj.set_property, 'construct-only', '456') def test_uint64(self): obj = new(PropertyObject) self.assertEqual(obj.props.uint64, 0) obj.props.uint64 = 1 self.assertEqual(obj.props.uint64, 1) obj.props.uint64 = 1 self.assertEqual(obj.props.uint64, 1) self.assertRaises((TypeError, OverflowError), obj.set_property, "uint64", -1) self.assertRaises((TypeError, OverflowError), obj.set_property, "uint64", -1) def test_uint64_default_value(self): try: class TimeControl(GObject.GObject): __gproperties__ = { 'time': (TYPE_UINT64, 'Time', 'Time', 0, (1 << 64) - 1, 0, ParamFlags.READABLE) } except OverflowError: (etype, ex) = sys.exc_info()[2:] self.fail(str(ex)) def test_enum(self): obj = new(PropertyObject) self.assertEqual(obj.props.enum, Gio.SocketType.STREAM) self.assertEqual(obj.enum, Gio.SocketType.STREAM) obj.enum = Gio.SocketType.DATAGRAM self.assertEqual(obj.props.enum, Gio.SocketType.DATAGRAM) self.assertEqual(obj.enum, Gio.SocketType.DATAGRAM) obj.props.enum = Gio.SocketType.STREAM self.assertEqual(obj.props.enum, Gio.SocketType.STREAM) self.assertEqual(obj.enum, Gio.SocketType.STREAM) obj.props.enum = 2 self.assertEqual(obj.props.enum, Gio.SocketType.DATAGRAM) self.assertEqual(obj.enum, Gio.SocketType.DATAGRAM) obj.enum = 1 self.assertEqual(obj.props.enum, Gio.SocketType.STREAM) self.assertEqual(obj.enum, Gio.SocketType.STREAM) self.assertRaises(TypeError, setattr, obj, 'enum', 'foo') self.assertRaises(TypeError, setattr, obj, 'enum', object()) self.assertRaises(TypeError, GObject.Property, type=Gio.SocketType) self.assertRaises(TypeError, GObject.Property, type=Gio.SocketType, default=Gio.SocketProtocol.TCP) self.assertRaises(TypeError, GObject.Property, type=Gio.SocketType, default=object()) self.assertRaises(TypeError, GObject.Property, type=Gio.SocketType, default=1) def test_repr(self): prop = GObject.Property(type=int) assert repr(prop) == "" def test_flags(self): obj = new(PropertyObject) self.assertEqual(obj.props.flags, GIMarshallingTests.Flags.VALUE1) self.assertEqual(obj.flags, GIMarshallingTests.Flags.VALUE1) obj.flags = GIMarshallingTests.Flags.VALUE2 | GIMarshallingTests.Flags.VALUE3 self.assertEqual(obj.props.flags, GIMarshallingTests.Flags.VALUE2 | GIMarshallingTests.Flags.VALUE3) self.assertEqual(obj.flags, GIMarshallingTests.Flags.VALUE2 | GIMarshallingTests.Flags.VALUE3) self.assertRaises(TypeError, setattr, obj, 'flags', 'foo') self.assertRaises(TypeError, setattr, obj, 'flags', object()) self.assertRaises(TypeError, setattr, obj, 'flags', None) self.assertRaises(TypeError, GObject.Property, type=GIMarshallingTests.Flags, default='foo') self.assertRaises(TypeError, GObject.Property, type=GIMarshallingTests.Flags, default=object()) self.assertRaises(TypeError, GObject.Property, type=GIMarshallingTests.Flags, default=None) def test_gtype(self): obj = new(PropertyObject) self.assertEqual(obj.props.gtype, TYPE_NONE) self.assertEqual(obj.gtype, TYPE_NONE) obj.gtype = TYPE_UINT64 self.assertEqual(obj.props.gtype, TYPE_UINT64) self.assertEqual(obj.gtype, TYPE_UINT64) obj.gtype = TYPE_INVALID self.assertEqual(obj.props.gtype, TYPE_INVALID) self.assertEqual(obj.gtype, TYPE_INVALID) # GType parameters do not support defaults in GLib self.assertRaises(TypeError, GObject.Property, type=TYPE_GTYPE, default=TYPE_INT) # incompatible type self.assertRaises(TypeError, setattr, obj, 'gtype', 'foo') self.assertRaises(TypeError, setattr, obj, 'gtype', object()) self.assertRaises(TypeError, GObject.Property, type=TYPE_GTYPE, default='foo') self.assertRaises(TypeError, GObject.Property, type=TYPE_GTYPE, default=object()) # set in constructor obj = new(PropertyObject, gtype=TYPE_UINT) self.assertEqual(obj.props.gtype, TYPE_UINT) self.assertEqual(obj.gtype, TYPE_UINT) def test_boxed(self): obj = new(PropertyObject) regex = GLib.Regex.new('[a-z]*', 0, 0) obj.props.boxed = regex self.assertEqual(obj.props.boxed.get_pattern(), '[a-z]*') self.assertEqual(obj.boxed.get_pattern(), '[a-z]*') self.assertRaises(TypeError, setattr, obj, 'boxed', 'foo') self.assertRaises(TypeError, setattr, obj, 'boxed', object()) def test_strings(self): obj = new(PropertyObject) # Should work with actual GStrv objects as well as # Python string lists class GStrv(list): __gtype__ = GObject.TYPE_STRV self.assertEqual(obj.props.strings, GStrv([])) self.assertEqual(obj.strings, GStrv([])) self.assertEqual(obj.props.strings, []) self.assertEqual(obj.strings, []) obj.strings = ['hello', 'world'] self.assertEqual(obj.props.strings, ['hello', 'world']) self.assertEqual(obj.strings, ['hello', 'world']) obj.strings = GStrv(['hello', 'world']) self.assertEqual(obj.props.strings, GStrv(['hello', 'world'])) self.assertEqual(obj.strings, GStrv(['hello', 'world'])) obj.strings = [] self.assertEqual(obj.strings, []) obj.strings = GStrv([]) self.assertEqual(obj.strings, GStrv([])) p = GObject.Property(type=TYPE_STRV, default=['hello', '1']) self.assertEqual(p.default, ['hello', '1']) self.assertEqual(p.type, TYPE_STRV) p = GObject.Property(type=TYPE_STRV, default=GStrv(['hello', '1'])) self.assertEqual(p.default, ['hello', '1']) self.assertEqual(p.type, TYPE_STRV) # set in constructor obj = new(PropertyObject, strings=['hello', 'world']) self.assertEqual(obj.props.strings, ['hello', 'world']) self.assertEqual(obj.strings, ['hello', 'world']) # wrong types self.assertRaises(TypeError, setattr, obj, 'strings', 1) self.assertRaises(TypeError, setattr, obj, 'strings', 'foo') self.assertRaises(TypeError, setattr, obj, 'strings', ['foo', 1]) self.assertRaises(TypeError, GObject.Property, type=TYPE_STRV, default=1) self.assertRaises(TypeError, GObject.Property, type=TYPE_STRV, default='foo') self.assertRaises(TypeError, GObject.Property, type=TYPE_STRV, default=['hello', 1]) def test_variant(self): obj = new(PropertyObject) self.assertEqual(obj.props.variant, None) self.assertEqual(obj.variant, None) obj.variant = GLib.Variant('s', 'hello') self.assertEqual(obj.variant.print_(True), "'hello'") obj.variant = GLib.Variant('b', True) self.assertEqual(obj.variant.print_(True), "true") obj.props.variant = GLib.Variant('y', 2) self.assertEqual(obj.variant.print_(True), "byte 0x02") obj.variant = None self.assertEqual(obj.variant, None) # set in constructor obj = new(PropertyObject, variant=GLib.Variant('u', 5)) self.assertEqual(obj.props.variant.print_(True), 'uint32 5') GObject.Property(type=TYPE_VARIANT, default=GLib.Variant('i', 1)) # incompatible types self.assertRaises(TypeError, setattr, obj, 'variant', 'foo') self.assertRaises(TypeError, setattr, obj, 'variant', 42) self.assertRaises(TypeError, GObject.Property, type=TYPE_VARIANT, default='foo') self.assertRaises(TypeError, GObject.Property, type=TYPE_VARIANT, default=object()) def test_variant_default(self): obj = new(PropertyObject) self.assertEqual(obj.props.variant_def.print_(True), '42') self.assertEqual(obj.variant_def.print_(True), '42') obj.props.variant_def = GLib.Variant('y', 2) self.assertEqual(obj.variant_def.print_(True), "byte 0x02") # set in constructor obj = new(PropertyObject, variant_def=GLib.Variant('u', 5)) self.assertEqual(obj.props.variant_def.print_(True), 'uint32 5') def test_interface(self): obj = new(PropertyObject) path = os.path.join(tempfile.gettempdir(), "some", "path") file = Gio.File.new_for_path(path) obj.props.interface = file self.assertEqual(obj.props.interface.get_path(), path) self.assertEqual(obj.interface.get_path(), path) self.assertRaises(TypeError, setattr, obj, 'interface', 'foo') self.assertRaises(TypeError, setattr, obj, 'interface', object()) def test_range(self): # kiwi code def max(c): return 2 ** ((8 * struct.calcsize(c)) - 1) - 1 def umax(c): return 2 ** (8 * struct.calcsize(c)) - 1 maxint = max('i') minint = -maxint - 1 maxuint = umax('I') maxlong = max('l') minlong = -maxlong - 1 maxulong = umax('L') maxint64 = max('q') minint64 = -maxint64 - 1 maxuint64 = umax('Q') types_ = dict(int=(TYPE_INT, minint, maxint), uint=(TYPE_UINT, 0, maxuint), long=(TYPE_LONG, minlong, maxlong), ulong=(TYPE_ULONG, 0, maxulong), int64=(TYPE_INT64, minint64, maxint64), uint64=(TYPE_UINT64, 0, maxuint64)) def build_gproperties(types_): d = {} for key, (gtype, min, max) in types_.items(): d[key] = (gtype, 'blurb', 'desc', min, max, 0, ParamFlags.READABLE | ParamFlags.WRITABLE) return d class RangeCheck(GObject.GObject): __gproperties__ = build_gproperties(types_) def __init__(self): self.values = {} GObject.GObject.__init__(self) def do_set_property(self, pspec, value): self.values[pspec.name] = value def do_get_property(self, pspec): return self.values.get(pspec.name, pspec.default_value) self.assertEqual(RangeCheck.props.int.minimum, minint) self.assertEqual(RangeCheck.props.int.maximum, maxint) self.assertEqual(RangeCheck.props.uint.minimum, 0) self.assertEqual(RangeCheck.props.uint.maximum, maxuint) self.assertEqual(RangeCheck.props.long.minimum, minlong) self.assertEqual(RangeCheck.props.long.maximum, maxlong) self.assertEqual(RangeCheck.props.ulong.minimum, 0) self.assertEqual(RangeCheck.props.ulong.maximum, maxulong) self.assertEqual(RangeCheck.props.int64.minimum, minint64) self.assertEqual(RangeCheck.props.int64.maximum, maxint64) self.assertEqual(RangeCheck.props.uint64.minimum, 0) self.assertEqual(RangeCheck.props.uint64.maximum, maxuint64) obj = RangeCheck() for key, (gtype, min, max) in types_.items(): self.assertEqual(obj.get_property(key), getattr(RangeCheck.props, key).default_value) obj.set_property(key, min) self.assertEqual(obj.get_property(key), min) obj.set_property(key, max) self.assertEqual(obj.get_property(key), max) def test_multi(self): obj = PropertyObject() obj.set_properties(normal="foo", uint64=7) normal, uint64 = obj.get_properties("normal", "uint64") self.assertEqual(normal, "foo") self.assertEqual(uint64, 7) class TestProperty(unittest.TestCase): def test_simple(self): class C(GObject.GObject): str = GObject.Property(type=str) float = GObject.Property(type=float) long = GObject.Property(type=int) int = GObject.Property(type=int) self.assertTrue(hasattr(C.props, 'str')) self.assertTrue(hasattr(C.props, 'int')) self.assertTrue(hasattr(C.props, 'float')) self.assertTrue(hasattr(C.props, 'long')) o = C() self.assertEqual(o.str, '') o.str = 'str' self.assertEqual(o.str, 'str') self.assertEqual(o.int, 0) o.int = 1138 self.assertEqual(o.int, 1138) self.assertEqual(o.float, 0.0) o.float = 3.14 self.assertEqual(o.float, 3.14) self.assertEqual(o.long, 0) o.long = 100 self.assertEqual(o.long, 100) def test_custom_getter(self): class C(GObject.GObject): def get_prop(self): return 'value' prop = GObject.Property(getter=get_prop) o = C() self.assertEqual(o.prop, 'value') self.assertRaises(TypeError, setattr, o, 'prop', 'xxx') def test_getter_exception(self): class C(GObject.Object): @GObject.Property(type=int) def prop(self): raise ValueError('something bad happend') o = C() with self.assertRaisesRegex(ValueError, 'something bad happend'): o.prop with self.assertRaisesRegex(ValueError, 'something bad happend'): o.get_property('prop') with self.assertRaisesRegex(ValueError, 'something bad happend'): o.props.prop def test_custom_setter(self): class C(GObject.GObject): def set_prop(self, value): self._value = value prop = GObject.Property(setter=set_prop) def __init__(self): self._value = None GObject.GObject.__init__(self) o = C() self.assertEqual(o._value, None) o.prop = 'bar' self.assertEqual(o._value, 'bar') self.assertRaises(TypeError, getattr, o, 'prop') def test_decorator_default(self): class C(GObject.GObject): _value = 'value' @GObject.Property def value(self): return self._value @value.setter def value_setter(self, value): self._value = value o = C() self.assertEqual(o.value, 'value') o.value = 'blah' self.assertEqual(o.value, 'blah') self.assertEqual(o.props.value, 'blah') def test_decorator_private_setter(self): class C(GObject.GObject): _value = 'value' @GObject.Property def value(self): return self._value @value.setter def _set_value(self, value): self._value = value o = C() self.assertEqual(o.value, 'value') o.value = 'blah' self.assertEqual(o.value, 'blah') self.assertEqual(o.props.value, 'blah') def test_decorator_with_call(self): class C(GObject.GObject): _value = 1 @GObject.Property(type=int, default=1, minimum=1, maximum=10) def typedValue(self): return self._value @typedValue.setter def typedValue_setter(self, value): self._value = value o = C() self.assertEqual(o.typedValue, 1) o.typedValue = 5 self.assertEqual(o.typedValue, 5) self.assertEqual(o.props.typedValue, 5) def test_errors(self): self.assertRaises(TypeError, GObject.Property, type='str') self.assertRaises(TypeError, GObject.Property, nick=False) self.assertRaises(TypeError, GObject.Property, blurb=False) # this never fail while bool is a subclass of int # >>> bool.__bases__ # (,) # self.assertRaises(TypeError, GObject.Property, type=bool, default=0) self.assertRaises(TypeError, GObject.Property, type=bool, default='ciao mamma') self.assertRaises(TypeError, GObject.Property, type=bool) self.assertRaises(TypeError, GObject.Property, type=object, default=0) self.assertRaises(TypeError, GObject.Property, type=complex) def test_defaults(self): GObject.Property(type=bool, default=True) GObject.Property(type=bool, default=False) def test_name_with_underscore(self): class C(GObject.GObject): prop_name = GObject.Property(type=int) o = C() o.prop_name = 10 self.assertEqual(o.prop_name, 10) def test_range(self): types_ = [ (TYPE_INT, MININT, MAXINT), (TYPE_UINT, 0, MAXUINT), (TYPE_LONG, MINLONG, MAXLONG), (TYPE_ULONG, 0, MAXULONG), (TYPE_INT64, MININT64, MAXINT64), (TYPE_UINT64, 0, MAXUINT64), ] for gtype, min, max in types_: # Normal, everything is alright prop = GObject.Property(type=gtype, minimum=min, maximum=max) subtype = type('', (GObject.GObject,), dict(prop=prop)) self.assertEqual(subtype.props.prop.minimum, min) self.assertEqual(subtype.props.prop.maximum, max) # Lower than minimum self.assertRaises(TypeError, GObject.Property, type=gtype, minimum=min - 1, maximum=max) # Higher than maximum self.assertRaises(TypeError, GObject.Property, type=gtype, minimum=min, maximum=max + 1) def test_min_max(self): class C(GObject.GObject): prop_int = GObject.Property(type=int, minimum=1, maximum=100, default=1) prop_float = GObject.Property(type=float, minimum=0.1, maximum=10.5, default=1.1) def __init__(self): GObject.GObject.__init__(self) # we test known-bad values here which cause Gtk-WARNING logs. # Explicitly allow these for this test. with capture_glib_warnings(allow_warnings=True, allow_criticals=True): o = C() self.assertEqual(o.prop_int, 1) o.prop_int = 5 self.assertEqual(o.prop_int, 5) o.prop_int = 0 self.assertEqual(o.prop_int, 5) o.prop_int = 101 self.assertEqual(o.prop_int, 5) self.assertEqual(o.prop_float, 1.1) o.prop_float = 7.75 self.assertEqual(o.prop_float, 7.75) o.prop_float = 0.09 self.assertEqual(o.prop_float, 7.75) o.prop_float = 10.51 self.assertEqual(o.prop_float, 7.75) def test_multiple_instances(self): class C(GObject.GObject): prop = GObject.Property(type=str, default='default') o1 = C() o2 = C() self.assertEqual(o1.prop, 'default') self.assertEqual(o2.prop, 'default') o1.prop = 'value' self.assertEqual(o1.prop, 'value') self.assertEqual(o2.prop, 'default') def test_object_property(self): class PropertyObject(GObject.GObject): obj = GObject.Property(type=GObject.GObject) pobj1 = PropertyObject() obj1_hash = hash(pobj1) pobj2 = PropertyObject() pobj2.obj = pobj1 del pobj1 pobj1 = pobj2.obj self.assertEqual(hash(pobj1), obj1_hash) def test_object_subclass_property(self): class ObjectSubclass(GObject.GObject): __gtype_name__ = 'ObjectSubclass' class PropertyObjectSubclass(GObject.GObject): obj = GObject.Property(type=ObjectSubclass) PropertyObjectSubclass(obj=ObjectSubclass()) def test_property_subclass(self): # test for #470718 class A(GObject.GObject): prop1 = GObject.Property(type=int) class B(A): prop2 = GObject.Property(type=int) b = B() b.prop2 = 10 self.assertEqual(b.prop2, 10) b.prop1 = 20 self.assertEqual(b.prop1, 20) def test_property_subclass_c(self): class A(Regress.TestSubObj): prop1 = GObject.Property(type=int) a = A() a.prop1 = 10 self.assertEqual(a.prop1, 10) # also has parent properties a.props.int = 20 self.assertEqual(a.props.int, 20) # Some of which are unusable without introspection a.props.list = ("str1", "str2") self.assertEqual(a.props.list, ["str1", "str2"]) a.set_property("list", ("str3", "str4")) self.assertEqual(a.props.list, ["str3", "str4"]) def test_property_subclass_custom_setter(self): # test for #523352 class A(GObject.GObject): def get_first(self): return 'first' first = GObject.Property(type=str, getter=get_first) class B(A): def get_second(self): return 'second' second = GObject.Property(type=str, getter=get_second) a = A() self.assertEqual(a.first, 'first') self.assertRaises(TypeError, setattr, a, 'first', 'foo') b = B() self.assertEqual(b.first, 'first') self.assertRaises(TypeError, setattr, b, 'first', 'foo') self.assertEqual(b.second, 'second') self.assertRaises(TypeError, setattr, b, 'second', 'foo') def test_property_subclass_custom_setter_error(self): try: class A(GObject.GObject): def get_first(self): return 'first' first = GObject.Property(type=str, getter=get_first) def do_get_property(self, pspec): pass except TypeError: pass else: raise AssertionError # Bug 587637. def test_float_min(self): GObject.Property(type=float, minimum=-1) GObject.Property(type=GObject.TYPE_FLOAT, minimum=-1) GObject.Property(type=GObject.TYPE_DOUBLE, minimum=-1) # Bug 644039 @unittest.skipUnless(hasattr(sys, "getrefcount"), "no sys.getrefcount") def test_reference_count(self): # We can check directly if an object gets finalized, so we will # observe it indirectly through the refcount of a member object. # We create our dummy object and store its current refcount o = object() rc = sys.getrefcount(o) # We add our object as a member to our newly created object we # want to observe. Its refcount is increased by one. t = PropertyObject(normal="test") t.o = o self.assertEqual(sys.getrefcount(o), rc + 1) # Now we want to ensure we do not leak any references to our # object with properties. If no ref is leaked, then when deleting # the local reference to this object, its reference count shoud # drop to zero, and our dummy object should loose one reference. del t self.assertEqual(sys.getrefcount(o), rc) def test_doc_strings(self): class C(GObject.GObject): foo_blurbed = GObject.Property(type=int, blurb='foo_blurbed doc string') @GObject.Property def foo_getter(self): """foo_getter doc string""" return 0 self.assertEqual(C.foo_blurbed.blurb, 'foo_blurbed doc string') self.assertEqual(C.foo_blurbed.__doc__, 'foo_blurbed doc string') self.assertEqual(C.foo_getter.blurb, 'foo_getter doc string') self.assertEqual(C.foo_getter.__doc__, 'foo_getter doc string') def test_python_to_glib_type_mapping(self): tester = GObject.Property() self.assertEqual(tester._type_from_python(int), GObject.TYPE_INT) self.assertEqual(tester._type_from_python(bool), GObject.TYPE_BOOLEAN) self.assertEqual(tester._type_from_python(float), GObject.TYPE_DOUBLE) self.assertEqual(tester._type_from_python(str), GObject.TYPE_STRING) self.assertEqual(tester._type_from_python(object), GObject.TYPE_PYOBJECT) self.assertEqual(tester._type_from_python(GObject.GObject), GObject.GObject.__gtype__) self.assertEqual(tester._type_from_python(GObject.GEnum), GObject.GEnum.__gtype__) self.assertEqual(tester._type_from_python(GObject.GFlags), GObject.GFlags.__gtype__) self.assertEqual(tester._type_from_python(GObject.GBoxed), GObject.GBoxed.__gtype__) self.assertEqual(tester._type_from_python(GObject.GInterface), GObject.GInterface.__gtype__) for type_ in [TYPE_NONE, TYPE_INTERFACE, TYPE_CHAR, TYPE_UCHAR, TYPE_INT, TYPE_UINT, TYPE_BOOLEAN, TYPE_LONG, TYPE_ULONG, TYPE_INT64, TYPE_UINT64, TYPE_FLOAT, TYPE_DOUBLE, TYPE_POINTER, TYPE_BOXED, TYPE_PARAM, TYPE_OBJECT, TYPE_STRING, TYPE_PYOBJECT, TYPE_GTYPE, TYPE_STRV]: self.assertEqual(tester._type_from_python(type_), type_) self.assertRaises(TypeError, tester._type_from_python, types.CodeType) class TestInstallProperties(unittest.TestCase): # These tests only test how signalhelper.install_signals works # with the __gsignals__ dict and therefore does not need to use # GObject as a base class because that would automatically call # install_signals within the meta-class. class Base(object): __gproperties__ = {'test': (0, '', '', 0, 0, 0, 0)} class Sub1(Base): pass class Sub2(Base): @GObject.Property(type=int) def sub2test(self): return 123 class ClassWithPropertyAndGetterVFunc(object): @GObject.Property(type=int) def sub2test(self): return 123 def do_get_property(self, name): return 321 class ClassWithPropertyRedefined(object): __gproperties__ = {'test': (0, '', '', 0, 0, 0, 0)} test = GObject.Property(type=int) def setUp(self): self.assertEqual(len(self.Base.__gproperties__), 1) propertyhelper.install_properties(self.Base) self.assertEqual(len(self.Base.__gproperties__), 1) def test_subclass_without_properties_is_not_modified(self): self.assertFalse('__gproperties__' in self.Sub1.__dict__) propertyhelper.install_properties(self.Sub1) self.assertFalse('__gproperties__' in self.Sub1.__dict__) def test_subclass_with_decorator_gets_gproperties_dict(self): # Sub2 has Property instances but will not have a __gproperties__ # until install_properties is called self.assertFalse('__gproperties__' in self.Sub2.__dict__) self.assertFalse('do_get_property' in self.Sub2.__dict__) self.assertFalse('do_set_property' in self.Sub2.__dict__) propertyhelper.install_properties(self.Sub2) self.assertTrue('__gproperties__' in self.Sub2.__dict__) self.assertEqual(len(self.Base.__gproperties__), 1) self.assertEqual(len(self.Sub2.__gproperties__), 1) self.assertTrue('sub2test' in self.Sub2.__gproperties__) # get/set vfuncs should have been added self.assertTrue('do_get_property' in self.Sub2.__dict__) self.assertTrue('do_set_property' in self.Sub2.__dict__) def test_object_with_property_and_do_get_property_vfunc_raises(self): self.assertRaises(TypeError, propertyhelper.install_properties, self.ClassWithPropertyAndGetterVFunc) def test_same_name_property_definitions_raises(self): self.assertRaises(ValueError, propertyhelper.install_properties, self.ClassWithPropertyRedefined) class CPropertiesTestBase(object): # Tests for properties implemented in C not Python. def setUp(self): self.obj = GIMarshallingTests.PropertiesObject() def get_prop(self, obj, name): raise NotImplementedError def set_prop(self, obj, name, value): raise NotImplementedError # https://bugzilla.gnome.org/show_bug.cgi?id=780652 @unittest.skipUnless( "some_flags" in dir(GIMarshallingTests.PropertiesObject.props), "tool old gi") def test_flags(self): self.assertEqual( self.get_prop(self.obj, 'some-flags'), GIMarshallingTests.Flags.VALUE1) self.set_prop(self.obj, 'some-flags', GIMarshallingTests.Flags.VALUE2) self.assertEqual(self.get_prop(self.obj, 'some-flags'), GIMarshallingTests.Flags.VALUE2) obj = GIMarshallingTests.PropertiesObject( some_flags=GIMarshallingTests.Flags.VALUE3) self.assertEqual(self.get_prop(obj, 'some-flags'), GIMarshallingTests.Flags.VALUE3) # https://bugzilla.gnome.org/show_bug.cgi?id=780652 @unittest.skipUnless( "some_enum" in dir(GIMarshallingTests.PropertiesObject.props), "tool old gi") def test_enum(self): self.assertEqual( self.get_prop(self.obj, 'some-enum'), GIMarshallingTests.GEnum.VALUE1) self.set_prop(self.obj, 'some-enum', GIMarshallingTests.GEnum.VALUE2) self.assertEqual(self.get_prop(self.obj, 'some-enum'), GIMarshallingTests.GEnum.VALUE2) obj = GIMarshallingTests.PropertiesObject( some_enum=GIMarshallingTests.GEnum.VALUE3) self.assertEqual(self.get_prop(obj, 'some-enum'), GIMarshallingTests.GEnum.VALUE3) def test_boolean(self): self.assertEqual(self.get_prop(self.obj, 'some-boolean'), False) self.set_prop(self.obj, 'some-boolean', True) self.assertEqual(self.get_prop(self.obj, 'some-boolean'), True) obj = GIMarshallingTests.PropertiesObject(some_boolean=True) self.assertEqual(self.get_prop(obj, 'some-boolean'), True) def test_char(self): self.assertEqual(self.get_prop(self.obj, 'some-char'), 0) self.set_prop(self.obj, 'some-char', GLib.MAXINT8) self.assertEqual(self.get_prop(self.obj, 'some-char'), GLib.MAXINT8) obj = GIMarshallingTests.PropertiesObject(some_char=-42) self.assertEqual(self.get_prop(obj, 'some-char'), -42) with pytest.raises(OverflowError): self.set_prop(obj, 'some-char', GLib.MAXINT8 + 1) with pytest.raises(OverflowError): self.set_prop(obj, 'some-char', GLib.MININT8 - 1) self.set_prop(obj, 'some-char', b"\x44") assert self.get_prop(obj, 'some-char') == 0x44 self.set_prop(obj, 'some-char', b"\xff") assert self.get_prop(obj, 'some-char') == -1 obj = GIMarshallingTests.PropertiesObject(some_char=u"\x7f") assert self.get_prop(obj, 'some-char') == 0x7f with pytest.raises(TypeError): GIMarshallingTests.PropertiesObject(some_char=u"€") with pytest.raises(TypeError): GIMarshallingTests.PropertiesObject(some_char=u"\ud83d") def test_uchar(self): self.assertEqual(self.get_prop(self.obj, 'some-uchar'), 0) self.set_prop(self.obj, 'some-uchar', GLib.MAXUINT8) self.assertEqual(self.get_prop(self.obj, 'some-uchar'), GLib.MAXUINT8) obj = GIMarshallingTests.PropertiesObject(some_uchar=42) self.assertEqual(self.get_prop(obj, 'some-uchar'), 42) with pytest.raises(OverflowError): self.set_prop(obj, 'some-uchar', GLib.MAXUINT8 + 1) with pytest.raises(OverflowError): self.set_prop(obj, 'some-uchar', -1) self.set_prop(obj, 'some-uchar', b"\x57") assert self.get_prop(obj, 'some-uchar') == 0x57 self.set_prop(obj, 'some-uchar', b"\xff") assert self.get_prop(obj, 'some-uchar') == 255 obj = GIMarshallingTests.PropertiesObject(some_uchar=u"\x7f") assert self.get_prop(obj, 'some-uchar') == 127 with pytest.raises(TypeError): GIMarshallingTests.PropertiesObject(some_uchar=u"\x80") with pytest.raises(TypeError): GIMarshallingTests.PropertiesObject(some_uchar=u"\ud83d") def test_int(self): self.assertEqual(self.get_prop(self.obj, 'some_int'), 0) self.set_prop(self.obj, 'some-int', GLib.MAXINT) self.assertEqual(self.get_prop(self.obj, 'some_int'), GLib.MAXINT) obj = GIMarshallingTests.PropertiesObject(some_int=-42) self.assertEqual(self.get_prop(obj, 'some-int'), -42) self.assertRaises(TypeError, self.set_prop, self.obj, 'some-int', 'foo') self.assertRaises(TypeError, self.set_prop, self.obj, 'some-int', None) self.assertEqual(self.get_prop(obj, 'some-int'), -42) def test_uint(self): self.assertEqual(self.get_prop(self.obj, 'some_uint'), 0) self.set_prop(self.obj, 'some-uint', GLib.MAXUINT) self.assertEqual(self.get_prop(self.obj, 'some_uint'), GLib.MAXUINT) obj = GIMarshallingTests.PropertiesObject(some_uint=42) self.assertEqual(self.get_prop(obj, 'some-uint'), 42) self.assertRaises(TypeError, self.set_prop, self.obj, 'some-uint', 'foo') self.assertRaises(TypeError, self.set_prop, self.obj, 'some-uint', None) self.assertEqual(self.get_prop(obj, 'some-uint'), 42) def test_long(self): self.assertEqual(self.get_prop(self.obj, 'some_long'), 0) self.set_prop(self.obj, 'some-long', GLib.MAXLONG) self.assertEqual(self.get_prop(self.obj, 'some_long'), GLib.MAXLONG) obj = GIMarshallingTests.PropertiesObject(some_long=-42) self.assertEqual(self.get_prop(obj, 'some-long'), -42) self.assertRaises(TypeError, self.set_prop, self.obj, 'some-long', 'foo') self.assertRaises(TypeError, self.set_prop, self.obj, 'some-long', None) self.assertEqual(self.get_prop(obj, 'some-long'), -42) def test_ulong(self): self.assertEqual(self.get_prop(self.obj, 'some_ulong'), 0) self.set_prop(self.obj, 'some-ulong', GLib.MAXULONG) self.assertEqual(self.get_prop(self.obj, 'some_ulong'), GLib.MAXULONG) obj = GIMarshallingTests.PropertiesObject(some_ulong=42) self.assertEqual(self.get_prop(obj, 'some-ulong'), 42) self.assertRaises(TypeError, self.set_prop, self.obj, 'some-ulong', 'foo') self.assertRaises(TypeError, self.set_prop, self.obj, 'some-ulong', None) self.assertEqual(self.get_prop(obj, 'some-ulong'), 42) def test_int64(self): self.assertEqual(self.get_prop(self.obj, 'some-int64'), 0) self.set_prop(self.obj, 'some-int64', GLib.MAXINT64) self.assertEqual(self.get_prop(self.obj, 'some-int64'), GLib.MAXINT64) obj = GIMarshallingTests.PropertiesObject(some_int64=-4200000000000000) self.assertEqual(self.get_prop(obj, 'some-int64'), -4200000000000000) def test_uint64(self): self.assertEqual(self.get_prop(self.obj, 'some-uint64'), 0) self.set_prop(self.obj, 'some-uint64', GLib.MAXUINT64) self.assertEqual(self.get_prop(self.obj, 'some-uint64'), GLib.MAXUINT64) obj = GIMarshallingTests.PropertiesObject(some_uint64=4200000000000000) self.assertEqual(self.get_prop(obj, 'some-uint64'), 4200000000000000) def test_float(self): self.assertEqual(self.get_prop(self.obj, 'some-float'), 0) self.set_prop(self.obj, 'some-float', GLib.MAXFLOAT) self.assertEqual(self.get_prop(self.obj, 'some-float'), GLib.MAXFLOAT) obj = GIMarshallingTests.PropertiesObject(some_float=42.42) self.assertAlmostEqual(self.get_prop(obj, 'some-float'), 42.42, places=4) obj = GIMarshallingTests.PropertiesObject(some_float=42) self.assertAlmostEqual(self.get_prop(obj, 'some-float'), 42.0, places=4) self.assertRaises(TypeError, self.set_prop, self.obj, 'some-float', 'foo') self.assertRaises(TypeError, self.set_prop, self.obj, 'some-float', None) self.assertAlmostEqual(self.get_prop(obj, 'some-float'), 42.0, places=4) def test_double(self): self.assertEqual(self.get_prop(self.obj, 'some-double'), 0) self.set_prop(self.obj, 'some-double', GLib.MAXDOUBLE) self.assertEqual(self.get_prop(self.obj, 'some-double'), GLib.MAXDOUBLE) obj = GIMarshallingTests.PropertiesObject(some_double=42.42) self.assertAlmostEqual(self.get_prop(obj, 'some-double'), 42.42) obj = GIMarshallingTests.PropertiesObject(some_double=42) self.assertAlmostEqual(self.get_prop(obj, 'some-double'), 42.0) self.assertRaises(TypeError, self.set_prop, self.obj, 'some-double', 'foo') self.assertRaises(TypeError, self.set_prop, self.obj, 'some-double', None) self.assertAlmostEqual(self.get_prop(obj, 'some-double'), 42.0) def test_strv(self): self.assertEqual(self.get_prop(self.obj, 'some-strv'), []) self.set_prop(self.obj, 'some-strv', ['hello', 'world']) self.assertEqual(self.get_prop(self.obj, 'some-strv'), ['hello', 'world']) self.assertRaises(TypeError, self.set_prop, self.obj, 'some-strv', 1) self.assertRaises(TypeError, self.set_prop, self.obj, 'some-strv', 'foo') self.assertRaises(TypeError, self.set_prop, self.obj, 'some-strv', [1, 2]) self.assertRaises(TypeError, self.set_prop, self.obj, 'some-strv', ['foo', 1]) self.assertEqual(self.get_prop(self.obj, 'some-strv'), ['hello', 'world']) obj = GIMarshallingTests.PropertiesObject(some_strv=['hello', 'world']) self.assertEqual(self.get_prop(obj, 'some-strv'), ['hello', 'world']) # unicode on py2 obj = GIMarshallingTests.PropertiesObject(some_strv=[u'foo']) self.assertEqual(self.get_prop(obj, 'some-strv'), [u'foo']) self.assertRaises(TypeError, self.set_prop, self.obj, 'some-strv', [u'foo', 1]) def test_boxed_struct(self): self.assertEqual(self.get_prop(self.obj, 'some-boxed-struct'), None) class GStrv(list): __gtype__ = GObject.TYPE_STRV struct1 = GIMarshallingTests.BoxedStruct() struct1.long_ = 1 self.set_prop(self.obj, 'some-boxed-struct', struct1) self.assertEqual(self.get_prop(self.obj, 'some-boxed-struct').long_, 1) self.assertEqual(self.obj.some_boxed_struct.long_, 1) self.assertRaises(TypeError, self.set_prop, self.obj, 'some-boxed-struct', 1) self.assertRaises(TypeError, self.set_prop, self.obj, 'some-boxed-struct', 'foo') obj = GIMarshallingTests.PropertiesObject(some_boxed_struct=struct1) self.assertEqual(self.get_prop(obj, 'some-boxed-struct').long_, 1) def test_boxed_glist(self): self.assertEqual(self.get_prop(self.obj, 'some-boxed-glist'), []) list_ = [GLib.MININT, 42, GLib.MAXINT] self.set_prop(self.obj, 'some-boxed-glist', list_) self.assertEqual(self.get_prop(self.obj, 'some-boxed-glist'), list_) self.set_prop(self.obj, 'some-boxed-glist', []) self.assertEqual(self.get_prop(self.obj, 'some-boxed-glist'), []) self.assertRaises(TypeError, self.set_prop, self.obj, 'some-boxed-glist', 1) self.assertRaises(TypeError, self.set_prop, self.obj, 'some-boxed-glist', 'foo') self.assertRaises(TypeError, self.set_prop, self.obj, 'some-boxed-glist', ['a']) def test_annotated_glist(self): obj = Regress.TestObj() self.assertEqual(self.get_prop(obj, 'list'), []) self.set_prop(obj, 'list', ['1', '2', '3']) self.assertTrue(isinstance(self.get_prop(obj, 'list'), list)) self.assertEqual(self.get_prop(obj, 'list'), ['1', '2', '3']) @unittest.expectedFailure def test_boxed_glist_ctor(self): list_ = [GLib.MININT, 42, GLib.MAXINT] obj = GIMarshallingTests.PropertiesObject(some_boxed_glist=list_) self.assertEqual(self.get_prop(obj, 'some-boxed-glist'), list_) def test_variant(self): self.assertEqual(self.get_prop(self.obj, 'some-variant'), None) self.set_prop(self.obj, 'some-variant', GLib.Variant('o', '/myobj')) self.assertEqual(self.get_prop(self.obj, 'some-variant').get_type_string(), 'o') self.assertEqual(self.get_prop(self.obj, 'some-variant').print_(False), "'/myobj'") self.set_prop(self.obj, 'some-variant', None) self.assertEqual(self.get_prop(self.obj, 'some-variant'), None) obj = GIMarshallingTests.PropertiesObject(some_variant=GLib.Variant('b', True)) self.assertEqual(self.get_prop(obj, 'some-variant').get_type_string(), 'b') self.assertEqual(self.get_prop(obj, 'some-variant').get_boolean(), True) self.assertRaises(TypeError, self.set_prop, self.obj, 'some-variant', 'foo') self.assertRaises(TypeError, self.set_prop, self.obj, 'some-variant', 23) self.assertEqual(self.get_prop(obj, 'some-variant').get_type_string(), 'b') self.assertEqual(self.get_prop(obj, 'some-variant').get_boolean(), True) def test_setting_several_properties(self): obj = GIMarshallingTests.PropertiesObject() obj.set_properties(some_uchar=54, some_int=42) self.assertEqual(42, self.get_prop(obj, 'some-int')) self.assertEqual(54, self.get_prop(obj, 'some-uchar')) def test_gtype(self): obj = Regress.TestObj() self.assertEqual(self.get_prop(obj, 'gtype'), GObject.TYPE_INVALID) self.set_prop(obj, 'gtype', int) self.assertEqual(self.get_prop(obj, 'gtype'), GObject.TYPE_INT) obj = Regress.TestObj(gtype=int) self.assertEqual(self.get_prop(obj, 'gtype'), GObject.TYPE_INT) self.set_prop(obj, 'gtype', str) self.assertEqual(self.get_prop(obj, 'gtype'), GObject.TYPE_STRING) def test_hash_table(self): obj = Regress.TestObj() self.assertEqual(self.get_prop(obj, 'hash-table'), None) self.set_prop(obj, 'hash-table', {'mec': 56}) self.assertTrue(isinstance(self.get_prop(obj, 'hash-table'), dict)) self.assertEqual(list(self.get_prop(obj, 'hash-table').items())[0], ('mec', 56)) def test_parent_class(self): class A(Regress.TestObj): prop1 = GObject.Property(type=int) a = A() self.set_prop(a, 'int', 20) self.assertEqual(self.get_prop(a, 'int'), 20) # test parent property which needs introspection self.set_prop(a, 'list', ("str1", "str2")) self.assertEqual(self.get_prop(a, 'list'), ["str1", "str2"]) def test_held_object_ref_count_getter(self): holder = GIMarshallingTests.PropertiesObject() held = GObject.Object() self.assertEqual(holder.__grefcount__, 1) self.assertEqual(held.__grefcount__, 1) self.set_prop(holder, 'some-object', held) self.assertEqual(holder.__grefcount__, 1) initial_ref_count = held.__grefcount__ self.get_prop(holder, 'some-object') gc.collect() self.assertEqual(held.__grefcount__, initial_ref_count) def test_held_object_ref_count_setter(self): holder = GIMarshallingTests.PropertiesObject() held = GObject.Object() self.assertEqual(holder.__grefcount__, 1) self.assertEqual(held.__grefcount__, 1) # Setting property should only increase ref count by 1 self.set_prop(holder, 'some-object', held) self.assertEqual(holder.__grefcount__, 1) self.assertEqual(held.__grefcount__, 2) # Clearing should pull it back down self.set_prop(holder, 'some-object', None) self.assertEqual(held.__grefcount__, 1) def test_set_object_property_to_invalid_type(self): obj = GIMarshallingTests.PropertiesObject() self.assertRaises(TypeError, self.set_prop, obj, 'some-object', 'not_an_object') class TestCPropsAccessor(CPropertiesTestBase, unittest.TestCase): # C property tests using the "props" accessor. def get_prop(self, obj, name): return getattr(obj.props, name.replace('-', '_')) def set_prop(self, obj, name, value): setattr(obj.props, name.replace('-', '_'), value) def test_props_accessor_dir(self): # Test class props = dir(GIMarshallingTests.PropertiesObject.props) self.assertTrue('some_float' in props) self.assertTrue('some_double' in props) self.assertTrue('some_variant' in props) # Test instance obj = GIMarshallingTests.PropertiesObject() props = dir(obj.props) self.assertTrue('some_float' in props) self.assertTrue('some_double' in props) self.assertTrue('some_variant' in props) def test_param_spec_dir(self): attrs = dir(GIMarshallingTests.PropertiesObject.props.some_float) self.assertTrue('name' in attrs) self.assertTrue('nick' in attrs) self.assertTrue('blurb' in attrs) self.assertTrue('flags' in attrs) self.assertTrue('default_value' in attrs) self.assertTrue('minimum' in attrs) self.assertTrue('maximum' in attrs) class TestCGetPropertyMethod(CPropertiesTestBase, unittest.TestCase): # C property tests using the "props" accessor. def get_prop(self, obj, name): return obj.get_property(name) def set_prop(self, obj, name, value): obj.set_property(name, value) def test_gobject_inheritance_with_incomplete_initialization(): class Test: def __init__(self): # super().__init__() should have been called here pass class Bomb(Test, GObject.Object): def __init__(self): super().__init__() bomb = Bomb() with pytest.raises(RuntimeError, match="is not initialized"): bomb.qdata @pytest.mark.skipif(not hasattr(Regress, "AnnotationObject"), reason="no Regress.AnnotationObject") def test_get_function_property(): obj = Regress.AnnotationObject() with pytest.raises(TypeError): assert obj.props.function_property @pytest.mark.skipif(not hasattr(Regress, "AnnotationObject"), reason="no Regress.AnnotationObject") def test_set_function_property(): obj = Regress.AnnotationObject() with pytest.raises(TypeError): obj.props.function_property = lambda *x: x ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/tests/test_pycapi.py0000664000000000000000000000207215074674453016407 0ustar00rootrootimport unittest import ctypes from ctypes import c_void_p, py_object, c_char_p import gi from gi.repository import Gio def get_capi(): if not hasattr(ctypes, "pythonapi"): return class CAPI(ctypes.Structure): _fields_ = [ ("", c_void_p), ("", c_void_p), ("", c_void_p), ("newgobj", ctypes.PYFUNCTYPE(py_object, c_void_p)), ] api_obj = gi._gobject._PyGObject_API func_type = ctypes.PYFUNCTYPE(c_void_p, py_object, c_char_p) PyCapsule_GetPointer = func_type( ('PyCapsule_GetPointer', ctypes.pythonapi)) ptr = PyCapsule_GetPointer(api_obj, b"gobject._PyGObject_API") ptr = ctypes.cast(ptr, ctypes.POINTER(CAPI)) return ptr.contents API = get_capi() @unittest.skipUnless(API, "no pythonapi support") class TestPythonCAPI(unittest.TestCase): def test_newgobj(self): w = Gio.FileInfo() # XXX: ugh :/ ptr = int(repr(w).split()[-1].split(")")[0], 16) capi = get_capi() new_w = capi.newgobj(ptr) assert w == new_w ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/tests/test_pygtkcompat.py0000664000000000000000000002340715074674453017471 0ustar00rootroot# -*- Mode: Python; py-indent-offset: 4 -*- # vim: tabstop=4 shiftwidth=4 expandtab import unittest import base64 import warnings import pytest import gi import pygtkcompat from pygtkcompat.pygtkcompat import _disable_all as disable_all from .helper import capture_gi_deprecation_warnings, capture_glib_warnings try: from gi.repository import Gtk, Gdk except ImportError: Gtk = None else: if Gtk._version != "3.0": Gtk = None class TestGlibCompat(unittest.TestCase): def setUp(self): with warnings.catch_warnings(record=True): pygtkcompat.enable() def tearDown(self): disable_all() def test_import(self): import glib import gio glib, gio @unittest.skipUnless(Gtk, 'Gtk not available') class TestMultipleEnable(unittest.TestCase): def tearDown(self): disable_all() def test_main(self): with warnings.catch_warnings(record=True): pygtkcompat.enable() pygtkcompat.enable() def test_gtk(self): pygtkcompat.enable_gtk("3.0") pygtkcompat.enable_gtk("3.0") import gtk # https://bugzilla.gnome.org/show_bug.cgi?id=759009 w = gtk.Window() w.realize() self.assertEqual(len(w.window.get_origin()), 2) w.destroy() def test_gtk_no_4(self): self.assertRaises(ValueError, pygtkcompat.enable_gtk, version='4.0') def test_gtk_version_conflict(self): pygtkcompat.enable_gtk("3.0") self.assertRaises(ValueError, pygtkcompat.enable_gtk, version='2.0') @unittest.skipUnless(Gtk, 'Gtk not available') class TestATKCompat(unittest.TestCase): def setUp(self): pygtkcompat.enable_gtk("3.0") def tearDown(self): disable_all() def test_object(self): import atk self.assertTrue(hasattr(atk, 'Object')) @unittest.skipUnless(Gtk, 'Gtk not available') class TestPangoCompat(unittest.TestCase): def setUp(self): pygtkcompat.enable_gtk("3.0") def tearDown(self): disable_all() def test_layout(self): import pango self.assertTrue(hasattr(pango, 'Layout')) @unittest.skipUnless(Gtk, 'Gtk not available') class TestPangoCairoCompat(unittest.TestCase): def setUp(self): pygtkcompat.enable_gtk("3.0") def tearDown(self): disable_all() def test_error_underline_path(self): import pangocairo self.assertTrue(hasattr(pangocairo, 'error_underline_path')) @unittest.skipUnless(Gtk, 'Gtk not available') class TestGTKCompat(unittest.TestCase): def setUp(self): pygtkcompat.enable_gtk("3.0") def tearDown(self): disable_all() def test_window_get_frame_extents(self): import gtk import gtk.gdk w = gtk.Window() w.realize() rect = w.window.get_frame_extents() assert isinstance(rect, gtk.gdk.Rectangle) def test_window_get_geometry(self): import gtk w = gtk.Window() w.realize() with capture_gi_deprecation_warnings(): geo = w.window.get_geometry() assert isinstance(geo, tuple) assert len(geo) == 5 def test_action_set_tool_item_type(self): import gtk with pytest.warns(gi.PyGIDeprecationWarning): gtk.Action().set_tool_item_type(gtk.Action) def test_treeviewcolumn_pack(self): import gtk col = gtk.TreeViewColumn() col.pack_end(gtk.CellRendererText()) col.pack_start(gtk.CellRendererText()) def test_cell_layout_pack(self): import gtk layout = gtk.EntryCompletion() layout.pack_end(gtk.CellRendererText()) layout.pack_start(gtk.CellRendererText()) def test_cell_layout_cell_data_func(self): import gtk def func(*args): pass layout = gtk.EntryCompletion() render = gtk.CellRendererText() layout.set_cell_data_func(render, func) def test_combo_row_separator_func(self): import gtk def func(*args): pass combo = gtk.ComboBox() combo.set_row_separator_func(func) def test_container_install_child_property(self): import gtk box = gtk.Box() with pytest.warns(gi.PyGIDeprecationWarning): box.install_child_property(0, None) def test_combo_box_new_text(self): import gtk combo = gtk.combo_box_new_text() assert isinstance(combo, gtk.ComboBox) combo.append_text("foo") def test_scale(self): import gtk adjustment = gtk.Adjustment() assert gtk.HScale() assert gtk.HScale(adjustment).get_adjustment() == adjustment adjustment = gtk.Adjustment() assert gtk.VScale() assert gtk.VScale(adjustment).get_adjustment() == adjustment def test_stock_add(self): import gtk gtk.stock_add([]) def test_text_view_scroll_to_mark(self): import gtk view = gtk.TextView() buf = view.get_buffer() mark = gtk.TextMark(name="foo") buf.add_mark(mark, buf.get_end_iter()) view.scroll_to_mark(mark, 0.0) def test_window_set_geometry_hints(self): import gtk w = gtk.Window() w.set_geometry_hints(None, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10) w.set_geometry_hints(None, 0, 0, 0, 0, 0, 0, 0, 0, -1, -1) with pytest.raises(TypeError): w.set_geometry_hints(None, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0) def test_buttons(self): import gtk.gdk self.assertEqual(gtk.gdk._2BUTTON_PRESS, 5) self.assertEqual(gtk.gdk.BUTTON_PRESS, 4) def test_enums(self): import gtk self.assertEqual(gtk.WINDOW_TOPLEVEL, Gtk.WindowType.TOPLEVEL) self.assertEqual(gtk.PACK_START, Gtk.PackType.START) def test_flags(self): import gtk self.assertEqual(gtk.EXPAND, Gtk.AttachOptions.EXPAND) self.assertEqual(gtk.gdk.SHIFT_MASK, Gdk.ModifierType.SHIFT_MASK) def test_keysyms(self): import gtk.keysyms self.assertEqual(gtk.keysyms.Escape, Gdk.KEY_Escape) self.assertTrue(gtk.keysyms._0, Gdk.KEY_0) def test_style(self): import gtk widget = gtk.Button() with capture_gi_deprecation_warnings(): widget.get_style_context().set_state(gtk.STATE_NORMAL) self.assertTrue(isinstance(widget.style.base[gtk.STATE_NORMAL], gtk.gdk.Color)) def test_alignment(self): import gtk # Creation of pygtk.Alignment causes hard warnings, ignore this in testing. with capture_glib_warnings(allow_warnings=True): a = gtk.Alignment() self.assertEqual(a.props.xalign, 0.0) self.assertEqual(a.props.yalign, 0.0) self.assertEqual(a.props.xscale, 0.0) self.assertEqual(a.props.yscale, 0.0) def test_box(self): import gtk box = gtk.Box() child = gtk.Button() box.pack_start(child) expand, fill, padding, pack_type = box.query_child_packing(child) self.assertTrue(expand) self.assertTrue(fill) self.assertEqual(padding, 0) self.assertEqual(pack_type, gtk.PACK_START) child = gtk.Button() box.pack_end(child) expand, fill, padding, pack_type = box.query_child_packing(child) self.assertTrue(expand) self.assertTrue(fill) self.assertEqual(padding, 0) self.assertEqual(pack_type, gtk.PACK_END) def test_combobox_entry(self): import gtk liststore = gtk.ListStore(int, str) liststore.append((1, 'One')) liststore.append((2, 'Two')) liststore.append((3, 'Three')) # might cause a Pango warning, do not break on this with capture_glib_warnings(allow_warnings=True): combo = gtk.ComboBoxEntry(model=liststore) combo.set_text_column(1) combo.set_active(0) self.assertEqual(combo.get_text_column(), 1) self.assertEqual(combo.get_child().get_text(), 'One') combo = gtk.combo_box_entry_new() combo.set_model(liststore) combo.set_text_column(1) combo.set_active(0) self.assertEqual(combo.get_text_column(), 1) self.assertEqual(combo.get_child().get_text(), 'One') combo = gtk.combo_box_entry_new_with_model(liststore) combo.set_text_column(1) combo.set_active(0) self.assertEqual(combo.get_text_column(), 1) self.assertEqual(combo.get_child().get_text(), 'One') def test_size_request(self): import gtk box = gtk.Box() with capture_gi_deprecation_warnings(): self.assertEqual(box.size_request(), [0, 0]) def test_pixbuf(self): import gtk.gdk gtk.gdk.Pixbuf() def test_pixbuf_loader(self): import gtk.gdk # load a 1x1 pixel PNG from memory data = base64.b64decode('iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcSJAAAADUlEQVR42mP4n8Dw' 'HwAGIAJf85Z3XgAAAABJRU5ErkJggg==') loader = gtk.gdk.PixbufLoader('png') loader.write(data) loader.close() pixbuf = loader.get_pixbuf() self.assertEqual(pixbuf.get_width(), 1) self.assertEqual(pixbuf.get_height(), 1) def test_pixbuf_formats(self): import gtk.gdk formats = gtk.gdk.pixbuf_get_formats() self.assertEqual(type(formats[0]), dict) self.assertTrue('name' in formats[0]) self.assertTrue('description' in formats[0]) self.assertTrue('mime_types' in formats[0]) self.assertEqual(type(formats[0]['extensions']), list) def test_gdk_window(self): import gtk w = gtk.Window() w.realize() origin = w.get_window().get_origin() self.assertTrue(isinstance(origin, tuple)) self.assertEqual(len(origin), 2) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/tests/test_repository.py0000664000000000000000000005014315074674453017343 0ustar00rootroot# -*- Mode: Python; py-indent-offset: 4 -*- # vim: tabstop=4 shiftwidth=4 expandtab # # Copyright (C) 2013 Simon Feltman # # test_repository.py: Test for the GIRepository 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 St, Fifth Floor, Boston, MA 02110-1301 # USA import unittest from collections import abc import gi._gi as GIRepository from gi.module import repository as repo from gi.repository import GObject from gi.repository import GIMarshallingTests from gi.repository import GIRepository as IntrospectedRepository from .helper import capture_glib_warnings def find_child_info(info, getter_name, name): getter = getattr(info, getter_name) for child in getter(): if child.get_name() == name: return child else: raise ValueError('child info %s not found' % name) class Test(unittest.TestCase): def setUp(self): repo.require('GLib') repo.require('GObject') repo.require('GIMarshallingTests') def test_repo_get_dependencies(self): self.assertRaises(TypeError, repo.get_dependencies) self.assertEqual(repo.get_dependencies("GLib"), []) self.assertEqual(repo.get_dependencies("GObject"), ["GLib-2.0"]) def test_repo_is_registered(self): self.assertRaises(TypeError, repo.is_registered) self.assertRaises(TypeError, repo.is_registered, None) self.assertTrue(repo.is_registered("GIRepository")) self.assertTrue(repo.is_registered("GIRepository", None)) self.assertTrue(isinstance(repo.is_registered("GIRepository"), bool)) self.assertTrue(repo.is_registered("GIRepository", "2.0")) self.assertFalse(repo.is_registered("GIRepository", "")) self.assertFalse(repo.is_registered("GIRepository", "99.0")) self.assertFalse(repo.is_registered("GIRepository", "1.0")) def test_repo_get_immediate_dependencies(self): self.assertRaises(TypeError, repo.get_immediate_dependencies) self.assertEqual(repo.get_immediate_dependencies("GLib"), []) self.assertEqual( repo.get_immediate_dependencies("GObject"), ["GLib-2.0"]) self.assertEqual( repo.get_immediate_dependencies(namespace="GObject"), ["GLib-2.0"]) self.assertEqual( repo.get_immediate_dependencies("GIMarshallingTests"), ["Gio-2.0"]) def test_arg_info(self): func_info = repo.find_by_name('GIMarshallingTests', 'array_fixed_out_struct') args = func_info.get_arguments() self.assertTrue(len(args), 1) arg = args[0] self.assertEqual(arg.get_container(), func_info) self.assertEqual(arg.get_direction(), GIRepository.Direction.OUT) self.assertEqual(arg.get_name(), 'structs') self.assertEqual(arg.get_namespace(), 'GIMarshallingTests') self.assertFalse(arg.is_caller_allocates()) self.assertFalse(arg.is_optional()) self.assertFalse(arg.is_return_value()) self.assertFalse(arg.may_be_null()) self.assertEqual(arg.get_destroy(), -1) self.assertEqual(arg.get_ownership_transfer(), GIRepository.Transfer.NOTHING) self.assertEqual(arg.get_scope(), GIRepository.ScopeType.INVALID) self.assertEqual(arg.get_type().get_tag(), GIRepository.TypeTag.ARRAY) def test_base_info(self): info = repo.find_by_name('GIMarshallingTests', 'Object') self.assertEqual(info.__name__, 'Object') self.assertEqual(info.get_name(), 'Object') self.assertEqual(info.__module__, 'gi.repository.GIMarshallingTests') self.assertEqual(info.get_name_unescaped(), 'Object') self.assertEqual(info.get_namespace(), 'GIMarshallingTests') self.assertEqual(info.get_container(), None) info2 = repo.find_by_name('GIMarshallingTests', 'Object') self.assertFalse(info is info2) self.assertEqual(info, info2) self.assertTrue(info.equal(info2)) assert isinstance(info.is_deprecated(), bool) assert isinstance(info.get_type(), int) assert info.get_attribute("nopenope") is None def test_object_info(self): info = repo.find_by_name('GIMarshallingTests', 'Object') self.assertEqual(info.get_parent(), repo.find_by_name('GObject', 'Object')) self.assertTrue(isinstance(info.get_methods(), abc.Iterable)) self.assertTrue(isinstance(info.get_fields(), abc.Iterable)) self.assertTrue(isinstance(info.get_interfaces(), abc.Iterable)) self.assertTrue(isinstance(info.get_constants(), abc.Iterable)) self.assertTrue(isinstance(info.get_vfuncs(), abc.Iterable)) self.assertTrue(isinstance(info.get_properties(), abc.Iterable)) self.assertFalse(info.get_abstract()) self.assertEqual(info.get_class_struct(), repo.find_by_name('GIMarshallingTests', 'ObjectClass')) self.assertEqual(info.get_type_name(), 'GIMarshallingTestsObject') self.assertEqual(info.get_type_init(), 'gi_marshalling_tests_object_get_type') self.assertFalse(info.get_fundamental()) self.assertEqual(info.get_parent(), repo.find_by_name('GObject', 'Object')) assert info.find_vfunc("nopenope") is None vfunc = info.find_vfunc("method_int8_out") assert isinstance(vfunc, GIRepository.VFuncInfo) def test_callable_inheritance(self): self.assertTrue(issubclass(GIRepository.CallableInfo, GIRepository.BaseInfo)) self.assertTrue(issubclass(GIRepository.CallbackInfo, GIRepository.CallableInfo)) self.assertTrue(issubclass(GIRepository.FunctionInfo, GIRepository.CallableInfo)) self.assertTrue(issubclass(GIRepository.VFuncInfo, GIRepository.CallableInfo)) self.assertTrue(issubclass(GIRepository.SignalInfo, GIRepository.CallableInfo)) def test_registered_type_info(self): info = repo.find_by_name('GIMarshallingTests', 'Object') # Call these from the class because GIObjectInfo overrides them self.assertEqual(GIRepository.RegisteredTypeInfo.get_g_type(info), GObject.type_from_name('GIMarshallingTestsObject')) self.assertEqual(GIRepository.RegisteredTypeInfo.get_type_name(info), 'GIMarshallingTestsObject') self.assertEqual(GIRepository.RegisteredTypeInfo.get_type_init(info), 'gi_marshalling_tests_object_get_type') def test_fundamental_object_info(self): repo.require('Regress') info = repo.find_by_name('Regress', 'TestFundamentalObject') self.assertTrue(info.get_abstract()) self.assertTrue(info.get_fundamental()) self.assertEqual(info.get_ref_function(), 'regress_test_fundamental_object_ref') self.assertEqual(info.get_unref_function(), 'regress_test_fundamental_object_unref') self.assertEqual(info.get_get_value_function(), 'regress_test_value_get_fundamental_object') self.assertEqual(info.get_set_value_function(), 'regress_test_value_set_fundamental_object') def test_interface_info(self): info = repo.find_by_name('GIMarshallingTests', 'Interface') self.assertTrue(isinstance(info.get_methods(), abc.Iterable)) self.assertTrue(isinstance(info.get_vfuncs(), abc.Iterable)) self.assertTrue(isinstance(info.get_constants(), abc.Iterable)) self.assertTrue(isinstance(info.get_prerequisites(), abc.Iterable)) self.assertTrue(isinstance(info.get_properties(), abc.Iterable)) self.assertTrue(isinstance(info.get_signals(), abc.Iterable)) method = info.find_method('test_int8_in') vfunc = info.find_vfunc('test_int8_in') self.assertEqual(method.get_name(), 'test_int8_in') self.assertEqual(vfunc.get_invoker(), method) self.assertEqual(method.get_vfunc(), vfunc) iface = info.get_iface_struct() self.assertEqual(iface, repo.find_by_name('GIMarshallingTests', 'InterfaceIface')) assert info.find_signal("nopenope") is None def test_struct_info(self): info = repo.find_by_name('GIMarshallingTests', 'InterfaceIface') self.assertTrue(isinstance(info, GIRepository.StructInfo)) self.assertTrue(isinstance(info.get_fields(), abc.Iterable)) self.assertTrue(isinstance(info.get_methods(), abc.Iterable)) self.assertTrue(isinstance(info.get_size(), int)) self.assertTrue(isinstance(info.get_alignment(), int)) self.assertTrue(info.is_gtype_struct()) self.assertFalse(info.is_foreign()) info = repo.find_by_name('GIMarshallingTests', 'SimpleStruct') assert info.find_method("nope") is None assert isinstance(info.find_method("method"), GIRepository.FunctionInfo) assert info.find_field("nope") is None assert isinstance(info.find_field("int8"), GIRepository.FieldInfo) def test_enum_info(self): info = repo.find_by_name('GIMarshallingTests', 'Enum') self.assertTrue(isinstance(info, GIRepository.EnumInfo)) self.assertTrue(isinstance(info.get_values(), abc.Iterable)) self.assertTrue(isinstance(info.get_methods(), abc.Iterable)) self.assertFalse(info.is_flags()) self.assertTrue(info.get_storage_type() > 0) # might be platform dependent def test_union_info(self): info = repo.find_by_name('GIMarshallingTests', 'Union') self.assertTrue(isinstance(info, GIRepository.UnionInfo)) self.assertTrue(isinstance(info.get_fields(), abc.Iterable)) self.assertTrue(isinstance(info.get_methods(), abc.Iterable)) self.assertTrue(isinstance(info.get_size(), int)) self.assertTrue(isinstance(info.get_alignment(), int)) def test_type_info(self): func_info = repo.find_by_name('GIMarshallingTests', 'array_fixed_out_struct') arg_info, = func_info.get_arguments() type_info = arg_info.get_type() self.assertTrue(type_info.is_pointer()) self.assertEqual(type_info.get_tag(), GIRepository.TypeTag.ARRAY) self.assertEqual(type_info.get_tag_as_string(), 'array') self.assertEqual(type_info.get_param_type(0).get_tag(), GIRepository.TypeTag.INTERFACE) self.assertEqual(type_info.get_param_type(0).get_interface(), repo.find_by_name('GIMarshallingTests', 'SimpleStruct')) self.assertEqual(type_info.get_interface(), None) self.assertEqual(type_info.get_array_length(), -1) self.assertEqual(type_info.get_array_fixed_size(), 2) self.assertFalse(type_info.is_zero_terminated()) self.assertEqual(type_info.get_array_type(), GIRepository.ArrayType.C) def test_field_info(self): info = repo.find_by_name('GIMarshallingTests', 'InterfaceIface') field = find_child_info(info, 'get_fields', 'test_int8_in') self.assertEqual(field.get_name(), 'test_int8_in') self.assertTrue(field.get_flags() & GIRepository.FieldInfoFlags.IS_READABLE) self.assertFalse(field.get_flags() & GIRepository.FieldInfoFlags.IS_WRITABLE) self.assertEqual(field.get_type().get_tag(), GIRepository.TypeTag.INTERFACE) # don't test actual values because that might fail with architecture differences self.assertTrue(isinstance(field.get_size(), int)) self.assertTrue(isinstance(field.get_offset(), int)) def test_property_info(self): info = repo.find_by_name('GIMarshallingTests', 'PropertiesObject') prop = find_child_info(info, 'get_properties', 'some-object') flags = GObject.ParamFlags.READABLE | GObject.ParamFlags.WRITABLE | GObject.ParamFlags.CONSTRUCT self.assertEqual(prop.get_flags(), flags) self.assertEqual(prop.get_type().get_tag(), GIRepository.TypeTag.INTERFACE) self.assertEqual(prop.get_type().get_interface(), repo.find_by_name('GObject', 'Object')) self.assertEqual(prop.get_ownership_transfer(), GIRepository.Transfer.NOTHING) def test_callable_info(self): func_info = repo.find_by_name('GIMarshallingTests', 'array_fixed_out_struct') self.assertTrue(hasattr(func_info, 'invoke')) self.assertTrue(isinstance(func_info.get_arguments(), abc.Iterable)) self.assertEqual(func_info.get_caller_owns(), GIRepository.Transfer.NOTHING) self.assertFalse(func_info.may_return_null()) self.assertEqual(func_info.get_return_type().get_tag(), GIRepository.TypeTag.VOID) self.assertRaises(AttributeError, func_info.get_return_attribute, '_not_an_attr') def test_signal_info(self): repo.require('Regress') info = repo.find_by_name('Regress', 'TestObj') sig_info = find_child_info(info, 'get_signals', 'test') sig_flags = GObject.SignalFlags.RUN_LAST | \ GObject.SignalFlags.NO_RECURSE | GObject.SignalFlags.NO_HOOKS self.assertTrue(sig_info is not None) self.assertTrue(isinstance(sig_info, GIRepository.CallableInfo)) self.assertTrue(isinstance(sig_info, GIRepository.SignalInfo)) self.assertEqual(sig_info.get_name(), 'test') self.assertEqual(sig_info.get_class_closure(), None) self.assertFalse(sig_info.true_stops_emit()) self.assertEqual(sig_info.get_flags(), sig_flags) def test_notify_signal_info_with_obj(self): repo.require('Regress') info = repo.find_by_name('Regress', 'TestObj') sig_info = find_child_info(info, 'get_signals', 'sig-with-array-prop') sig_flags = GObject.SignalFlags.RUN_LAST self.assertTrue(sig_info is not None) self.assertTrue(isinstance(sig_info, GIRepository.CallableInfo)) self.assertTrue(isinstance(sig_info, GIRepository.SignalInfo)) self.assertEqual(sig_info.get_name(), 'sig-with-array-prop') self.assertEqual(sig_info.get_class_closure(), None) self.assertFalse(sig_info.true_stops_emit()) self.assertEqual(sig_info.get_flags(), sig_flags) def test_object_constructor(self): info = repo.find_by_name('GIMarshallingTests', 'Object') method = find_child_info(info, 'get_methods', 'new') self.assertTrue(isinstance(method, GIRepository.CallableInfo)) self.assertTrue(isinstance(method, GIRepository.FunctionInfo)) self.assertTrue(method in info.get_methods()) self.assertEqual(method.get_name(), 'new') self.assertFalse(method.is_method()) self.assertTrue(method.is_constructor()) self.assertEqual(method.get_symbol(), 'gi_marshalling_tests_object_new') flags = method.get_flags() self.assertFalse(flags & GIRepository.FunctionInfoFlags.IS_METHOD) self.assertTrue(flags & GIRepository.FunctionInfoFlags.IS_CONSTRUCTOR) self.assertFalse(flags & GIRepository.FunctionInfoFlags.IS_GETTER) self.assertFalse(flags & GIRepository.FunctionInfoFlags.IS_SETTER) self.assertFalse(flags & GIRepository.FunctionInfoFlags.WRAPS_VFUNC) self.assertFalse(flags & GIRepository.FunctionInfoFlags.THROWS) def test_method_info(self): info = repo.find_by_name('GIMarshallingTests', 'Object') method = find_child_info(info, 'get_methods', 'vfunc_return_value_only') self.assertTrue(isinstance(method, GIRepository.CallableInfo)) self.assertTrue(isinstance(method, GIRepository.FunctionInfo)) self.assertTrue(method in info.get_methods()) self.assertEqual(method.get_name(), 'vfunc_return_value_only') self.assertFalse(method.is_constructor()) self.assertEqual(method.get_symbol(), 'gi_marshalling_tests_object_vfunc_return_value_only') self.assertTrue(method.is_method()) flags = method.get_flags() self.assertTrue(flags & GIRepository.FunctionInfoFlags.IS_METHOD) self.assertFalse(flags & GIRepository.FunctionInfoFlags.IS_CONSTRUCTOR) self.assertFalse(flags & GIRepository.FunctionInfoFlags.IS_GETTER) self.assertFalse(flags & GIRepository.FunctionInfoFlags.IS_SETTER) self.assertFalse(flags & GIRepository.FunctionInfoFlags.WRAPS_VFUNC) self.assertFalse(flags & GIRepository.FunctionInfoFlags.THROWS) def test_vfunc_info(self): info = repo.find_by_name('GIMarshallingTests', 'Object') invoker = find_child_info(info, 'get_methods', 'vfunc_return_value_only') vfunc = find_child_info(info, 'get_vfuncs', 'vfunc_return_value_only') self.assertTrue(isinstance(vfunc, GIRepository.CallableInfo)) self.assertTrue(isinstance(vfunc, GIRepository.VFuncInfo)) self.assertEqual(vfunc.get_name(), 'vfunc_return_value_only') self.assertEqual(vfunc.get_invoker(), invoker) self.assertEqual(invoker, info.find_method('vfunc_return_value_only')) self.assertEqual(vfunc.get_flags(), 0) self.assertEqual(vfunc.get_offset(), 0xFFFF) # unknown offset self.assertEqual(vfunc.get_signal(), None) def test_callable_can_throw_gerror(self): info = repo.find_by_name('GIMarshallingTests', 'Object') invoker = find_child_info(info, 'get_methods', 'vfunc_meth_with_error') vfunc = find_child_info(info, 'get_vfuncs', 'vfunc_meth_with_err') self.assertTrue(invoker.can_throw_gerror()) self.assertTrue(vfunc.can_throw_gerror()) # Test that args do not include the GError** self.assertEqual(len(invoker.get_arguments()), 1) self.assertEqual(len(vfunc.get_arguments()), 1) # Sanity check method that does not throw. invoker_no_throws = find_child_info(info, 'get_methods', 'method_int8_in') self.assertFalse(invoker_no_throws.can_throw_gerror()) def test_flags_double_registration_error(self): # a warning is printed for double registration and pygobject will # also raise a RuntimeError. GIMarshallingTests.NoTypeFlags # cause flags registration info = repo.find_by_name('GIMarshallingTests', 'NoTypeFlags') with capture_glib_warnings(allow_warnings=True, allow_criticals=True): self.assertRaises(RuntimeError, GIRepository.flags_register_new_gtype_and_add, info) def test_enum_double_registration_error(self): # a warning is printed for double registration and pygobject will # also raise a RuntimeError. GIMarshallingTests.Enum # cause enum registration info = repo.find_by_name('GIMarshallingTests', 'Enum') with capture_glib_warnings(allow_warnings=True, allow_criticals=True): self.assertRaises(RuntimeError, GIRepository.enum_register_new_gtype_and_add, info) def test_enums(self): self.assertTrue(hasattr(GIRepository, 'Direction')) self.assertTrue(hasattr(GIRepository, 'Transfer')) self.assertTrue(hasattr(GIRepository, 'ArrayType')) self.assertTrue(hasattr(GIRepository, 'ScopeType')) self.assertTrue(hasattr(GIRepository, 'VFuncInfoFlags')) self.assertTrue(hasattr(GIRepository, 'FieldInfoFlags')) self.assertTrue(hasattr(GIRepository, 'FunctionInfoFlags')) self.assertTrue(hasattr(GIRepository, 'TypeTag')) self.assertTrue(hasattr(GIRepository, 'InfoType')) def test_introspected_argument_info(self): self.assertTrue(isinstance(IntrospectedRepository.Argument.__info__, GIRepository.UnionInfo)) arg = IntrospectedRepository.Argument() self.assertTrue(isinstance(arg.__info__, GIRepository.UnionInfo)) old_info = IntrospectedRepository.Argument.__info__ IntrospectedRepository.Argument.__info__ = 'not an info' self.assertRaises(TypeError, IntrospectedRepository.Argument) IntrospectedRepository.Argument.__info__ = old_info ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/tests/test_resulttuple.py0000664000000000000000000000575715074674453017527 0ustar00rootroot# -*- Mode: Python; py-indent-offset: 4 -*- # vim: tabstop=4 shiftwidth=4 expandtab # # Copyright (C) 2015 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, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 # USA import unittest import pickle import gi from gi.repository import GIMarshallingTests from gi.repository import Regress ResultTuple = gi._gi.ResultTuple class TestResultTuple(unittest.TestCase): def test_base(self): self.assertTrue(issubclass(ResultTuple, tuple)) def test_create(self): names = [None, "foo", None, "bar"] for i in range(10): new = ResultTuple._new_type(names) self.assertTrue(issubclass(new, ResultTuple)) def test_repr_dir(self): new = ResultTuple._new_type([None, "foo", None, "bar"]) inst = new([1, 2, 3, "a"]) self.assertEqual(repr(inst), "(1, foo=2, 3, bar='a')") self.assertTrue("foo" in dir(inst)) def test_repr_dir_empty(self): new = ResultTuple._new_type([]) inst = new() self.assertEqual(repr(inst), "()") dir(inst) def test_getatttr(self): new = ResultTuple._new_type([None, "foo", None, "bar"]) inst = new([1, 2, 3, "a"]) self.assertTrue(hasattr(inst, "foo")) self.assertEqual(inst.foo, inst[1]) self.assertRaises(AttributeError, getattr, inst, "nope") def test_pickle(self): new = ResultTuple._new_type([None, "foo", None, "bar"]) inst = new([1, 2, 3, "a"]) inst2 = pickle.loads(pickle.dumps(inst)) self.assertEqual(inst2, inst) self.assertTrue(isinstance(inst2, tuple)) self.assertFalse(isinstance(inst2, new)) def test_gi(self): res = GIMarshallingTests.init_function([]) self.assertEqual(repr(res), "(True, argv=[])") res = GIMarshallingTests.array_return_etc(5, 9) self.assertEqual(repr(res), "([5, 0, 1, 9], sum=14)") res = GIMarshallingTests.array_out_etc(-5, 9) self.assertEqual(repr(res), "(ints=[-5, 0, 1, 9], sum=4)") cb = lambda: (1, 2) res = GIMarshallingTests.callback_multiple_out_parameters(cb) self.assertEqual(repr(res), "(a=1.0, b=2.0)") def test_regress(self): res = Regress.TestObj().skip_return_val(50, 42.0, 60, 2, 3) self.assertEqual(repr(res), "(out_b=51, inout_d=61, out_sum=32)") ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/tests/test_signal.py0000664000000000000000000015364215074674453016411 0ustar00rootroot# -*- Mode: Python -*- import gc import unittest import sys import weakref import threading import time from gi.repository import GObject, GLib, Regress, Gio from gi import _signalhelper as signalhelper from gi.module import repository as repo import testhelper from .helper import capture_glib_warnings, capture_gi_deprecation_warnings class C(GObject.GObject): __gsignals__ = {'my_signal': (GObject.SignalFlags.RUN_FIRST, None, (GObject.TYPE_INT,))} def do_my_signal(self, arg): self.arg = arg class D(C): def do_my_signal(self, arg2): self.arg2 = arg2 C.do_my_signal(self, arg2) class TestSignalCreation(unittest.TestCase): # Bug 540376. def test_illegals(self): self.assertRaises(TypeError, lambda: GObject.signal_new('test', None, 0, None, (GObject.TYPE_LONG,))) class TestChaining(unittest.TestCase): def setUp(self): self.inst = C() self.inst.connect("my_signal", self.my_signal_handler_cb, 1, 2, 3) def my_signal_handler_cb(self, *args): assert len(args) == 5 assert isinstance(args[0], C) assert args[0] == self.inst assert isinstance(args[1], int) assert args[1] == 42 assert args[2:] == (1, 2, 3) def test_chaining(self): self.inst.emit("my_signal", 42) assert self.inst.arg == 42 def test_chaining2(self): inst2 = D() inst2.emit("my_signal", 44) assert inst2.arg == 44 assert inst2.arg2 == 44 # This is for bug 153718 class TestGSignalsError(unittest.TestCase): def test_invalid_type(self, *args): def foo(): class Foo(GObject.GObject): __gsignals__ = None self.assertRaises(TypeError, foo) gc.collect() def test_invalid_name(self, *args): def foo(): class Foo(GObject.GObject): __gsignals__ = {'not-exists': 'override'} with capture_glib_warnings(allow_warnings=True): self.assertRaises(TypeError, foo) gc.collect() class TestGPropertyError(unittest.TestCase): def test_invalid_type(self, *args): def foo(): class Foo(GObject.GObject): __gproperties__ = None self.assertRaises(TypeError, foo) gc.collect() def test_invalid_name(self, *args): def foo(): class Foo(GObject.GObject): __gproperties__ = {None: None} self.assertRaises(TypeError, foo) gc.collect() class TestList(unittest.TestCase): def test_list_names(self): self.assertEqual(GObject.signal_list_names(C), ('my-signal',)) def my_accumulator(ihint, return_accu, handler_return, user_data): """An accumulator that stops emission when the sum of handler returned values reaches 3""" assert user_data == "accum data" if return_accu >= 3: return False, return_accu return True, return_accu + handler_return class Foo(GObject.GObject): my_acc_signal = GObject.Signal(return_type=GObject.TYPE_INT, flags=GObject.SignalFlags.RUN_LAST, accumulator=my_accumulator, accu_data="accum data") my_other_acc_signal = GObject.Signal(return_type=GObject.TYPE_BOOLEAN, flags=GObject.SignalFlags.RUN_LAST, accumulator=GObject.signal_accumulator_true_handled) my_acc_first_wins = GObject.Signal(return_type=GObject.TYPE_BOOLEAN, flags=GObject.SignalFlags.RUN_LAST, accumulator=GObject.signal_accumulator_first_wins) class TestAccumulator(unittest.TestCase): def test_accumulator(self): inst = Foo() inst.my_acc_signal.connect(lambda obj: 1) inst.my_acc_signal.connect(lambda obj: 2) # the value returned in the following handler will not be # considered, because at this point the accumulator already # reached its limit. inst.my_acc_signal.connect(lambda obj: 3) retval = inst.my_acc_signal.emit() self.assertEqual(retval, 3) def test_accumulator_true_handled(self): inst = Foo() inst.my_other_acc_signal.connect(self._true_handler1) inst.my_other_acc_signal.connect(self._true_handler2) # the following handler will not be called because handler2 # returns True, so it should stop the emission. inst.my_other_acc_signal.connect(self._true_handler3) self.__true_val = None inst.my_other_acc_signal.emit() self.assertEqual(self.__true_val, 2) def test_accumulator_first_wins(self): # First signal hit will always win inst = Foo() inst.my_acc_first_wins.connect(self._true_handler3) inst.my_acc_first_wins.connect(self._true_handler1) inst.my_acc_first_wins.connect(self._true_handler2) self.__true_val = None inst.my_acc_first_wins.emit() self.assertEqual(self.__true_val, 3) def _true_handler1(self, obj): self.__true_val = 1 return False def _true_handler2(self, obj): self.__true_val = 2 return True def _true_handler3(self, obj): self.__true_val = 3 return False class E(GObject.GObject): __gsignals__ = {'signal': (GObject.SignalFlags.RUN_FIRST, None, ())} # Property used to test detailed signal prop = GObject.Property(type=int, default=0) def __init__(self): GObject.GObject.__init__(self) self.status = 0 def do_signal(self): assert self.status == 0 self.status = 1 class F(GObject.GObject): __gsignals__ = {'signal': (GObject.SignalFlags.RUN_FIRST, None, ())} def __init__(self): GObject.GObject.__init__(self) self.status = 0 def do_signal(self): self.status += 1 class TestEmissionHook(unittest.TestCase): def test_add(self): self.hook = True e = E() e.connect('signal', self._callback) GObject.add_emission_hook(E, "signal", self._emission_hook) e.emit('signal') self.assertEqual(e.status, 3) def test_remove(self): self.hook = False e = E() e.connect('signal', self._callback) hook_id = GObject.add_emission_hook(E, "signal", self._emission_hook) GObject.remove_emission_hook(E, "signal", hook_id) e.emit('signal') self.assertEqual(e.status, 3) def _emission_hook(self, e): self.assertEqual(e.status, 1) e.status = 2 def _callback(self, e): if self.hook: self.assertEqual(e.status, 2) else: self.assertEqual(e.status, 1) e.status = 3 def test_callback_return_false(self): self.hook = False obj = F() def _emission_hook(obj): obj.status += 1 return False GObject.add_emission_hook(obj, "signal", _emission_hook) obj.emit('signal') obj.emit('signal') self.assertEqual(obj.status, 3) def test_callback_return_true(self): self.hook = False obj = F() def _emission_hook(obj): obj.status += 1 return True hook_id = GObject.add_emission_hook(obj, "signal", _emission_hook) obj.emit('signal') obj.emit('signal') GObject.remove_emission_hook(obj, "signal", hook_id) self.assertEqual(obj.status, 4) def test_callback_return_true_but_remove(self): self.hook = False obj = F() def _emission_hook(obj): obj.status += 1 return True hook_id = GObject.add_emission_hook(obj, "signal", _emission_hook) obj.emit('signal') GObject.remove_emission_hook(obj, "signal", hook_id) obj.emit('signal') self.assertEqual(obj.status, 3) class TestMatching(unittest.TestCase): class Object(GObject.Object): status = 0 prop = GObject.Property(type=int, default=0) @GObject.Signal() def my_signal(self): pass @unittest.expectedFailure # https://bugzilla.gnome.org/show_bug.cgi?id=692918 def test_signal_handler_block_matching(self): def dummy(*args): "Hack to work around: " def foo(obj): obj.status += 1 obj = self.Object() handler_id = GObject.signal_connect_closure(obj, 'my-signal', foo, after=False) handler_id self.assertEqual(obj.status, 0) obj.emit('my-signal') self.assertEqual(obj.status, 1) # Blocking by match criteria disables the foo callback signal_id, detail = GObject.signal_parse_name('my-signal', obj, True) count = GObject.signal_handlers_block_matched(obj, GObject.SignalMatchType.ID | GObject.SignalMatchType.CLOSURE, signal_id=signal_id, detail=detail, closure=foo, func=dummy, data=dummy) self.assertEqual(count, 1) obj.emit('my-signal') self.assertEqual(obj.status, 1) # Unblocking by the same match criteria allows callback to work again count = GObject.signal_handlers_unblock_matched(obj, GObject.SignalMatchType.ID | GObject.SignalMatchType.CLOSURE, signal_id=signal_id, detail=detail, closure=foo, func=dummy, data=dummy) self.assertEqual(count, 1) obj.emit('my-signal') self.assertEqual(obj.status, 2) # Disconnecting by match criteria completely removes the handler count = GObject.signal_handlers_disconnect_matched(obj, GObject.SignalMatchType.ID | GObject.SignalMatchType.CLOSURE, signal_id=signal_id, detail=detail, closure=foo, func=dummy, data=dummy) self.assertEqual(count, 1) obj.emit('my-signal') self.assertEqual(obj.status, 2) def test_signal_handler_find(self): def foo(obj): obj.status += 1 obj = self.Object() handler_id = GObject.signal_connect_closure(obj, 'my-signal', foo, after=False) signal_id, detail = GObject.signal_parse_name('my-signal', obj, True) found_id = GObject.signal_handler_find(obj, GObject.SignalMatchType.ID, signal_id=signal_id, detail=detail, closure=None, func=0, data=0) self.assertEqual(handler_id, found_id) class TestClosures(unittest.TestCase): def setUp(self): self.count = 0 self.emission_stopped = False self.emission_error = False self.handler_pending = False def _callback_handler_pending(self, e): signal_id, detail = GObject.signal_parse_name('signal', e, True) self.handler_pending = GObject.signal_has_handler_pending(e, signal_id, detail, may_be_blocked=False) def _callback(self, e): self.count += 1 def _callback_stop_emission(self, obj, prop, stop_it): if stop_it: obj.stop_emission_by_name('notify::prop') self.emission_stopped = True else: self.count += 1 def _callback_invalid_stop_emission_name(self, obj, prop): with capture_glib_warnings(allow_warnings=True, allow_criticals=True) as warn: obj.stop_emission_by_name('notasignal::baddetail') self.emission_error = True self.assertTrue(warn) def test_disconnect_by_func(self): e = E() e.connect('signal', self._callback) e.disconnect_by_func(self._callback) e.emit('signal') self.assertEqual(self.count, 0) def test_disconnect(self): e = E() handler_id = e.connect('signal', self._callback) self.assertTrue(e.handler_is_connected(handler_id)) e.disconnect(handler_id) e.emit('signal') self.assertEqual(self.count, 0) self.assertFalse(e.handler_is_connected(handler_id)) def test_stop_emission_by_name(self): e = E() # Sandwich a callback that stops emission in between a callback that increments e.connect('notify::prop', self._callback_stop_emission, False) e.connect('notify::prop', self._callback_stop_emission, True) e.connect('notify::prop', self._callback_stop_emission, False) e.set_property('prop', 1234) self.assertEqual(e.get_property('prop'), 1234) self.assertEqual(self.count, 1) self.assertTrue(self.emission_stopped) def test_stop_emission_by_name_error(self): e = E() e.connect('notify::prop', self._callback_invalid_stop_emission_name) with capture_glib_warnings(): e.set_property('prop', 1234) self.assertTrue(self.emission_error) def test_handler_block(self): e = E() e.connect('signal', self._callback) e.handler_block_by_func(self._callback) e.emit('signal') self.assertEqual(self.count, 0) def test_handler_unblock(self): e = E() handler_id = e.connect('signal', self._callback) e.handler_block(handler_id) e.handler_unblock_by_func(self._callback) e.emit('signal') self.assertEqual(self.count, 1) def test_handler_block_method(self): # Filed as #375589 class A: def __init__(self): self.a = 0 def callback(self, o): self.a = 1 o.handler_block_by_func(self.callback) inst = A() e = E() e.connect("signal", inst.callback) e.emit('signal') self.assertEqual(inst.a, 1) gc.collect() def test_gstring(self): class C(GObject.GObject): __gsignals__ = {'my_signal': (GObject.SignalFlags.RUN_LAST, GObject.TYPE_GSTRING, (GObject.TYPE_GSTRING,))} def __init__(self, test): GObject.GObject.__init__(self) self.test = test def do_my_signal(self, data): self.data = data self.test.assertEqual(len(data), 3) return ''.join([data[2], data[1], data[0]]) c = C(self) data = c.emit("my_signal", "\01\00\02") self.assertEqual(data, "\02\00\01") def test_handler_pending(self): obj = F() obj.connect('signal', self._callback_handler_pending) obj.connect('signal', self._callback) self.assertEqual(self.count, 0) self.assertEqual(self.handler_pending, False) obj.emit('signal') self.assertEqual(self.count, 1) self.assertEqual(self.handler_pending, True) def test_signal_handlers_destroy(self): obj = F() obj.connect('signal', self._callback) obj.connect('signal', self._callback) obj.connect('signal', self._callback) obj.emit('signal') self.assertEqual(self.count, 3) # count should remain at 3 after all handlers are destroyed GObject.signal_handlers_destroy(obj) obj.emit('signal') self.assertEqual(self.count, 3) class SigPropClass(GObject.GObject): __gsignals__ = {'my_signal': (GObject.SignalFlags.RUN_FIRST, None, (GObject.TYPE_INT,))} __gproperties__ = { 'foo': (str, None, None, '', GObject.ParamFlags.WRITABLE | GObject.ParamFlags.CONSTRUCT), } signal_emission_failed = False def do_my_signal(self, arg): self.arg = arg def do_set_property(self, pspec, value): if pspec.name == 'foo': self._foo = value else: raise AttributeError('unknown property %s' % pspec.name) try: self.emit("my-signal", 1) except TypeError: self.signal_emission_failed = True class TestSigProp(unittest.TestCase): def test_emit_in_property_setter(self): obj = SigPropClass() self.assertFalse(obj.signal_emission_failed) class CM(GObject.GObject): __gsignals__ = dict( test1=(GObject.SignalFlags.RUN_FIRST, None, ()), test2=(GObject.SignalFlags.RUN_LAST, None, (str,)), test3=(GObject.SignalFlags.RUN_LAST, int, (GObject.TYPE_DOUBLE,)), test4=(GObject.SignalFlags.RUN_FIRST, None, (bool, int, GObject.TYPE_FLOAT, GObject.TYPE_DOUBLE, int, GObject.TYPE_UINT, GObject.TYPE_ULONG)), test_float=(GObject.SignalFlags.RUN_LAST, GObject.TYPE_FLOAT, (GObject.TYPE_FLOAT,)), test_double=(GObject.SignalFlags.RUN_LAST, GObject.TYPE_DOUBLE, (GObject.TYPE_DOUBLE,)), test_int64=(GObject.SignalFlags.RUN_LAST, GObject.TYPE_INT64, (GObject.TYPE_INT64,)), test_string=(GObject.SignalFlags.RUN_LAST, str, (str,)), test_object=(GObject.SignalFlags.RUN_LAST, object, (object,)), test_paramspec=(GObject.SignalFlags.RUN_LAST, GObject.ParamSpec, ()), test_paramspec_in=(GObject.SignalFlags.RUN_LAST, GObject.ParamSpec, (GObject.ParamSpec, )), test_gvalue=(GObject.SignalFlags.RUN_LAST, GObject.Value, (GObject.Value,)), test_gvalue_ret=(GObject.SignalFlags.RUN_LAST, GObject.Value, (GObject.TYPE_GTYPE,)), ) testprop = GObject.Property(type=int) class _TestCMarshaller: def setUp(self): self.obj = CM() testhelper.connectcallbacks(self.obj) def test_test1(self): self.obj.emit("test1") def test_test2(self): self.obj.emit("test2", "string") def test_test3(self): rv = self.obj.emit("test3", 42.0) self.assertEqual(rv, 20) def test_test4(self): self.obj.emit("test4", True, 10, 3.14, 1.78, 20, 30, 31) def test_float(self): rv = self.obj.emit("test-float", 1.234) self.assertTrue(rv >= 1.233999 and rv <= 1.2400001, rv) def test_double(self): rv = self.obj.emit("test-double", 1.234) self.assertEqual(rv, 1.234) def test_int64(self): rv = self.obj.emit("test-int64", 102030405) self.assertEqual(rv, 102030405) rv = self.obj.emit("test-int64", GLib.MAXINT64) self.assertEqual(rv, GLib.MAXINT64 - 1) rv = self.obj.emit("test-int64", GLib.MININT64) self.assertEqual(rv, GLib.MININT64) def test_string(self): rv = self.obj.emit("test-string", "str") self.assertEqual(rv, "str") def test_object(self): rv = self.obj.emit("test-object", self) self.assertEqual(rv, self) def test_paramspec(self): rv = self.obj.emit("test-paramspec") self.assertEqual(rv.name, "test-param") self.assertEqual(rv.nick, "test") @unittest.skipUnless(hasattr(GObject, 'param_spec_boolean'), 'too old gobject-introspection') def test_paramspec_in(self): rv = GObject.param_spec_boolean('mybool', 'test-bool', 'do something', True, GObject.ParamFlags.READABLE) rv2 = self.obj.emit("test-paramspec-in", rv) self.assertEqual(type(rv), type(rv2)) self.assertEqual(rv2.name, "mybool") self.assertEqual(rv2.nick, "test-bool") def test_C_paramspec(self): self.notify_called = False def cb_notify(obj, prop): self.notify_called = True self.assertEqual(obj, self.obj) self.assertEqual(prop.name, "testprop") self.obj.connect("notify", cb_notify) self.obj.set_property("testprop", 42) self.assertTrue(self.notify_called) def test_gvalue(self): # implicit int rv = self.obj.emit("test-gvalue", 42) self.assertEqual(rv, 42) # explicit float v = GObject.Value(GObject.TYPE_FLOAT, 1.234) rv = self.obj.emit("test-gvalue", v) self.assertAlmostEqual(rv, 1.234, places=4) # implicit float rv = self.obj.emit("test-gvalue", 1.234) self.assertAlmostEqual(rv, 1.234, places=4) # explicit int64 v = GObject.Value(GObject.TYPE_INT64, GLib.MAXINT64) rv = self.obj.emit("test-gvalue", v) self.assertEqual(rv, GLib.MAXINT64) # explicit uint64 v = GObject.Value(GObject.TYPE_UINT64, GLib.MAXUINT64) rv = self.obj.emit("test-gvalue", v) self.assertEqual(rv, GLib.MAXUINT64) @unittest.expectedFailure # https://bugzilla.gnome.org/show_bug.cgi?id=705291 def test_gvalue_implicit_int64(self): # implicit int64 rv = self.obj.emit("test-gvalue", GLib.MAXINT64) self.assertEqual(rv, GLib.MAXINT64) # implicit uint64 rv = self.obj.emit("test-gvalue", GLib.MAXUINT64) self.assertEqual(rv, GLib.MAXUINT64) def test_gvalue_ret(self): self.assertEqual(self.obj.emit("test-gvalue-ret", GObject.TYPE_INT), GLib.MAXINT) self.assertEqual(self.obj.emit("test-gvalue-ret", GObject.TYPE_UINT), GLib.MAXUINT) self.assertEqual(self.obj.emit("test-gvalue-ret", GObject.TYPE_INT64), GLib.MAXINT64) self.assertEqual(self.obj.emit("test-gvalue-ret", GObject.TYPE_UINT64), GLib.MAXUINT64) self.assertEqual(self.obj.emit("test-gvalue-ret", GObject.TYPE_STRING), "hello") class TestCMarshaller(_TestCMarshaller, unittest.TestCase): pass # Test for 374653 class TestPyGValue(unittest.TestCase): def test_none_null_boxed_conversion(self): class C(GObject.GObject): __gsignals__ = dict(my_boxed_signal=( GObject.SignalFlags.RUN_LAST, GObject.TYPE_STRV, ())) obj = C() obj.connect('my-boxed-signal', lambda obj: None) sys.last_type = None obj.emit('my-boxed-signal') assert not sys.last_type class TestSignalDecorator(unittest.TestCase): class Decorated(GObject.GObject): value = 0 @GObject.Signal def pushed(self): """this will push""" self.value += 1 @GObject.Signal(flags=GObject.SignalFlags.RUN_LAST) def pulled(self): self.value -= 1 @GObject.Signal(flags=GObject.SignalFlags.DETAILED) def detailed(self): self.value -= 1 stomped = GObject.Signal('stomped', arg_types=(int,), doc='this will stomp') unnamed = GObject.Signal() class DecoratedOverride(GObject.GObject): overridden_closure_called = False notify_called = False value = GObject.Property(type=int, default=0) @GObject.SignalOverride def notify(self, *args, **kargs): self.overridden_closure_called = True def on_notify(self, obj, prop): self.notify_called = True def setUp(self): self.unnamedCalled = False def onUnnamed(self, obj): self.unnamedCalled = True def test_disconnect(self): decorated = self.Decorated() id_ = decorated.pushed.connect(lambda *args: None) decorated.pushed.disconnect(id_) def test_signal_repr(self): decorated = self.Decorated() assert repr(decorated.pushed) == 'BoundSignal("pushed")' def test_signal_call(self): decorated = self.Decorated() assert decorated.value == 0 decorated.pushed() assert decorated.value == 1 def test_connect_detailed(self): decorated = self.Decorated() id_ = decorated.detailed.connect_detailed(lambda *args: None, "foo") decorated.pushed.disconnect(id_) def test_get_signal_args(self): self.assertEqual(self.Decorated.pushed.get_signal_args(), (GObject.SignalFlags.RUN_FIRST, None, tuple(), None, None)) self.assertEqual(self.Decorated.pulled.get_signal_args(), (GObject.SignalFlags.RUN_LAST, None, tuple(), None, None)) self.assertEqual(self.Decorated.stomped.get_signal_args(), (GObject.SignalFlags.RUN_FIRST, None, (int,), None, None)) def test_closures_called(self): decorated = self.Decorated() self.assertEqual(decorated.value, 0) decorated.pushed.emit() self.assertEqual(decorated.value, 1) decorated.pulled.emit() self.assertEqual(decorated.value, 0) def test_signal_copy(self): blah = self.Decorated.stomped.copy('blah') self.assertEqual(str(blah), blah) self.assertEqual(blah.func, self.Decorated.stomped.func) self.assertEqual(blah.flags, self.Decorated.stomped.flags) self.assertEqual(blah.return_type, self.Decorated.stomped.return_type) self.assertEqual(blah.arg_types, self.Decorated.stomped.arg_types) self.assertEqual(blah.__doc__, self.Decorated.stomped.__doc__) def test_doc_string(self): # Test the two techniques for setting doc strings on the signals # class variables, through the "doc" keyword or as the getter doc string. self.assertEqual(self.Decorated.stomped.__doc__, 'this will stomp') self.assertEqual(self.Decorated.pushed.__doc__, 'this will push') def test_unnamed_signal_gets_named(self): self.assertEqual(str(self.Decorated.unnamed), 'unnamed') def test_unnamed_signal_gets_called(self): obj = self.Decorated() obj.connect('unnamed', self.onUnnamed) self.assertEqual(self.unnamedCalled, False) obj.emit('unnamed') self.assertEqual(self.unnamedCalled, True) def test_overridden_signal(self): # Test that the pushed signal is called in with super and the override # which should both increment the "value" to 3 obj = self.DecoratedOverride() obj.connect("notify", obj.on_notify) self.assertEqual(obj.value, 0) obj.value = 1 self.assertEqual(obj.value, 1) self.assertTrue(obj.overridden_closure_called) self.assertTrue(obj.notify_called) class TestSignalConnectors(unittest.TestCase): class CustomButton(GObject.GObject): on_notify_called = False value = GObject.Property(type=int) @GObject.Signal(arg_types=(int,)) def clicked(self, value): self.value = value def setUp(self): self.obj = None self.value = None def on_clicked(self, obj, value): self.obj = obj self.value = value def test_signal_notify(self): def on_notify(obj, param): obj.on_notify_called = True obj = self.CustomButton() obj.connect('notify', on_notify) self.assertFalse(obj.on_notify_called) obj.notify('value') self.assertTrue(obj.on_notify_called) def test_signal_emit(self): # standard callback connection with different forms of emit. obj = self.CustomButton() obj.connect('clicked', self.on_clicked) # vanilla obj.emit('clicked', 1) self.assertEqual(obj.value, 1) self.assertEqual(obj, self.obj) self.assertEqual(self.value, 1) # using class signal as param self.obj = None self.value = None obj.emit(self.CustomButton.clicked, 1) self.assertEqual(obj, self.obj) self.assertEqual(self.value, 1) # using bound signal as param self.obj = None self.value = None obj.emit(obj.clicked, 1) self.assertEqual(obj, self.obj) self.assertEqual(self.value, 1) # using bound signal with emit self.obj = None self.value = None obj.clicked.emit(1) self.assertEqual(obj, self.obj) self.assertEqual(self.value, 1) def test_signal_class_connect(self): obj = self.CustomButton() obj.connect(self.CustomButton.clicked, self.on_clicked) obj.emit('clicked', 2) self.assertEqual(obj, self.obj) self.assertEqual(self.value, 2) def test_signal_bound_connect(self): obj = self.CustomButton() obj.clicked.connect(self.on_clicked) obj.emit('clicked', 3) self.assertEqual(obj, self.obj) self.assertEqual(self.value, 3) class _ConnectDataTestBase(object): # Notes: # - self.Object is overridden in sub-classes. # - Numeric suffixes indicate the number of user data args passed in. Object = None def run_connect_test(self, emit_args, user_data, flags=0): obj = self.Object() callback_args = [] def callback(*args): callback_args.append(args) return 0 obj.connect_data('sig-with-int64-prop', callback, connect_flags=flags, *user_data) obj.emit('sig-with-int64-prop', *emit_args) self.assertEqual(len(callback_args), 1) return callback_args[0] def test_0(self): obj, value = self.run_connect_test([GLib.MAXINT64], user_data=[]) self.assertIsInstance(obj, self.Object) self.assertEqual(value, GLib.MAXINT64) def test_1(self): obj, value, data = self.run_connect_test([GLib.MAXINT64], user_data=['mydata']) self.assertIsInstance(obj, self.Object) self.assertEqual(value, GLib.MAXINT64) self.assertEqual(data, 'mydata') def test_after_0(self): obj, value = self.run_connect_test([GLib.MAXINT64], user_data=[], flags=GObject.ConnectFlags.AFTER) self.assertIsInstance(obj, self.Object) self.assertEqual(value, GLib.MAXINT64) def test_after_1(self): obj, value, data = self.run_connect_test([GLib.MAXINT64], user_data=['mydata'], flags=GObject.ConnectFlags.AFTER) self.assertIsInstance(obj, self.Object) self.assertEqual(value, GLib.MAXINT64) self.assertEqual(data, 'mydata') def test_swaped_0(self): # Swapped only works with a single user data argument. with self.assertRaises(ValueError): self.run_connect_test([GLib.MAXINT64], user_data=[], flags=GObject.ConnectFlags.SWAPPED) def test_swaped_1(self): # Notice obj and data are reversed in the return. data, value, obj = self.run_connect_test([GLib.MAXINT64], user_data=['mydata'], flags=GObject.ConnectFlags.SWAPPED) self.assertIsInstance(obj, self.Object) self.assertEqual(value, GLib.MAXINT64) self.assertEqual(data, 'mydata') def test_swaped_2(self): # Swapped only works with a single user data argument. with self.assertRaises(ValueError): self.run_connect_test([GLib.MAXINT64], user_data=[1, 2], flags=GObject.ConnectFlags.SWAPPED) def test_after_and_swapped_0(self): # Swapped only works with a single user data argument. with self.assertRaises(ValueError): self.run_connect_test([GLib.MAXINT64], user_data=[], flags=GObject.ConnectFlags.AFTER | GObject.ConnectFlags.SWAPPED) def test_after_and_swapped_1(self): # Notice obj and data are reversed in the return. data, value, obj = self.run_connect_test([GLib.MAXINT64], user_data=['mydata'], flags=GObject.ConnectFlags.AFTER | GObject.ConnectFlags.SWAPPED) self.assertIsInstance(obj, self.Object) self.assertEqual(value, GLib.MAXINT64) self.assertEqual(data, 'mydata') def test_after_and_swapped_2(self): # Swapped only works with a single user data argument. with self.assertRaises(ValueError): self.run_connect_test([GLib.MAXINT64], user_data=[], flags=GObject.ConnectFlags.AFTER | GObject.ConnectFlags.SWAPPED) class TestConnectDataNonIntrospected(unittest.TestCase, _ConnectDataTestBase): # This tests connect_data with non-introspected signals # (created in Python in this case). class Object(GObject.Object): test = GObject.Signal() sig_with_int64_prop = GObject.Signal(return_type=GObject.TYPE_INT64, arg_types=[GObject.TYPE_INT64], flags=GObject.SignalFlags.RUN_LAST) class TestConnectDataIntrospected(unittest.TestCase, _ConnectDataTestBase): # This tests connect_data with introspected signals brought in from Regress. Object = Regress.TestObj class TestInstallSignals(unittest.TestCase): # These tests only test how signalhelper.install_signals works # with the __gsignals__ dict and therefore does not need to use # GObject as a base class because that would automatically call # install_signals within the meta-class. class Base(object): __gsignals__ = {'test': (0, None, tuple())} class Sub1(Base): pass class Sub2(Base): @GObject.Signal def sub2test(self): pass def setUp(self): self.assertEqual(len(self.Base.__gsignals__), 1) signalhelper.install_signals(self.Base) self.assertEqual(len(self.Base.__gsignals__), 1) def test_subclass_gets_empty_gsignals_dict(self): # Installing signals will add the __gsignals__ dict to a class # if it doesn't already exists. self.assertFalse('__gsignals__' in self.Sub1.__dict__) signalhelper.install_signals(self.Sub1) self.assertTrue('__gsignals__' in self.Sub1.__dict__) # Sub1 should only contain an empty signals dict, this tests: # https://bugzilla.gnome.org/show_bug.cgi?id=686496 self.assertEqual(self.Sub1.__dict__['__gsignals__'], {}) def test_subclass_with_decorator_gets_gsignals_dict(self): self.assertFalse('__gsignals__' in self.Sub2.__dict__) signalhelper.install_signals(self.Sub2) self.assertTrue('__gsignals__' in self.Sub2.__dict__) self.assertEqual(len(self.Base.__gsignals__), 1) self.assertEqual(len(self.Sub2.__gsignals__), 1) self.assertTrue('sub2test' in self.Sub2.__gsignals__) # Make sure the vfunc was added self.assertTrue(hasattr(self.Sub2, 'do_sub2test')) class TestPython3Signals(unittest.TestCase): class AnnotatedClass(GObject.GObject): @GObject.Signal def sig1(self, a: int, b: float): pass @GObject.Signal(flags=GObject.SignalFlags.RUN_LAST) def sig2_with_return(self, a: int, b: float) -> str: return "test" def test_annotations(self): self.assertEqual(signalhelper.get_signal_annotations(self.AnnotatedClass.sig1.func), (None, (int, float))) self.assertEqual(signalhelper.get_signal_annotations(self.AnnotatedClass.sig2_with_return.func), (str, (int, float))) self.assertEqual(self.AnnotatedClass.sig2_with_return.get_signal_args(), (GObject.SignalFlags.RUN_LAST, str, (int, float), None, None)) self.assertEqual(self.AnnotatedClass.sig2_with_return.arg_types, (int, float)) self.assertEqual(self.AnnotatedClass.sig2_with_return.return_type, str) def test_emit_return(self): obj = self.AnnotatedClass() self.assertEqual(obj.sig2_with_return.emit(1, 2.0), 'test') class TestSignalModuleLevelFunctions(unittest.TestCase): def test_signal_list_ids_with_invalid_type(self): with self.assertRaisesRegex(TypeError, 'type must be instantiable or an interface.*'): GObject.signal_list_ids(GObject.TYPE_INVALID) def test_signal_list_ids(self): with self.assertRaisesRegex(TypeError, 'type must be instantiable or an interface.*'): GObject.signal_list_ids(GObject.TYPE_INT) ids = GObject.signal_list_ids(C) self.assertEqual(len(ids), 1) # Note canonicalized names self.assertEqual(GObject.signal_name(ids[0]), 'my-signal') # There is no signal 0 in gobject self.assertEqual(GObject.signal_name(0), None) def test_signal_lookup_with_invalid_type(self): with self.assertRaisesRegex(TypeError, 'type must be instantiable or an interface.*'): GObject.signal_lookup('NOT_A_SIGNAL_NAME', GObject.TYPE_INVALID) def test_signal_lookup(self): ids = GObject.signal_list_ids(C) self.assertEqual(ids[0], GObject.signal_lookup('my_signal', C)) self.assertEqual(ids[0], GObject.signal_lookup('my-signal', C)) with self.assertRaisesRegex(TypeError, 'type must be instantiable or an interface.*'): GObject.signal_lookup('NOT_A_SIGNAL_NAME', GObject.TYPE_INT) # Invalid signal names return 0 instead of raising self.assertEqual(GObject.signal_lookup('NOT_A_SIGNAL_NAME', C), 0) def test_signal_query(self): my_signal_id, = GObject.signal_list_ids(C) # Form is: (id, name, gtype, arg_count, return_type, (arg_type1, ...)) my_signal_expected_query_result = [my_signal_id, 'my-signal', C.__gtype__, 1, GObject.TYPE_NONE, (GObject.TYPE_INT,)] # signal_query(name, type) self.assertEqual(list(GObject.signal_query('my-signal', C)), my_signal_expected_query_result) # signal_query(signal_id) self.assertEqual(list(GObject.signal_query(my_signal_id)), my_signal_expected_query_result) # invalid query returns None instead of raising self.assertEqual(GObject.signal_query(0), None) self.assertEqual(GObject.signal_query('NOT_A_SIGNAL', C), None) class TestIntrospectedSignals(unittest.TestCase): def test_object_param_signal(self): obj = Regress.TestObj() def callback(obj, obj_param): self.assertEqual(obj_param.props.int, 3) self.assertGreater(obj_param.__grefcount__, 1) obj.called = True obj.called = False obj.connect('sig-with-obj', callback) obj.emit_sig_with_obj() self.assertTrue(obj.called) def test_connect_after(self): obj = Regress.TestObj() def callback(obj, obj_param): obj.called = True obj.called = False obj.connect_after('sig-with-obj', callback) obj.emit_sig_with_obj() self.assertTrue(obj.called) def test_int64_param_from_py(self): obj = Regress.TestObj() def callback(obj, i): obj.callback_i = i return i obj.callback_i = None obj.connect('sig-with-int64-prop', callback) rv = obj.emit('sig-with-int64-prop', GLib.MAXINT64) self.assertEqual(rv, GLib.MAXINT64) self.assertEqual(obj.callback_i, GLib.MAXINT64) def test_uint64_param_from_py(self): obj = Regress.TestObj() def callback(obj, i): obj.callback_i = i return i obj.callback_i = None obj.connect('sig-with-uint64-prop', callback) rv = obj.emit('sig-with-uint64-prop', GLib.MAXUINT64) self.assertEqual(rv, GLib.MAXUINT64) self.assertEqual(obj.callback_i, GLib.MAXUINT64) def test_int64_param_from_c(self): obj = Regress.TestObj() def callback(obj, i): obj.callback_i = i return i obj.callback_i = None obj.connect('sig-with-int64-prop', callback) obj.emit_sig_with_int64() self.assertEqual(obj.callback_i, GLib.MAXINT64) def test_uint64_param_from_c(self): obj = Regress.TestObj() def callback(obj, i): obj.callback_i = i return i obj.callback_i = None obj.connect('sig-with-uint64-prop', callback) obj.emit_sig_with_uint64() self.assertEqual(obj.callback_i, GLib.MAXUINT64) def test_intarray_ret(self): obj = Regress.TestObj() def callback(obj, i): obj.callback_i = i return [i, i + 1] obj.callback_i = None try: obj.connect('sig-with-intarray-ret', callback) except TypeError as e: # compat with g-i 1.34.x if 'unknown signal' in str(e): return raise rv = obj.emit('sig-with-intarray-ret', 42) self.assertEqual(obj.callback_i, 42) self.assertEqual(type(rv), GLib.Array) self.assertEqual(rv.len, 2) @unittest.skip('https://bugzilla.gnome.org/show_bug.cgi?id=669496') def test_array_parm(self): obj = Regress.TestObj() def callback(obj, arr): obj.callback_arr = arr obj.connect('sig-with-array-prop', callback) obj.callback_arr = None self.assertEqual(obj.emit('sig-with-array-prop', [1, 2, GLib.MAXUINT]), None) self.assertEqual(obj.callback_arr, [1, 2, GLib.MAXUINT]) def test_held_struct_ref(self): held_structs = [] def callback(obj, struct): # The struct held by Python will become a copy after this callback exits. struct.some_int = 42 struct.some_int8 = 42 held_structs.append(struct) struct = Regress.TestSimpleBoxedA() obj = Regress.TestObj() self.assertEqual(struct.some_int, 0) self.assertEqual(struct.some_int8, 0) obj.connect('test-with-static-scope-arg', callback) obj.emit('test-with-static-scope-arg', struct) # The held struct will be a copy of the modified struct. self.assertEqual(len(held_structs), 1) held_struct = held_structs[0] self.assertEqual(held_struct.some_int, 42) self.assertEqual(held_struct.some_int8, 42) # Boxed equality checks pointers by default. self.assertNotEqual(struct, held_struct) def test_action(self): obj = Regress.TestAction() other_obj = obj.emit('action') self.assertEqual(other_obj.__grefcount__, 1) other_obj2 = obj.emit('action2') self.assertIsNone(other_obj2) class TestIntrospectedSignalsIssue158(unittest.TestCase): """ The test for https://gitlab.gnome.org/GNOME/pygobject/issues/158 """ _obj_sig_names = [sig.get_name() for sig in repo.find_by_name('Regress', 'TestObj').get_signals()] def __init__(self, *args): unittest.TestCase.__init__(self, *args) self._gc_thread_stop = False def _gc_thread(self): while not self._gc_thread_stop: gc.collect() time.sleep(0.010) def _callback(self, *args): pass def test_run(self): """ Manually trigger GC from a different thread periodicaly while the main thread keeps connecting/disconnecting to/from signals. It takes a lot of time to reproduce the issue. It is possible to make it fail reliably by changing the code of pygobject_unwatch_closure slightly from: PyGObjectData *inst_data = data; inst_data->closures = g_slist_remove (inst_data->closures, closure); to PyGObjectData *inst_data = data; GSList *tmp = g_slist_remove (inst_data->closures, closure); g_usleep(G_USEC_PER_SEC/10); inst_data->closures = tmp; """ obj = Regress.TestObj() gc_thread = threading.Thread(target=self._gc_thread) gc_thread.start() for _ in range(8): handlers = [obj.connect(sig, self._callback) for sig in self._obj_sig_names] time.sleep(0.010) while len(handlers) > 0: obj.disconnect(handlers.pop()) self._gc_thread_stop = True gc_thread.join() class _ConnectObjectTestBase(object): # Notes: # - self.Object is overridden in sub-classes. # - Numeric suffixes indicate the number of user data args passed in. Object = None SwapObject = None def run_connect_test(self, emit_args, user_data, flags=0): obj = self.Object() callback_args = [] swap_obj = self.SwapObject() def callback(*args): callback_args.append(args) return 0 if flags & GObject.ConnectFlags.AFTER: connect_func = obj.connect_object_after else: connect_func = obj.connect_object with capture_gi_deprecation_warnings(): connect_func('sig-with-int64-prop', callback, swap_obj, *user_data) obj.emit('sig-with-int64-prop', *emit_args) self.assertEqual(len(callback_args), 1) return callback_args[0] def test_0(self): obj, value = self.run_connect_test([GLib.MAXINT64], user_data=[]) self.assertIsInstance(obj, self.SwapObject) self.assertEqual(value, GLib.MAXINT64) def test_1(self): obj, value, data = self.run_connect_test([GLib.MAXINT64], user_data=['mydata']) self.assertIsInstance(obj, self.SwapObject) self.assertEqual(value, GLib.MAXINT64) self.assertEqual(data, 'mydata') def test_2(self): obj, value, data1, data2 = self.run_connect_test([GLib.MAXINT64], user_data=['mydata1', 'mydata2']) self.assertIsInstance(obj, self.SwapObject) self.assertEqual(value, GLib.MAXINT64) self.assertEqual(data1, 'mydata1') self.assertEqual(data2, 'mydata2') def test_after_0(self): obj, value = self.run_connect_test([GLib.MAXINT64], user_data=[], flags=GObject.ConnectFlags.AFTER) self.assertIsInstance(obj, self.SwapObject) self.assertEqual(value, GLib.MAXINT64) def test_after_1(self): obj, value, data = self.run_connect_test([GLib.MAXINT64], user_data=['mydata'], flags=GObject.ConnectFlags.AFTER) self.assertIsInstance(obj, self.SwapObject) self.assertEqual(value, GLib.MAXINT64) self.assertEqual(data, 'mydata') def test_after_2(self): obj, value, data1, data2 = self.run_connect_test([GLib.MAXINT64], user_data=['mydata1', 'mydata2'], flags=GObject.ConnectFlags.AFTER) self.assertIsInstance(obj, self.SwapObject) self.assertEqual(value, GLib.MAXINT64) self.assertEqual(data1, 'mydata1') self.assertEqual(data2, 'mydata2') class TestConnectGObjectNonIntrospected(unittest.TestCase, _ConnectObjectTestBase): # This tests connect_object with non-introspected signals # (created in Python in this case). class Object(GObject.Object): test = GObject.Signal() sig_with_int64_prop = GObject.Signal(return_type=GObject.TYPE_INT64, arg_types=[GObject.TYPE_INT64], flags=GObject.SignalFlags.RUN_LAST) # Object passed for swapping is GObject based. class SwapObject(GObject.Object): pass class TestConnectGObjectIntrospected(unittest.TestCase, _ConnectObjectTestBase): # This tests connect_object with introspected signals brought in from Regress. Object = Regress.TestObj # Object passed for swapping is GObject based. class SwapObject(GObject.Object): pass class TestConnectPyObjectNonIntrospected(unittest.TestCase, _ConnectObjectTestBase): # This tests connect_object with non-introspected signals # (created in Python in this case). class Object(GObject.Object): test = GObject.Signal() sig_with_int64_prop = GObject.Signal(return_type=GObject.TYPE_INT64, arg_types=[GObject.TYPE_INT64], flags=GObject.SignalFlags.RUN_LAST) # Object passed for swapping is pure Python SwapObject = object class TestConnectPyObjectIntrospected(unittest.TestCase, _ConnectObjectTestBase): # This tests connect_object with introspected signals brought in from Regress. Object = Regress.TestObj # Object passed for swapping is pure Python SwapObject = object class _RefCountTestBase(object): # NOTE: ref counts are always one more than expected because the getrefcount() # function adds a ref for the input argument. # Sub-classes set this Object = None class PyData(object): pass @unittest.skipUnless(hasattr(sys, "getrefcount"), "no sys.getrefcount") def test_callback_ref_count_del(self): def callback(obj, value): return value // 2 callback_ref = weakref.ref(callback) self.assertEqual(sys.getrefcount(callback), 2) obj = self.Object() obj.connect('sig-with-int64-prop', callback) self.assertEqual(sys.getrefcount(callback), 3) del callback self.assertEqual(sys.getrefcount(callback_ref()), 2) res = obj.emit('sig-with-int64-prop', 42) self.assertEqual(res, 21) self.assertEqual(sys.getrefcount(callback_ref), 2) del obj self.assertIsNone(callback_ref()) @unittest.skipUnless(hasattr(sys, "getrefcount"), "no sys.getrefcount") def test_callback_ref_count_disconnect(self): def callback(obj, value): return value // 2 callback_ref = weakref.ref(callback) self.assertEqual(sys.getrefcount(callback), 2) obj = self.Object() handler_id = obj.connect('sig-with-int64-prop', callback) self.assertEqual(sys.getrefcount(callback), 3) del callback self.assertEqual(sys.getrefcount(callback_ref()), 2) res = obj.emit('sig-with-int64-prop', 42) self.assertEqual(res, 21) self.assertEqual(sys.getrefcount(callback_ref), 2) obj.disconnect(handler_id) self.assertIsNone(callback_ref()) @unittest.skipUnless(hasattr(sys, "getrefcount"), "no sys.getrefcount") def test_callback_ref_count_disconnect_by_func(self): def callback(obj, value): return value // 2 callback_ref = weakref.ref(callback) self.assertEqual(sys.getrefcount(callback), 2) obj = self.Object() obj.connect('sig-with-int64-prop', callback) self.assertEqual(sys.getrefcount(callback), 3) del callback self.assertEqual(sys.getrefcount(callback_ref()), 2) res = obj.emit('sig-with-int64-prop', 42) self.assertEqual(res, 21) self.assertEqual(sys.getrefcount(callback_ref), 2) obj.disconnect_by_func(callback_ref()) self.assertIsNone(callback_ref()) @unittest.skipUnless(hasattr(sys, "getrefcount"), "no sys.getrefcount") def test_user_data_ref_count(self): def callback(obj, value, data): return value // 2 data = self.PyData() data_ref = weakref.ref(data) self.assertEqual(sys.getrefcount(data), 2) obj = self.Object() obj.connect('sig-with-int64-prop', callback, data) self.assertEqual(sys.getrefcount(data), 3) del data self.assertEqual(sys.getrefcount(data_ref()), 2) res = obj.emit('sig-with-int64-prop', 42) self.assertEqual(res, 21) self.assertEqual(sys.getrefcount(data_ref()), 2) del obj self.assertIsNone(data_ref()) @unittest.skipUnless(hasattr(sys, "getrefcount"), "no sys.getrefcount") @unittest.expectedFailure # https://bugzilla.gnome.org/show_bug.cgi?id=688064 def test_object_ref_count(self): # connect_object() should only weakly reference the object passed in # and auto-disconnect the signal when the object is destroyed. def callback(data, value): return value // 2 data = GObject.Object() data_ref = weakref.ref(data) self.assertEqual(sys.getrefcount(data), 2) obj = self.Object() handler_id = obj.connect_object('sig-with-int64-prop', callback, data) self.assertEqual(sys.getrefcount(data), 2) res = obj.emit('sig-with-int64-prop', 42) self.assertEqual(res, 21) self.assertEqual(sys.getrefcount(data), 2) del data self.assertIsNone(data_ref()) self.assertFalse(obj.handler_is_connected(handler_id)) class TestRefCountsNonIntrospected(unittest.TestCase, _RefCountTestBase): class Object(GObject.Object): sig_with_int64_prop = GObject.Signal(return_type=GObject.TYPE_INT64, arg_types=[GObject.TYPE_INT64], flags=GObject.SignalFlags.RUN_LAST) class TestRefCountsIntrospected(unittest.TestCase, _RefCountTestBase): Object = Regress.TestObj class TestClosureRefCycle(unittest.TestCase): def test_closure_ref_cycle_unreachable(self): # https://bugzilla.gnome.org/show_bug.cgi?id=731501 called = [] def on_add(store, *args): called.append(store) store = Gio.ListStore() store.connect_object('items-changed', on_add, store) # Remove all Python references to the object and keep it alive # on the C level. x = Gio.FileInfo() x.set_attribute_object('store', store) del store gc.collect() # get it back and trigger the signal x.get_attribute_object('store').append(Gio.FileInfo()) self.assertEqual(len(called), 1) self.assertTrue(called[0].__grefcount__ > 0) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/tests/test_source.py0000664000000000000000000003152015074674453016422 0ustar00rootroot# -*- Mode: Python -*- import sys import gc import unittest import warnings from gi.repository import GLib from gi import PyGIDeprecationWarning from .helper import capture_glib_warnings class Idle(GLib.Idle): def __init__(self, loop): GLib.Idle.__init__(self) self.count = 0 self.set_callback(self.callback, loop) def callback(self, loop): self.count += 1 return True class MySource(GLib.Source): def __init__(self): GLib.Source.__init__(self) def prepare(self): return True, 0 def check(self): return True def dispatch(self, callback, args): return callback(*args) class TestSource(unittest.TestCase): def timeout_callback(self, loop): loop.quit() def my_callback(self, loop): self.pos += 1 return True def setup_timeout(self, loop): timeout = GLib.Timeout(500) timeout.set_callback(self.timeout_callback, loop) timeout.attach() def test_sources(self): loop = GLib.MainLoop() self.setup_timeout(loop) idle = Idle(loop) self.assertEqual(idle.get_context(), None) idle.attach() self.assertEqual(idle.get_context(), GLib.main_context_default()) self.pos = 0 m = MySource() self.assertEqual(m.get_context(), None) m.set_callback(self.my_callback, loop) m.attach() self.assertEqual(m.get_context(), GLib.main_context_default()) loop.run() m.destroy() idle.destroy() self.assertGreater(self.pos, 0) self.assertGreaterEqual(idle.count, 0) self.assertTrue(m.is_destroyed()) self.assertTrue(idle.is_destroyed()) def test_source_prepare(self): # this test may not terminate if prepare() is wrapped incorrectly dispatched = [False] loop = GLib.MainLoop() class CustomTimeout(GLib.Source): def prepare(self): return (False, 10) def check(self): return True def dispatch(self, callback, args): dispatched[0] = True loop.quit() return False source = CustomTimeout() source.attach() source.set_callback(dir) loop.run() assert dispatched[0] def test_is_destroyed_simple(self): s = GLib.Source() self.assertFalse(s.is_destroyed()) s.destroy() self.assertTrue(s.is_destroyed()) c = GLib.MainContext() s = GLib.Source() s.attach(c) self.assertFalse(s.is_destroyed()) s.destroy() self.assertTrue(s.is_destroyed()) def test_is_destroyed_context(self): def f(): c = GLib.MainContext() s = GLib.Source() s.attach(c) return s s = f() gc.collect() gc.collect() self.assertTrue(s.is_destroyed()) def test_remove(self): s = GLib.idle_add(dir) self.assertEqual(GLib.source_remove(s), True) # Removing sources not found cause critical with capture_glib_warnings(allow_criticals=True): # s is now removed, should fail now self.assertEqual(GLib.source_remove(s), False) # accepts large source IDs (they are unsigned) self.assertEqual(GLib.source_remove(GLib.MAXINT32), False) self.assertEqual(GLib.source_remove(GLib.MAXINT32 + 1), False) self.assertEqual(GLib.source_remove(GLib.MAXUINT32), False) def test_recurse_property(self): s = GLib.Idle() self.assertTrue(s.can_recurse in [False, True]) s.can_recurse = False self.assertFalse(s.can_recurse) def test_priority(self): s = GLib.Idle() self.assertEqual(s.priority, GLib.PRIORITY_DEFAULT_IDLE) s.priority = GLib.PRIORITY_HIGH self.assertEqual(s.priority, GLib.PRIORITY_HIGH) s = GLib.Idle(GLib.PRIORITY_LOW) self.assertEqual(s.priority, GLib.PRIORITY_LOW) s = GLib.Timeout(1, GLib.PRIORITY_LOW) self.assertEqual(s.priority, GLib.PRIORITY_LOW) s = GLib.Source() self.assertEqual(s.priority, GLib.PRIORITY_DEFAULT) def test_get_current_time(self): # Note, deprecated API s = GLib.Idle() with warnings.catch_warnings(record=True) as w: warnings.simplefilter('always') time = s.get_current_time() self.assertTrue(issubclass(w[0].category, PyGIDeprecationWarning)) self.assertTrue(isinstance(time, float)) # plausibility check, and check magnitude of result self.assertGreater(time, 1300000000.0) self.assertLess(time, 2000000000.0) def test_add_remove_poll(self): # FIXME: very shallow test, only verifies the API signature pollfd = GLib.PollFD(99, GLib.IOCondition.IN | GLib.IOCondition.HUP) self.assertEqual(pollfd.fd, 99) source = GLib.Source() source.add_poll(pollfd) source.remove_poll(pollfd) def test_out_of_scope_before_dispatch(self): # https://bugzilla.gnome.org/show_bug.cgi?id=504337 GLib.Timeout(20) GLib.Idle() @unittest.skipIf(sys.platform == "darwin", "hangs") def test_finalize(self): self.dispatched = False self.finalized = False class S(GLib.Source): def prepare(s): return (True, 1) def dispatch(s, callback, args): self.dispatched = True return False def finalize(s): self.finalized = True source = S() source.attach() self.assertFalse(self.finalized) self.assertFalse(source.is_destroyed()) while source.get_context().iteration(False): pass source.destroy() self.assertTrue(self.dispatched) self.assertFalse(self.finalized) self.assertTrue(source.is_destroyed()) del source gc.collect() gc.collect() self.assertTrue(self.finalized) def test_python_unref_with_active_source(self): # Tests a Python derived Source which is free'd in the context of # Python, but which was attached to a MainContext (via source.attach()) self.dispatched = False self.finalized = False class S(GLib.Source): def prepare(s): return (True, 1) def check(s): pass def dispatch(s, callback, args): self.dispatched = True return False def finalize(s): self.finalized = True context = GLib.MainContext.new() source = S() id_ = source.attach(context) self.assertFalse(self.finalized) self.assertFalse(source.is_destroyed()) # Delete the source from Python, it should detach del source gc.collect() gc.collect() while context.iteration(may_block=False): pass assert self.finalized assert not self.dispatched assert context.find_source_by_id(id_) is None @unittest.skipIf(sys.implementation.name == "pypy", "PyPy doesn't __del__ immediately") def test_python_unref_during_dispatch(self): # Tests a Python derived Source which is free'd in the context of # Python, while being dispatched # NOTE: Finalize is explicitly called by __del__ for consistency self.dispatched = False self.finalized = False class S(GLib.Source): def __init__(s, func=None): s.func = func def prepare(s): return (True, 1) def check(s): pass def dispatch(s, callback, args): self.dispatched = True self.source = None return False def finalize(s): self.finalized = True context = GLib.MainContext.new() self.source = S() id_ = self.source.attach(context) while context.iteration(may_block=False): pass assert self.source is None assert context.find_source_by_id(id_) is None assert self.finalized assert self.dispatched def test_extra_init_args(self): class SourceWithInitArgs(GLib.Source): def __init__(self, arg, kwarg=None): super(SourceWithInitArgs, self).__init__() self.arg = arg self.kwarg = kwarg source = SourceWithInitArgs(1, kwarg=2) self.assertEqual(source.arg, 1) self.assertEqual(source.kwarg, 2) @unittest.skipIf(sys.platform == "darwin", "hangs") class TestUserData(unittest.TestCase): def test_idle_no_data(self): ml = GLib.MainLoop() def cb(): ml.quit() id = GLib.idle_add(cb) self.assertEqual(ml.get_context().find_source_by_id(id).priority, GLib.PRIORITY_DEFAULT_IDLE) ml.run() def test_timeout_no_data(self): ml = GLib.MainLoop() def cb(): ml.quit() id = GLib.timeout_add(1, cb) self.assertEqual(ml.get_context().find_source_by_id(id).priority, GLib.PRIORITY_DEFAULT) ml.run() def test_idle_data(self): ml = GLib.MainLoop() def cb(data): data['called'] = True ml.quit() data = {} id = GLib.idle_add(cb, data) self.assertEqual(ml.get_context().find_source_by_id(id).priority, GLib.PRIORITY_DEFAULT_IDLE) ml.run() self.assertTrue(data['called']) def test_idle_multidata(self): ml = GLib.MainLoop() def cb(data, data2): data['called'] = True data['data2'] = data2 ml.quit() data = {} id = GLib.idle_add(cb, data, 'hello') self.assertEqual(ml.get_context().find_source_by_id(id).priority, GLib.PRIORITY_DEFAULT_IDLE) ml.run() self.assertTrue(data['called']) self.assertEqual(data['data2'], 'hello') def test_timeout_data(self): ml = GLib.MainLoop() def cb(data): data['called'] = True ml.quit() data = {} id = GLib.timeout_add(1, cb, data) self.assertEqual(ml.get_context().find_source_by_id(id).priority, GLib.PRIORITY_DEFAULT) ml.run() self.assertTrue(data['called']) def test_timeout_multidata(self): ml = GLib.MainLoop() def cb(data, data2): data['called'] = True data['data2'] = data2 ml.quit() data = {} id = GLib.timeout_add(1, cb, data, 'hello') self.assertEqual(ml.get_context().find_source_by_id(id).priority, GLib.PRIORITY_DEFAULT) ml.run() self.assertTrue(data['called']) self.assertEqual(data['data2'], 'hello') def test_idle_no_data_priority(self): ml = GLib.MainLoop() def cb(): ml.quit() id = GLib.idle_add(cb, priority=GLib.PRIORITY_HIGH) self.assertEqual(ml.get_context().find_source_by_id(id).priority, GLib.PRIORITY_HIGH) ml.run() def test_timeout_no_data_priority(self): ml = GLib.MainLoop() def cb(): ml.quit() id = GLib.timeout_add(1, cb, priority=GLib.PRIORITY_HIGH) self.assertEqual(ml.get_context().find_source_by_id(id).priority, GLib.PRIORITY_HIGH) ml.run() def test_idle_data_priority(self): ml = GLib.MainLoop() def cb(data): data['called'] = True ml.quit() data = {} id = GLib.idle_add(cb, data, priority=GLib.PRIORITY_HIGH) self.assertEqual(ml.get_context().find_source_by_id(id).priority, GLib.PRIORITY_HIGH) ml.run() self.assertTrue(data['called']) def test_timeout_data_priority(self): ml = GLib.MainLoop() def cb(data): data['called'] = True ml.quit() data = {} id = GLib.timeout_add(1, cb, data, priority=GLib.PRIORITY_HIGH) self.assertEqual(ml.get_context().find_source_by_id(id).priority, GLib.PRIORITY_HIGH) ml.run() self.assertTrue(data['called']) def cb_no_data(self): self.loop.quit() def test_idle_method_callback_no_data(self): self.loop = GLib.MainLoop() GLib.idle_add(self.cb_no_data) self.loop.run() def cb_with_data(self, data): data['called'] = True self.loop.quit() def test_idle_method_callback_with_data(self): self.loop = GLib.MainLoop() data = {} GLib.idle_add(self.cb_with_data, data) self.loop.run() self.assertTrue(data['called']) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/tests/test_subprocess.py0000664000000000000000000001472015074674453017315 0ustar00rootroot# -*- Mode: Python -*- import sys import os import unittest import warnings import pytest from gi.repository import GLib from gi import PyGIDeprecationWarning from .helper import capture_gi_deprecation_warnings def test_child_watch_add_get_args_various(): cb = lambda pid, status: None get_args = GLib._child_watch_add_get_args pid = 42 with capture_gi_deprecation_warnings(): assert get_args(pid, cb, 2) == (0, pid, cb, (2,)) with pytest.raises(TypeError): get_args(pid, cb, 2, 3, 4) assert get_args(0, pid, 2, 3, function=cb) == (0, pid, cb, (2, 3)) assert get_args(0, pid, cb, 2, 3) == (0, pid, cb, (2, 3)) assert get_args(0, pid, cb, data=99) == (0, pid, cb, (99,)) with pytest.raises(TypeError): get_args(0, pid, 24) with pytest.raises(TypeError): get_args(0, pid, cb, 2, 3, data=99) @unittest.skipIf(os.name == "nt", "not on Windows") class TestProcess(unittest.TestCase): def test_deprecated_child_watch_no_data(self): cb = lambda pid, status: None pid = object() with warnings.catch_warnings(record=True) as w: warnings.simplefilter('always') res = GLib._child_watch_add_get_args(pid, cb) self.assertTrue(issubclass(w[0].category, PyGIDeprecationWarning)) self.assertEqual(len(res), 4) self.assertEqual(res[0], GLib.PRIORITY_DEFAULT) self.assertEqual(res[1], pid) self.assertTrue(callable(cb)) self.assertSequenceEqual(res[3], []) def test_deprecated_child_watch_data_priority(self): cb = lambda pid, status: None pid = object() with warnings.catch_warnings(record=True) as w: warnings.simplefilter('always') res = GLib._child_watch_add_get_args(pid, cb, 12345, GLib.PRIORITY_HIGH) self.assertTrue(issubclass(w[0].category, PyGIDeprecationWarning)) self.assertEqual(len(res), 4) self.assertEqual(res[0], GLib.PRIORITY_HIGH) self.assertEqual(res[1], pid) self.assertEqual(res[2], cb) self.assertSequenceEqual(res[3], [12345]) def test_deprecated_child_watch_data_priority_kwargs(self): cb = lambda pid, status: None pid = object() with warnings.catch_warnings(record=True) as w: warnings.simplefilter('always') res = GLib._child_watch_add_get_args(pid, cb, priority=GLib.PRIORITY_HIGH, data=12345) self.assertTrue(issubclass(w[0].category, PyGIDeprecationWarning)) self.assertEqual(len(res), 4) self.assertEqual(res[0], GLib.PRIORITY_HIGH) self.assertEqual(res[1], pid) self.assertEqual(res[2], cb) self.assertSequenceEqual(res[3], [12345]) @unittest.expectedFailure # using keyword args is fully supported by PyGObject machinery def test_child_watch_all_kwargs(self): cb = lambda pid, status: None pid = object() res = GLib._child_watch_add_get_args(priority=GLib.PRIORITY_HIGH, pid=pid, function=cb, data=12345) self.assertEqual(len(res), 4) self.assertEqual(res[0], GLib.PRIORITY_HIGH) self.assertEqual(res[1], pid) self.assertEqual(res[2], cb) self.assertSequenceEqual(res[3], [12345]) def test_child_watch_no_data(self): def cb(pid, status): self.status = status self.loop.quit() self.status = None self.loop = GLib.MainLoop() argv = [sys.executable, '-c', 'import sys'] pid, stdin, stdout, stderr = GLib.spawn_async( argv, flags=GLib.SpawnFlags.DO_NOT_REAP_CHILD) pid.close() id = GLib.child_watch_add(GLib.PRIORITY_HIGH, pid, cb) self.assertEqual(self.loop.get_context().find_source_by_id(id).priority, GLib.PRIORITY_HIGH) self.loop.run() self.assertEqual(self.status, 0) def test_child_watch_with_data(self): def cb(pid, status, data): self.status = status self.data = data self.loop.quit() self.data = None self.status = None self.loop = GLib.MainLoop() argv = [sys.executable, '-c', 'import sys'] pid, stdin, stdout, stderr = GLib.spawn_async( argv, flags=GLib.SpawnFlags.DO_NOT_REAP_CHILD) self.assertEqual(stdin, None) self.assertEqual(stdout, None) self.assertEqual(stderr, None) self.assertNotEqual(pid, 0) pid.close() id = GLib.child_watch_add(GLib.PRIORITY_HIGH, pid, cb, 12345) self.assertEqual(self.loop.get_context().find_source_by_id(id).priority, GLib.PRIORITY_HIGH) self.loop.run() self.assertEqual(self.data, 12345) self.assertEqual(self.status, 0) def test_spawn_async_fds(self): pid, stdin, stdout, stderr = GLib.spawn_async( ['cat'], flags=GLib.SpawnFlags.SEARCH_PATH, standard_input=True, standard_output=True, standard_error=True) os.write(stdin, b'hello world!\n') os.close(stdin) out = os.read(stdout, 50) os.close(stdout) err = os.read(stderr, 50) os.close(stderr) pid.close() self.assertEqual(out, b'hello world!\n') self.assertEqual(err, b'') def test_spawn_async_with_pipes(self): res, pid, stdin, stdout, stderr = GLib.spawn_async_with_pipes( working_directory=None, argv=['cat'], envp=None, flags=GLib.SpawnFlags.SEARCH_PATH) os.write(stdin, b'hello world!\n') os.close(stdin) out = os.read(stdout, 50) os.close(stdout) err = os.read(stderr, 50) os.close(stderr) GLib.spawn_close_pid(pid) self.assertEqual(out, b'hello world!\n') self.assertEqual(err, b'') def test_spawn_async_envp(self): pid, stdin, stdout, stderr = GLib.spawn_async( ['sh', '-c', 'echo $TEST_VAR'], ['TEST_VAR=moo!'], flags=GLib.SpawnFlags.SEARCH_PATH, standard_output=True) self.assertEqual(stdin, None) self.assertEqual(stderr, None) out = os.read(stdout, 50) os.close(stdout) pid.close() self.assertEqual(out, b'moo!\n') def test_backwards_compat_flags(self): with warnings.catch_warnings(): warnings.simplefilter('ignore', PyGIDeprecationWarning) self.assertEqual(GLib.SpawnFlags.DO_NOT_REAP_CHILD, GLib.SPAWN_DO_NOT_REAP_CHILD) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/tests/test_thread.py0000664000000000000000000000147415074674453016376 0ustar00rootroot# -*- Mode: Python -*- import unittest from gi.repository import GLib import testhelper class TestThread(unittest.TestCase): def setUp(self): self.main = GLib.MainLoop() self.called = False def from_thread_cb(self, test, enum): assert test == self.obj assert int(enum) == 0 assert type(enum) is not int self.called = True GLib.idle_add(self.timeout_cb) def idle_cb(self): self.obj = testhelper.get_test_thread() self.obj.connect('from-thread', self.from_thread_cb) self.obj.emit('emit-signal') def test_extension_module(self): GLib.idle_add(self.idle_cb) GLib.timeout_add(2000, self.timeout_cb) self.main.run() self.assertTrue(self.called) def timeout_cb(self): self.main.quit() ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/tests/test_typeclass.py0000664000000000000000000000603115074674453017130 0ustar00rootroot# -*- Mode: Python; py-indent-offset: 4 -*- # vim: tabstop=4 shiftwidth=4 expandtab # # test_typeclass.py: Tests for GTypeClass related methods and marshalling. # # Copyright (C) 2014 Simon Feltman # # 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 unittest from gi.repository import GObject from gi.repository import GIMarshallingTests class TestCoercion(unittest.TestCase): def test_coerce_from_class(self): prop = GObject.ObjectClass.find_property(GIMarshallingTests.PropertiesObject, 'some-int') self.assertIsInstance(prop, GObject.ParamSpec) self.assertEqual(prop.name, 'some-int') self.assertEqual(prop.value_type, GObject.TYPE_INT) self.assertEqual(prop.owner_type, GIMarshallingTests.PropertiesObject.__gtype__) def test_coerce_from_gtype(self): gtype = GIMarshallingTests.PropertiesObject.__gtype__ prop = GObject.ObjectClass.find_property(gtype, 'some-int') self.assertIsInstance(prop, GObject.ParamSpec) self.assertEqual(prop.name, 'some-int') self.assertEqual(prop.value_type, GObject.TYPE_INT) self.assertEqual(prop.owner_type, gtype) def test_coerce_from_instance(self): obj = GIMarshallingTests.PropertiesObject() prop = GObject.ObjectClass.find_property(obj, 'some-int') self.assertIsInstance(prop, GObject.ParamSpec) self.assertEqual(prop.name, 'some-int') self.assertEqual(prop.value_type, GObject.TYPE_INT) self.assertEqual(prop.owner_type, obj.__gtype__) def test_marshalling_error(self): with self.assertRaises(TypeError): GObject.ObjectClass.find_property(object, 'some-int') with self.assertRaises(TypeError): GObject.ObjectClass.find_property(42, 'some-int') class TestTypeClassMethodsMovedToClass(unittest.TestCase): def test_list_child_properties(self): pspecs = GIMarshallingTests.PropertiesObject.list_properties() pnames = [pspec.name for pspec in pspecs] self.assertTrue('some-int' in pnames) self.assertTrue('some-float' in pnames) self.assertTrue('some-char' in pnames) def test_find_child_property(self): pspec = GIMarshallingTests.PropertiesObject.find_property('some-int') self.assertEqual(pspec.name, 'some-int') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/tests/test_unknown.py0000664000000000000000000000157515074674453016630 0ustar00rootroot# -*- Mode: Python -*- import unittest from gi.repository import GObject import testhelper TestInterface = GObject.GType.from_name('TestInterface') class TestUnknown(unittest.TestCase): def test_unknown_interface(self): obj = testhelper.get_unknown() TestUnknownGType = GObject.GType.from_name('TestUnknown') TestUnknown = GObject.new(TestUnknownGType).__class__ assert isinstance(obj, testhelper.Interface) assert isinstance(obj, TestUnknown) def test_property(self): obj = testhelper.get_unknown() self.assertEqual(obj.get_property('some-property'), None) obj.set_property('some-property', 'foo') def test_unknown_property(self): obj = testhelper.get_unknown() self.assertRaises(TypeError, obj.get_property, 'unknown') self.assertRaises(TypeError, obj.set_property, 'unknown', '1') ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/tests/testhelpermodule.c0000664000000000000000000005377715074674453017264 0ustar00rootroot#include "pygobject.h" #include #include "test-thread.h" #include "test-unknown.h" #include "test-floating.h" #define PYGI_DEFINE_TYPE(typename, symbol, csymbol) \ PyTypeObject symbol = { \ PyVarObject_HEAD_INIT(NULL, 0) \ typename, \ sizeof(csymbol) \ }; static PyObject * _wrap_TestInterface__do_iface_method(PyObject *cls, PyObject *args, PyObject *kwargs); static GType test_type_get_type(void) { static GType gtype = 0; GType parent_type; if (gtype == 0) { GTypeInfo *type_info; GTypeQuery query; parent_type = g_type_from_name("PyGObject"); if (parent_type == 0) g_error("could not get PyGObject from testmodule"); type_info = (GTypeInfo *)g_new0(GTypeInfo, 1); g_type_query(parent_type, &query); type_info->class_size = (guint16)query.class_size; type_info->instance_size = (guint16)query.instance_size; gtype = g_type_register_static(parent_type, "TestType", type_info, 0); if (!gtype) g_error("Could not register TestType"); } return gtype; } #define TYPE_TEST (test_type_get_type()) static PyObject * _wrap_get_test_thread (PyObject * self) { GObject *obj; test_thread_get_type(); g_assert (g_type_is_a (TEST_TYPE_THREAD, G_TYPE_OBJECT)); obj = g_object_new (TEST_TYPE_THREAD, NULL); g_assert (obj != NULL); return pygobject_new(obj); } static PyObject * _wrap_get_unknown (PyObject * self) { GObject *obj; obj = g_object_new (TEST_TYPE_UNKNOWN, NULL); return pygobject_new(obj); } static PyObject * _wrap_create_test_type (PyObject * self) { GObject *obj; PyObject *rv; obj = g_object_new(TYPE_TEST, NULL); rv = pygobject_new(obj); g_object_unref(obj); return rv; } static PyObject * _wrap_test_g_object_new (PyObject * self) { GObject *obj; PyObject *rv; obj = g_object_new(g_type_from_name("PyGObject"), NULL); rv = PyLong_FromLong(obj->ref_count); /* should be == 2 at this point */ g_object_unref(obj); return rv; } /* TestUnknown */ static PyObject * _wrap_test_interface_iface_method(PyGObject *self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { NULL }; if (!PyArg_ParseTupleAndKeywords(args, kwargs,":", kwlist)) return NULL; test_interface_iface_method(TEST_INTERFACE(self->obj)); Py_INCREF(Py_None); return Py_None; } static const PyMethodDef _PyTestInterface_methods[] = { { "iface_method", (PyCFunction)_wrap_test_interface_iface_method, METH_VARARGS|METH_KEYWORDS, NULL }, { "do_iface_method", (PyCFunction)_wrap_TestInterface__do_iface_method, METH_VARARGS|METH_KEYWORDS|METH_CLASS, NULL }, { NULL, NULL, 0, NULL } }; /* TestInterface */ PYGI_DEFINE_TYPE("test.Interface", PyTestInterface_Type, PyObject); static PyObject * _wrap_TestInterface__do_iface_method(PyObject *cls, PyObject *args, PyObject *kwargs) { TestInterfaceIface *iface; static char *kwlist[] = { "self", NULL }; PyGObject *self; if (!PyArg_ParseTupleAndKeywords(args, kwargs,"O!:TestInterface.iface_method", kwlist, &PyTestInterface_Type, &self)) return NULL; iface = g_type_interface_peek(g_type_class_peek(pyg_type_from_object(cls)), TEST_TYPE_INTERFACE); if (iface->iface_method) iface->iface_method(TEST_INTERFACE(self->obj)); else { PyErr_SetString(PyExc_NotImplementedError, "interface method TestInterface.iface_method not implemented"); return NULL; } Py_INCREF(Py_None); return Py_None; } PYGI_DEFINE_TYPE("testhelper.Unknown", PyTestUnknown_Type, PyGObject); static void _wrap_TestInterface__proxy_do_iface_method(TestInterface *self) { PyGILState_STATE __py_state; PyObject *py_self; PyObject *py_retval; PyObject *py_args; PyObject *py_method; __py_state = PyGILState_Ensure(); py_self = pygobject_new((GObject *) self); if (!py_self) { if (PyErr_Occurred()) PyErr_Print(); PyGILState_Release(__py_state); return; } py_args = PyTuple_New(0); py_method = PyObject_GetAttrString(py_self, "do_iface_method"); if (!py_method) { if (PyErr_Occurred()) PyErr_Print(); Py_DECREF(py_args); Py_DECREF(py_self); PyGILState_Release(__py_state); return; } py_retval = PyObject_CallObject(py_method, py_args); if (!py_retval) { if (PyErr_Occurred()) PyErr_Print(); Py_DECREF(py_method); Py_DECREF(py_args); Py_DECREF(py_self); PyGILState_Release(__py_state); return; } if (py_retval != Py_None) { if (PyErr_Occurred()) PyErr_Print(); PyErr_SetString(PyExc_TypeError, "retval should be None"); Py_DECREF(py_retval); Py_DECREF(py_method); Py_DECREF(py_args); Py_DECREF(py_self); PyGILState_Release(__py_state); return; } Py_DECREF(py_retval); Py_DECREF(py_method); Py_DECREF(py_args); Py_DECREF(py_self); PyGILState_Release(__py_state); } static void __TestInterface__interface_init(TestInterfaceIface *iface, PyTypeObject *pytype) { TestInterfaceIface *parent_iface = g_type_interface_peek_parent(iface); PyObject *py_method; py_method = pytype ? PyObject_GetAttrString((PyObject *) pytype, "do_iface_method") : NULL; if (py_method && !PyObject_TypeCheck(py_method, &PyCFunction_Type)) { iface->iface_method = _wrap_TestInterface__proxy_do_iface_method; } else { PyErr_Clear(); if (parent_iface) { iface->iface_method = parent_iface->iface_method; } Py_XDECREF(py_method); } } static const GInterfaceInfo __TestInterface__iinfo = { (GInterfaceInitFunc) __TestInterface__interface_init, NULL, NULL }; /* TestFloating */ PYGI_DEFINE_TYPE("testhelper.Floating", PyTestFloating_Type, PyGObject); /* TestOwnedByLibrary */ PYGI_DEFINE_TYPE("testhelper.OwnedByLibrary", PyTestOwnedByLibrary_Type, PyGObject); static PyObject * _wrap_test_owned_by_library_release (PyGObject *self) { test_owned_by_library_release (TEST_OWNED_BY_LIBRARY (self->obj)); return Py_None; } static const PyMethodDef _PyTestOwnedByLibrary_methods[] = { { "release", (PyCFunction)_wrap_test_owned_by_library_release, METH_NOARGS, NULL }, { NULL, NULL, 0, NULL } }; /* TestFloatingAndSunk */ PYGI_DEFINE_TYPE("testhelper.FloatingAndSunk", PyTestFloatingAndSunk_Type, PyGObject); static PyObject * _wrap_test_floating_and_sunk_release (PyGObject *self) { test_floating_and_sunk_release (TEST_FLOATING_AND_SUNK (self->obj)); return Py_None; } static const PyMethodDef _PyTestFloatingAndSunk_methods[] = { { "release", (PyCFunction)_wrap_test_floating_and_sunk_release, METH_NOARGS, NULL }, { NULL, NULL, 0, NULL } }; #include #include static void test1_callback (GObject *object, char *data) { g_return_if_fail (G_IS_OBJECT (object)); g_return_if_fail (!strcmp (data, "user-data")); } static void test1_callback_swapped (char *data, GObject *object) { g_return_if_fail (G_IS_OBJECT (object)); g_return_if_fail (!strcmp (data, "user-data")); } static void test2_callback (GObject *object, char *string) { g_return_if_fail (G_IS_OBJECT (object)); g_return_if_fail (!strcmp (string, "string")); } static int test3_callback (GObject *object, double d) { g_return_val_if_fail (G_IS_OBJECT (object), -1); g_return_val_if_fail (d == 42.0, -1); return 20; } static void test4_callback (GObject *object, gboolean b, long l, float f, double d, guint uint, gulong ulong, gpointer user_data) { g_return_if_fail (b == TRUE); g_return_if_fail (l == 10L); g_return_if_fail (f <= 3.14001 && f >= 3.13999); g_return_if_fail (d <= 1.78001 && d >= 1.77999); g_return_if_fail (uint == 20); g_return_if_fail (ulong == 30L); } static float test_float_callback (GObject *object, float f) { g_return_val_if_fail (G_IS_OBJECT (object), -1); g_return_val_if_fail (f <= 1.234001 && f >= 1.123999, -1); return f; } static double test_double_callback (GObject *object, double d) { g_return_val_if_fail (G_IS_OBJECT (object), -1); g_return_val_if_fail (d <= 1.234001 && d >= 1.123999, -1); return d; } static gint64 test_int64_callback (GObject *object, gint64 i) { g_return_val_if_fail (G_IS_OBJECT (object), -1); if (i == G_MAXINT64) return i-1; return i; } static char * test_string_callback (GObject *object, char *s) { g_return_val_if_fail (G_IS_OBJECT (object), NULL); g_return_val_if_fail (!strcmp(s, "str"), NULL); return g_strdup (s); } static GObject * test_object_callback (GObject *object, GObject *o) { g_return_val_if_fail (G_IS_OBJECT (object), NULL); return o; } static GParamSpec * test_paramspec_callback (GObject *object) { g_return_val_if_fail (G_IS_OBJECT (object), NULL); return g_param_spec_boolean ("test-param", "test", "test boolean", TRUE, G_PARAM_READABLE); } static GValue * test_gvalue_callback (GObject *object, const GValue *v) { GValue *ret; g_return_val_if_fail (G_IS_OBJECT (object), NULL); g_return_val_if_fail (G_IS_VALUE (v), NULL); ret = g_malloc0 (sizeof (GValue)); g_value_init (ret, G_VALUE_TYPE (v)); g_value_copy (v, ret); return ret; } static GValue * test_gvalue_ret_callback (GObject *object, GType type) { GValue *ret; g_return_val_if_fail (G_IS_OBJECT (object), NULL); ret = g_malloc0 (sizeof (GValue)); g_value_init (ret, type); switch (type) { case G_TYPE_INT: g_value_set_int(ret, G_MAXINT); break; case G_TYPE_INT64: g_value_set_int64(ret, G_MAXINT64); break; case G_TYPE_UINT: g_value_set_uint(ret, G_MAXUINT); break; case G_TYPE_UINT64: g_value_set_uint64(ret, G_MAXUINT64); break; case G_TYPE_STRING: g_value_set_string(ret, "hello"); break; default: g_critical ("test_gvalue_ret_callback() does not support type %s", g_type_name (type)); } return ret; } static GParamSpec * test_paramspec_in_callback (GObject *object, GParamSpec *p) { g_return_val_if_fail (G_IS_OBJECT (object), NULL); g_return_val_if_fail (G_IS_PARAM_SPEC (p), NULL); return p; } static void connectcallbacks (GObject *object) { gchar *data = "user-data"; g_signal_connect (G_OBJECT (object), "test1", G_CALLBACK (test1_callback), data); g_signal_connect_swapped (G_OBJECT (object), "test1", G_CALLBACK (test1_callback_swapped), data); g_signal_connect (G_OBJECT (object), "test2", G_CALLBACK (test2_callback), NULL); g_signal_connect (G_OBJECT (object), "test3", G_CALLBACK (test3_callback), NULL); g_signal_connect (G_OBJECT (object), "test4", G_CALLBACK (test4_callback), NULL); g_signal_connect (G_OBJECT (object), "test_float", G_CALLBACK (test_float_callback), NULL); g_signal_connect (G_OBJECT (object), "test_double", G_CALLBACK (test_double_callback), NULL); g_signal_connect (G_OBJECT (object), "test_int64", G_CALLBACK (test_int64_callback), NULL); g_signal_connect (G_OBJECT (object), "test_string", G_CALLBACK (test_string_callback), NULL); g_signal_connect (G_OBJECT (object), "test_object", G_CALLBACK (test_object_callback), NULL); g_signal_connect (G_OBJECT (object), "test_paramspec", G_CALLBACK (test_paramspec_callback), NULL); g_signal_connect (G_OBJECT (object), "test_gvalue", G_CALLBACK (test_gvalue_callback), NULL); g_signal_connect (G_OBJECT (object), "test_gvalue_ret", G_CALLBACK (test_gvalue_ret_callback), NULL); g_signal_connect (G_OBJECT (object), "test_paramspec_in", G_CALLBACK (test_paramspec_in_callback), NULL); } static PyObject * _wrap_connectcallbacks(PyObject * self, PyObject *args) { PyGObject *obj; if (!PyArg_ParseTuple(args, "O", &obj)) return NULL; connectcallbacks (G_OBJECT (obj->obj)); Py_INCREF(Py_None); return Py_None; } static PyObject * _wrap_test_value(PyObject *self, PyObject *args) { GValue tvalue = {0,}, *value = &tvalue; PyObject *obj; if (!PyArg_ParseTuple(args, "O", &obj)) return NULL; g_value_init(value, G_TYPE_VALUE); if (pyg_value_from_pyobject(value, obj)) { PyErr_SetString(PyExc_TypeError, "Could not convert to GValue"); return NULL; } return pyg_value_as_pyobject(value, FALSE); } static PyObject * _wrap_test_state_ensure_release(PyObject *self, PyObject *args) { int state = pyg_gil_state_ensure (); pyg_gil_state_release (state); Py_RETURN_NONE; } #define PYGI_TYPE_VALUE_ARRAY (g_value_array_get_type()) static PyObject * _wrap_test_value_array(PyObject *self, PyObject *args) { GValue tvalue = {0,}, *value = &tvalue; PyObject *obj; if (!PyArg_ParseTuple(args, "O", &obj)) return NULL; G_GNUC_BEGIN_IGNORE_DEPRECATIONS g_value_init(value, PYGI_TYPE_VALUE_ARRAY); G_GNUC_END_IGNORE_DEPRECATIONS if (pyg_value_from_pyobject(value, obj)) { PyErr_SetString(PyExc_TypeError, "Could not convert to GValueArray"); return NULL; } return pyg_value_as_pyobject(value, FALSE); } static PyObject * _wrap_value_array_get_nth_type(PyObject *self, PyObject *args) { guint n; GType type; GValue *nth; GValueArray *arr; PyObject *obj; if (!PyArg_ParseTuple(args, "OI", &obj, &n)) return NULL; G_GNUC_BEGIN_IGNORE_DEPRECATIONS if (pyg_boxed_check(obj, G_TYPE_VALUE) && G_VALUE_HOLDS(pyg_boxed_get(obj, GValue), PYGI_TYPE_VALUE_ARRAY)) { arr = g_value_get_boxed(pyg_boxed_get(obj, GValue)); } else if (pyg_boxed_check(obj, PYGI_TYPE_VALUE_ARRAY)) { arr = pyg_boxed_get(obj, GValueArray); } else { PyErr_SetString(PyExc_TypeError, "First argument is not GValueArray"); return NULL; } if (n >= arr->n_values) { PyErr_SetString(PyExc_TypeError, "Index is out of bounds"); return NULL; } nth = g_value_array_get_nth(arr, n); type = G_VALUE_TYPE(nth); G_GNUC_END_IGNORE_DEPRECATIONS return pyg_type_wrapper_new(type); } static PyObject * _wrap_constant_strip_prefix(PyObject *self, PyObject *args) { const char *name, *strip_prefix; const gchar *result; if (!PyArg_ParseTuple (args, "ss", &name, &strip_prefix)) return NULL; result = pyg_constant_strip_prefix (name, strip_prefix); return PyUnicode_FromString (result); } static PyObject * _wrap_test_gerror_exception(PyObject *self, PyObject *args) { PyObject *py_method; PyObject *py_args; PyObject *py_ret; GError *err = NULL; if (!PyArg_ParseTuple(args, "O", &py_method)) return NULL; py_args = PyTuple_New(0); py_ret = PyObject_CallObject(py_method, py_args); if (pyg_gerror_exception_check(&err)) { pyg_error_check(&err); return NULL; } Py_DECREF(py_args); Py_DECREF(py_ret); Py_INCREF(Py_None); return Py_None; } static PyObject * _wrap_test_owned_by_library_get_instance_list (PyObject *self) { PyObject *py_list, *py_obj; GSList *list, *tmp; list = test_owned_by_library_get_instance_list (); if ((py_list = PyList_New (0)) == NULL) { return NULL; } for (tmp = list; tmp != NULL; tmp = tmp->next) { py_obj = pygobject_new (G_OBJECT (tmp->data)); if (py_obj == NULL) { Py_DECREF (py_list); return NULL; } PyList_Append (py_list, py_obj); Py_DECREF (py_obj); } return py_list; } static PyObject * _wrap_test_floating_and_sunk_get_instance_list (PyObject *self) { PyObject *py_list, *py_obj; GSList *list, *tmp; list = test_floating_and_sunk_get_instance_list (); if ((py_list = PyList_New (0)) == NULL) { return NULL; } for (tmp = list; tmp != NULL; tmp = tmp->next) { py_obj = pygobject_new (G_OBJECT (tmp->data)); if (py_obj == NULL) { Py_DECREF (py_list); return NULL; } PyList_Append (py_list, py_obj); Py_DECREF (py_obj); } return py_list; } G_GNUC_BEGIN_IGNORE_DEPRECATIONS static PyObject * _wrap_test_parse_constructor_args (PyObject *self, PyObject *args) { char *arg_names[] = {"label", NULL}; char *prop_names[] = {"label", NULL}; GParameter params[1] = {{0}}; PyObject *parsed_args[1]; guint nparams = 0; if (!PyArg_ParseTuple(args, "O", &(parsed_args[0]))) return NULL; if (!pyg_parse_constructor_args ( TYPE_TEST, arg_names, prop_names, params, &nparams, parsed_args)) { return NULL; } return PyLong_FromLong (nparams); } G_GNUC_END_IGNORE_DEPRECATIONS static PyObject * _wrap_test_to_unichar_conv (PyObject * self, PyObject *args) { PyObject *obj; gunichar result; if (!PyArg_ParseTuple(args, "O", &obj)) return NULL; if (!pyg_pyobj_to_unichar_conv (obj, &result)) return NULL; return PyLong_FromLong (result); } static PyMethodDef testhelper_functions[] = { { "test_parse_constructor_args", (PyCFunction)_wrap_test_parse_constructor_args, METH_VARARGS }, { "get_test_thread", (PyCFunction)_wrap_get_test_thread, METH_NOARGS }, { "test_to_unichar_conv", (PyCFunction)_wrap_test_to_unichar_conv, METH_VARARGS }, { "get_unknown", (PyCFunction)_wrap_get_unknown, METH_NOARGS }, { "create_test_type", (PyCFunction)_wrap_create_test_type, METH_NOARGS }, { "test_state_ensure_release", (PyCFunction)_wrap_test_state_ensure_release, METH_NOARGS }, { "test_g_object_new", (PyCFunction)_wrap_test_g_object_new, METH_NOARGS }, { "connectcallbacks", (PyCFunction)_wrap_connectcallbacks, METH_VARARGS }, { "test_value", (PyCFunction)_wrap_test_value, METH_VARARGS }, { "test_value_array", (PyCFunction)_wrap_test_value_array, METH_VARARGS }, { "value_array_get_nth_type", (PyCFunction)_wrap_value_array_get_nth_type, METH_VARARGS }, { "constant_strip_prefix", (PyCFunction)_wrap_constant_strip_prefix, METH_VARARGS }, { "test_gerror_exception", (PyCFunction)_wrap_test_gerror_exception, METH_VARARGS }, { "owned_by_library_get_instance_list", (PyCFunction)_wrap_test_owned_by_library_get_instance_list, METH_NOARGS }, { "floating_and_sunk_get_instance_list", (PyCFunction)_wrap_test_floating_and_sunk_get_instance_list, METH_NOARGS }, { NULL, NULL } }; static struct PyModuleDef _testhelpermodule = { PyModuleDef_HEAD_INIT, "testhelper", NULL, -1, testhelper_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_testhelper(void); PYGI_MODINIT_FUNC PyInit_testhelper(void) { PyObject *module; PyObject *gobject_module; PyObject *m, *d; module = PyModule_Create(&_testhelpermodule); if ((gobject_module = pygobject_init(-1, -1, -1)) == NULL) return NULL; Py_DECREF (gobject_module); d = PyModule_GetDict(module); if ((m = PyImport_ImportModule("gi.repository.GObject")) == NULL) { PyErr_SetString(PyExc_ImportError, "could not import gobject"); return NULL; } /* TestInterface */ PyTestInterface_Type.tp_methods = (struct PyMethodDef*)_PyTestInterface_methods; PyTestInterface_Type.tp_flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE); pyg_register_interface(d, "Interface", TEST_TYPE_INTERFACE, &PyTestInterface_Type); pyg_register_interface_info(TEST_TYPE_INTERFACE, &__TestInterface__iinfo); /* TestUnknown */ PyTestUnknown_Type.tp_flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE); PyTestUnknown_Type.tp_weaklistoffset = offsetof(PyGObject, weakreflist); PyTestUnknown_Type.tp_dictoffset = offsetof(PyGObject, inst_dict); pygobject_register_class(d, "Unknown", TEST_TYPE_UNKNOWN, &PyTestUnknown_Type, Py_BuildValue("(O)", &PyGObject_Type, &PyTestInterface_Type)); /* TestFloating */ PyTestFloating_Type.tp_flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE); PyTestFloating_Type.tp_weaklistoffset = offsetof(PyGObject, weakreflist); PyTestFloating_Type.tp_dictoffset = offsetof(PyGObject, inst_dict); pygobject_register_class(d, "Floating", TEST_TYPE_FLOATING, &PyTestFloating_Type, Py_BuildValue("(O)", &PyGObject_Type)); /* TestOwnedByLibrary */ PyTestOwnedByLibrary_Type.tp_flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE); PyTestOwnedByLibrary_Type.tp_methods = (struct PyMethodDef*)_PyTestOwnedByLibrary_methods; PyTestOwnedByLibrary_Type.tp_weaklistoffset = offsetof(PyGObject, weakreflist); PyTestOwnedByLibrary_Type.tp_dictoffset = offsetof(PyGObject, inst_dict); pygobject_register_class(d, "OwnedByLibrary", TEST_TYPE_OWNED_BY_LIBRARY, &PyTestOwnedByLibrary_Type, Py_BuildValue("(O)", &PyGObject_Type)); /* TestFloatingAndSunk */ PyTestFloatingAndSunk_Type.tp_flags = (Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE); PyTestFloatingAndSunk_Type.tp_methods = (struct PyMethodDef*)_PyTestFloatingAndSunk_methods; PyTestFloatingAndSunk_Type.tp_weaklistoffset = offsetof(PyGObject, weakreflist); PyTestFloatingAndSunk_Type.tp_dictoffset = offsetof(PyGObject, inst_dict); pygobject_register_class(d, "FloatingAndSunk", TEST_TYPE_FLOATING_AND_SUNK, &PyTestFloatingAndSunk_Type, Py_BuildValue("(O)", &PyGObject_Type)); return module; } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/tests/valgrind.supp0000664000000000000000000000076015074674453016232 0ustar00rootroot# https://bugzilla.redhat.com/show_bug.cgi?id=1538073 { Memcheck:Cond fun:__wcsnlen_sse4_1 fun:wcsrtombs fun:wcstombs fun:wcstombs fun:encode_current_locale* } { Memcheck:Leak match-leak-kinds: definite fun:malloc fun:FcPatternObjectInsertElt fun:FcPatternObjectAddWithBinding } { Memcheck:Leak match-leak-kinds: definite fun:malloc fun:FcPatternCreate fun:FcParsePattern fun:FcEndElement } ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1760786731.0 pygobject-3.50.2/tools/pygi-convert.sh0000775000000000000000000005161315074674453016501 0ustar00rootroot#!/bin/sh if [ -n "$1" ]; then FILES_TO_CONVERT="$@" else FILES_TO_CONVERT="$(find . -name '*.py')" fi for f in $FILES_TO_CONVERT; do perl -i -0 \ -pe "s/import gconf\n/from gi.repository import GConf\n/g;" \ -pe "s/gconf\./GConf\./g;" \ -pe "s/GConf\.client_get_default/GConf.Client.get_default/g;" \ -pe "s/GConf\.CLIENT_/GConf.ClientPreloadType./g;" \ -pe "s/GConf\.VALUE_/GConf.ValueType./g;" \ -pe "s/gconf_client.notify_add\('\/desktop\/sugar\/collaboration\/publish_gadget',/return;gconf_client.notify_add\('\/desktop\/sugar\/collaboration\/publish_gadget',/g;" \ \ -pe "s/import pygtk/import gi/g;" \ -pe "s/pygtk.require\('2.0'\)/gi.require_version\('Gtk', '3.0'\)/g;" \ -pe "s/pygtk.require\(\"2.0\"\)/gi.require_version\(\"Gtk\", \"3.0\"\)/g;" \ -pe "s/import gtk\n/from gi.repository import Gtk\n/g;" \ -pe "s/(? 0/self._content.get_children\(\)/g;" \ -pe "s/len\(self.menu.get_children\(\)\) > 0/self.menu.get_children\(\)/g;" \ -pe "s/import gobject\n/from gi.repository import GObject\n/g;" \ -pe "s/Gtk\..*\.__init__/gobject.GObject.__init__/g;" \ \ -pe "s/rsvg.Handle\s*\(data=([^,\)]+)\)/Rsvg.Handle.new_from_data(\1)/g;" \ \ -pe "s/from gtk import gdk\n/from gi.repository import Gdk\n/g;" \ -pe "s/import gtk.gdk as gdk\n/from gi.repository import Gdk\n/g;" \ -pe "s/Gtk.gdk.x11_/GdkX11.x11_/g;" \ -pe "s/Gtk.gdk\./Gdk\./g;" \ -pe "s/(? Maintainer-Email: Christoph Reiter , Arjan Molenaar , Dan Yeaw , Ignacio Casal Quinteiro License: GNU Lesser General Public License v2.1 (LGPLv2.1) Classifier: Development Status :: 5 - Production/Stable Classifier: Intended Audience :: Developers Classifier: License :: OSI Approved :: GNU Lesser General Public License v2 or later (LGPLv2+) Classifier: Operating System :: POSIX Classifier: Operating System :: Microsoft :: Windows Classifier: Programming Language :: C Classifier: Programming Language :: Python Classifier: Topic :: Software Development :: Libraries :: Python Modules Project-URL: Homepage, https://pygobject.gnome.org Project-URL: Repository, https://gitlab.gnome.org/GNOME/pygobject.git Project-URL: Changelog, https://gitlab.gnome.org/GNOME/pygobject/-/blob/main/NEWS Requires-Python: <4.0,>=3.9 Requires-Dist: pycairo>=1.16 Description-Content-Type: text/x-rst .. image:: https://gitlab.gnome.org/GNOME/pygobject/-/raw/master/docs/images/pygobject.svg?ref_type=heads :align: center :width: 400px :height: 98px | **PyGObject** is a Python package which provides bindings for `GObject `__ based libraries such as `GTK `__, `GStreamer `__, `WebKitGTK `__, `GLib `__, `GIO `__ and many more. It supports Linux, Windows, and macOS and works with **Python 3.9+** and **PyPy3**. PyGObject, including this documentation, is licensed under the **LGPLv2.1+**. Homepage -------- https://pygobject.gnome.org Installation ------------ The latest version from PyGObject can be installed from `PyPI `__: pip install PyGObject PyGObject is only distributed as source distribution, so you need a C compiler installed on your host. Please have a look at our `Getting Started `__ documentation for OS specific installation instructions. Development ~~~~~~~~~~~ Our website contains instructions on how to `set up a development environment `__. Default branch renamed to ``main`` ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ The default development branch of PyGObject has been renamed to ``main``. To update your local checkout, use:: git checkout master git branch -m master main git fetch git branch --unset-upstream git branch -u origin/main git symbolic-ref refs/remotes/origin/HEAD refs/remotes/origin/main